-diff -Nur linux-2.6.12.5/arch/mips/Kconfig linux-2.6.12.5-brcm/arch/mips/Kconfig
---- linux-2.6.12.5/arch/mips/Kconfig 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/arch/mips/Kconfig 2005-09-03 21:53:36.323284896 +0200
-@@ -40,6 +40,15 @@
- Members include the Acer PICA, MIPS Magnum 4000, MIPS Millenium and
- Olivetti M700-10 workstations.
-
-+config BCM947XX
-+ bool "Support for BCM947xx based boards"
-+ select DMA_NONCOHERENT
-+ select HW_HAS_PCI
-+ select IRQ_CPU
-+ select CPU_LITTLE_ENDIAN
-+ help
-+ Support for BCM947xx based boards
-+
- config ACER_PICA_61
- bool "Support for Acer PICA 1 chipset (EXPERIMENTAL)"
- depends on MACH_JAZZ && EXPERIMENTAL
-@@ -974,7 +983,7 @@
-
- config CPU_LITTLE_ENDIAN
- bool "Generate little endian code"
-- default y if ACER_PICA_61 || CASIO_E55 || DDB5074 || DDB5476 || DDB5477 || MACH_DECSTATION || IBM_WORKPAD || LASAT || MIPS_COBALT || MIPS_ITE8172 || MIPS_IVR || SOC_AU1X00 || NEC_OSPREY || OLIVETTI_M700 || SNI_RM200_PCI || VICTOR_MPC30X || ZAO_CAPCELLA
-+ default y if ACER_PICA_61 || CASIO_E55 || DDB5074 || DDB5476 || DDB5477 || MACH_DECSTATION || IBM_WORKPAD || LASAT || MIPS_COBALT || MIPS_ITE8172 || MIPS_IVR || SOC_AU1X00 || NEC_OSPREY || OLIVETTI_M700 || SNI_RM200_PCI || VICTOR_MPC30X || ZAO_CAPCELLA || BCM947XX
- default n if MIPS_EV64120 || MIPS_EV96100 || MOMENCO_OCELOT || MOMENCO_OCELOT_G || SGI_IP22 || SGI_IP27 || SGI_IP32 || TOSHIBA_JMR3927
- help
- Some MIPS machines can be configured for either little or big endian
-diff -Nur linux-2.6.12.5/arch/mips/Makefile linux-2.6.12.5-brcm/arch/mips/Makefile
---- linux-2.6.12.5/arch/mips/Makefile 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/arch/mips/Makefile 2005-09-03 22:24:07.794917120 +0200
-@@ -79,7 +79,7 @@
- cflags-y += -I $(TOPDIR)/include/asm/gcc
- cflags-y += -G 0 -mno-abicalls -fno-pic -pipe
- cflags-y += $(call cc-option, -finline-limit=100000)
--LDFLAGS_vmlinux += -G 0 -static -n
-+LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
- MODFLAGS += -mlong-calls
-
- cflags-$(CONFIG_SB1XXX_CORELIS) += -mno-sched-prolog -fno-omit-frame-pointer
-@@ -170,6 +170,7 @@
- cflags-$(CONFIG_CPU_MIPS32) += \
- $(call set_gccflags,mips32,mips32,r4600,mips3,mips2) \
- -Wa,--trap
-+cflags-$(CONFIG_CPU_MIPS32) += -Wa,--trap
-
- cflags-$(CONFIG_CPU_MIPS64) += \
- $(call set_gccflags,mips64,mips64,r4600,mips3,mips2) \
-@@ -618,6 +619,14 @@
- load-$(CONFIG_SIBYTE_SWARM) := 0xffffffff80100000
-
- #
-+# Broadcom BCM47XX boards
-+#
-+core-$(CONFIG_BCM947XX) += arch/mips/bcm947xx/ arch/mips/bcm947xx/broadcom/
-+cflags-$(CONFIG_BCM947XX) += -Iarch/mips/bcm947xx/include
-+load-$(CONFIG_BCM947XX) := 0xffffffff80001000
-+
-+
-+#
- # SNI RM200 PCI
- #
- core-$(CONFIG_SNI_RM200_PCI) += arch/mips/sni/
-diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/Makefile linux-2.6.12.5-brcm/arch/mips/bcm947xx/Makefile
---- linux-2.6.12.5/arch/mips/bcm947xx/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/Makefile 2005-08-28 11:12:20.406862800 +0200
-@@ -0,0 +1,6 @@
-+#
-+# Makefile for the BCM47xx specific kernel interface routines
-+# under Linux.
-+#
-+
-+obj-y := irq.o int-handler.o prom.o setup.o time.o
-diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/Makefile linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/Makefile
---- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/Makefile 2005-08-28 11:12:20.407862648 +0200
-@@ -0,0 +1,6 @@
-+#
-+# Makefile for the BCM47xx specific kernel interface routines
-+# under Linux.
-+#
-+
-+obj-y := sbutils.o linux_osl.o bcmsrom.o bcmutils.o sbmips.o sbpci.o hnddma.o
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/bcmsrom.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/bcmsrom.c
--- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/bcmsrom.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/bcmsrom.c 2005-08-28 11:12:20.408862496 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/bcmsrom.c 2005-11-07 01:12:51.811809000 +0100
@@ -0,0 +1,685 @@
+/*
+ * Misc useful routines to access NIC SROM
+
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/bcmutils.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/bcmutils.c
--- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/bcmutils.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/bcmutils.c 2005-08-28 11:12:20.428859456 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/bcmutils.c 2005-11-07 01:12:51.815809250 +0100
@@ -0,0 +1,691 @@
+/*
+ * Misc useful OS-independent routines.
+
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/hnddma.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/hnddma.c
--- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/hnddma.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/hnddma.c 2005-08-28 11:12:20.430859152 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/hnddma.c 2005-11-07 01:12:51.815809250 +0100
@@ -0,0 +1,763 @@
+/*
+ * Generic Broadcom Home Networking Division (HND) DMA module.
+}
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/linux_osl.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/linux_osl.c
--- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/linux_osl.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/linux_osl.c 2005-08-28 11:12:20.476852160 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/linux_osl.c 2005-11-07 01:12:51.815809250 +0100
@@ -0,0 +1,420 @@
+/*
+ * Linux OS Independent Layer
+}
+
+#endif
-diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/sbmips.c
---- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/sbmips.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/sbmips.c 2005-08-28 11:12:20.478851856 +0200
-@@ -0,0 +1,950 @@
+diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/Makefile linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/Makefile
+--- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/Makefile 2005-11-19 14:16:38.941631500 +0100
+@@ -0,0 +1,7 @@
++#
++# Makefile for the BCM47xx specific kernel interface routines
++# under Linux.
++#
++
++obj-y := sbutils.o linux_osl.o bcmsrom.o bcmutils.o sbmips.o sbpci.o hnddma.o
++#obj-y := nvram.o nvram_linux.o
+diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/nvram.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/nvram.c
+--- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/nvram.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/nvram.c 2005-11-19 02:28:26.438059500 +0100
+@@ -0,0 +1,321 @@
+/*
-+ * BCM47XX Sonics SiliconBackplane MIPS core routines
++ * NVRAM variable manipulation (common)
+ *
-+ * Copyright 2001-2003, Broadcom Corporation
++ * Copyright 2004, Broadcom Corporation
+ * All Rights Reserved.
+ *
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
-+ * $Id: sbmips.c,v 1.1 2005/02/28 13:33:32 jolt Exp $
++ * $Id$
+ */
+
+#include <typedefs.h>
+#include <osl.h>
-+#include <sbutils.h>
-+#include <bcmdevs.h>
++#include <bcmendian.h>
+#include <bcmnvram.h>
+#include <bcmutils.h>
-+#include <hndmips.h>
-+#include <sbconfig.h>
-+#include <sbextif.h>
-+#include <sbchipc.h>
-+#include <sbmemc.h>
++#include <sbsdram.h>
+
-+/*
-+ * Memory segments (32bit kernel mode addresses)
-+ */
-+#undef KUSEG
-+#undef KSEG0
-+#undef KSEG1
-+#undef KSEG2
-+#undef KSEG3
-+#define KUSEG 0x00000000
-+#define KSEG0 0x80000000
-+#define KSEG1 0xa0000000
-+#define KSEG2 0xc0000000
-+#define KSEG3 0xe0000000
++extern struct nvram_tuple * BCMINIT(_nvram_realloc)(struct nvram_tuple *t, const char *name, const char *value);
++extern void BCMINIT(_nvram_free)(struct nvram_tuple *t);
++extern int BCMINIT(_nvram_read)(void *buf);
+
-+/*
-+ * Map an address to a certain kernel segment
-+ */
-+#undef KSEG0ADDR
-+#undef KSEG1ADDR
-+#undef KSEG2ADDR
-+#undef KSEG3ADDR
-+#define KSEG0ADDR(a) (((a) & 0x1fffffff) | KSEG0)
-+#define KSEG1ADDR(a) (((a) & 0x1fffffff) | KSEG1)
-+#define KSEG2ADDR(a) (((a) & 0x1fffffff) | KSEG2)
-+#define KSEG3ADDR(a) (((a) & 0x1fffffff) | KSEG3)
++char * BCMINIT(_nvram_get)(const char *name);
++int BCMINIT(_nvram_set)(const char *name, const char *value);
++int BCMINIT(_nvram_unset)(const char *name);
++int BCMINIT(_nvram_getall)(char *buf, int count);
++int BCMINIT(_nvram_commit)(struct nvram_header *header);
++int BCMINIT(_nvram_init)(void);
++void BCMINIT(_nvram_exit)(void);
+
-+/*
-+ * The following macros are especially useful for __asm__
-+ * inline assembler.
-+ */
-+#ifndef __STR
-+#define __STR(x) #x
-+#endif
-+#ifndef STR
-+#define STR(x) __STR(x)
-+#endif
++static struct nvram_tuple * BCMINITDATA(nvram_hash)[257];
++static struct nvram_tuple * nvram_dead;
+
-+/* *********************************************************************
-+ * CP0 Registers
-+ ********************************************************************* */
++/* Free all tuples. Should be locked. */
++static void
++BCMINITFN(nvram_free)(void)
++{
++ uint i;
++ struct nvram_tuple *t, *next;
+
-+#define C0_INX 0 /* CP0: TLB Index */
-+#define C0_RAND 1 /* CP0: TLB Random */
-+#define C0_TLBLO0 2 /* CP0: TLB EntryLo0 */
-+#define C0_TLBLO C0_TLBLO0 /* CP0: TLB EntryLo0 */
-+#define C0_TLBLO1 3 /* CP0: TLB EntryLo1 */
-+#define C0_CTEXT 4 /* CP0: Context */
-+#define C0_PGMASK 5 /* CP0: TLB PageMask */
-+#define C0_WIRED 6 /* CP0: TLB Wired */
-+#define C0_BADVADDR 8 /* CP0: Bad Virtual Address */
-+#define C0_COUNT 9 /* CP0: Count */
-+#define C0_TLBHI 10 /* CP0: TLB EntryHi */
-+#define C0_COMPARE 11 /* CP0: Compare */
-+#define C0_SR 12 /* CP0: Processor Status */
-+#define C0_STATUS C0_SR /* CP0: Processor Status */
-+#define C0_CAUSE 13 /* CP0: Exception Cause */
-+#define C0_EPC 14 /* CP0: Exception PC */
-+#define C0_PRID 15 /* CP0: Processor Revision Indentifier */
-+#define C0_CONFIG 16 /* CP0: Config */
-+#define C0_LLADDR 17 /* CP0: LLAddr */
-+#define C0_WATCHLO 18 /* CP0: WatchpointLo */
-+#define C0_WATCHHI 19 /* CP0: WatchpointHi */
-+#define C0_XCTEXT 20 /* CP0: XContext */
-+#define C0_DIAGNOSTIC 22 /* CP0: Diagnostic */
-+#define C0_BROADCOM C0_DIAGNOSTIC /* CP0: Broadcom Register */
-+#define C0_ECC 26 /* CP0: ECC */
-+#define C0_CACHEERR 27 /* CP0: CacheErr */
-+#define C0_TAGLO 28 /* CP0: TagLo */
-+#define C0_TAGHI 29 /* CP0: TagHi */
-+#define C0_ERREPC 30 /* CP0: ErrorEPC */
++ /* Free hash table */
++ for (i = 0; i < ARRAYSIZE(BCMINIT(nvram_hash)); i++) {
++ for (t = BCMINIT(nvram_hash)[i]; t; t = next) {
++ next = t->next;
++ BCMINIT(_nvram_free)(t);
++ }
++ BCMINIT(nvram_hash)[i] = NULL;
++ }
+
-+/*
-+ * Macros to access the system control coprocessor
-+ */
++ /* Free dead table */
++ for (t = nvram_dead; t; t = next) {
++ next = t->next;
++ BCMINIT(_nvram_free)(t);
++ }
++ nvram_dead = NULL;
+
-+#define MFC0(source, sel) \
-+({ \
-+ int __res; \
-+ __asm__ __volatile__( \
-+ ".set\tnoreorder\n\t" \
-+ ".set\tnoat\n\t" \
-+ ".word\t"STR(0x40010000 | ((source)<<11) | (sel))"\n\t" \
-+ "move\t%0,$1\n\t" \
-+ ".set\tat\n\t" \
-+ ".set\treorder" \
-+ :"=r" (__res) \
-+ : \
-+ :"$1"); \
-+ __res; \
-+})
++ /* Indicate to per-port code that all tuples have been freed */
++ BCMINIT(_nvram_free)(NULL);
++}
+
-+#define MTC0(source, sel, value) \
-+do { \
-+ __asm__ __volatile__( \
-+ ".set\tnoreorder\n\t" \
-+ ".set\tnoat\n\t" \
-+ "move\t$1,%z0\n\t" \
-+ ".word\t"STR(0x40810000 | ((source)<<11) | (sel))"\n\t" \
-+ ".set\tat\n\t" \
-+ ".set\treorder" \
-+ : \
-+ :"Jr" (value) \
-+ :"$1"); \
-+} while (0)
++/* String hash */
++static INLINE uint
++hash(const char *s)
++{
++ uint hash = 0;
+
-+/*
-+ * R4x00 interrupt enable / cause bits
-+ */
-+#undef IE_SW0
-+#undef IE_SW1
-+#undef IE_IRQ0
-+#undef IE_IRQ1
-+#undef IE_IRQ2
-+#undef IE_IRQ3
-+#undef IE_IRQ4
-+#undef IE_IRQ5
-+#define IE_SW0 (1<< 8)
-+#define IE_SW1 (1<< 9)
-+#define IE_IRQ0 (1<<10)
-+#define IE_IRQ1 (1<<11)
-+#define IE_IRQ2 (1<<12)
-+#define IE_IRQ3 (1<<13)
-+#define IE_IRQ4 (1<<14)
-+#define IE_IRQ5 (1<<15)
++ while (*s)
++ hash = 31 * hash + *s++;
+
-+/*
-+ * Bitfields in the R4xx0 cp0 status register
-+ */
-+#define ST0_IE 0x00000001
-+#define ST0_EXL 0x00000002
-+#define ST0_ERL 0x00000004
-+#define ST0_KSU 0x00000018
-+# define KSU_USER 0x00000010
-+# define KSU_SUPERVISOR 0x00000008
-+# define KSU_KERNEL 0x00000000
-+#define ST0_UX 0x00000020
-+#define ST0_SX 0x00000040
-+#define ST0_KX 0x00000080
-+#define ST0_DE 0x00010000
-+#define ST0_CE 0x00020000
++ return hash;
++}
+
-+/*
-+ * Status register bits available in all MIPS CPUs.
-+ */
-+#define ST0_IM 0x0000ff00
-+#define ST0_CH 0x00040000
-+#define ST0_SR 0x00100000
-+#define ST0_TS 0x00200000
-+#define ST0_BEV 0x00400000
-+#define ST0_RE 0x02000000
-+#define ST0_FR 0x04000000
-+#define ST0_CU 0xf0000000
-+#define ST0_CU0 0x10000000
-+#define ST0_CU1 0x20000000
-+#define ST0_CU2 0x40000000
-+#define ST0_CU3 0x80000000
-+#define ST0_XX 0x80000000 /* MIPS IV naming */
-+
-+/*
-+ * Cache Operations
-+ */
++/* (Re)initialize the hash table. Should be locked. */
++static int
++BCMINITFN(nvram_rehash)(struct nvram_header *header)
++{
++ char buf[] = "0xXXXXXXXX", *name, *value, *end, *eq;
+
-+#ifndef Fill_I
-+#define Fill_I 0x14
-+#endif
++ /* (Re)initialize hash table */
++ BCMINIT(nvram_free)();
+
-+#define cache_unroll(base,op) \
-+ __asm__ __volatile__(" \
-+ .set noreorder; \
-+ .set mips3; \
-+ cache %1, (%0); \
-+ .set mips0; \
-+ .set reorder" \
-+ : \
-+ : "r" (base), \
-+ "i" (op));
++ /* Parse and set "name=value\0 ... \0\0" */
++ name = (char *) &header[1];
++ end = (char *) header + NVRAM_SPACE - 2;
++ end[0] = end[1] = '\0';
++ for (; *name; name = value + strlen(value) + 1) {
++ if (!(eq = strchr(name, '=')))
++ break;
++ *eq = '\0';
++ value = eq + 1;
++ BCMINIT(_nvram_set)(name, value);
++ *eq = '=';
++ }
+
-+/*
-+ * These are the UART port assignments, expressed as offsets from the base
-+ * register. These assignments should hold for any serial port based on
-+ * a 8250, 16450, or 16550(A).
-+ */
++ /* Set special SDRAM parameters */
++ if (!BCMINIT(_nvram_get)("sdram_init")) {
++ sprintf(buf, "0x%04X", (uint16)(header->crc_ver_init >> 16));
++ BCMINIT(_nvram_set)("sdram_init", buf);
++ }
++ if (!BCMINIT(_nvram_get)("sdram_config")) {
++ sprintf(buf, "0x%04X", (uint16)(header->config_refresh & 0xffff));
++ BCMINIT(_nvram_set)("sdram_config", buf);
++ }
++ if (!BCMINIT(_nvram_get)("sdram_refresh")) {
++ sprintf(buf, "0x%04X", (uint16)((header->config_refresh >> 16) & 0xffff));
++ BCMINIT(_nvram_set)("sdram_refresh", buf);
++ }
++ if (!BCMINIT(_nvram_get)("sdram_ncdl")) {
++ sprintf(buf, "0x%08X", header->config_ncdl);
++ BCMINIT(_nvram_set)("sdram_ncdl", buf);
++ }
+
-+#define UART_MCR 4 /* Out: Modem Control Register */
-+#define UART_MSR 6 /* In: Modem Status Register */
-+#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
++ return 0;
++}
+
-+/*
-+ * Returns TRUE if an external UART exists at the given base
-+ * register.
-+ */
-+static bool
-+serial_exists(uint8 *regs)
++/* Get the value of an NVRAM variable. Should be locked. */
++char *
++BCMINITFN(_nvram_get)(const char *name)
+{
-+ uint8 save_mcr, status1;
++ uint i;
++ struct nvram_tuple *t;
++ char *value;
+
-+ save_mcr = R_REG(®s[UART_MCR]);
-+ W_REG(®s[UART_MCR], UART_MCR_LOOP | 0x0a);
-+ status1 = R_REG(®s[UART_MSR]) & 0xf0;
-+ W_REG(®s[UART_MCR], save_mcr);
++ if (!name)
++ return NULL;
+
-+ return (status1 == 0x90);
++ /* Hash the name */
++ i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash));
++
++ /* Find the associated tuple in the hash table */
++ for (t = BCMINIT(nvram_hash)[i]; t && strcmp(t->name, name); t = t->next);
++
++ value = t ? t->value : NULL;
++
++ return value;
+}
+
-+/*
-+ * Initializes UART access. The callback function will be called once
-+ * per found UART.
-+*/
-+void
-+sb_serial_init(void *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift))
++/* Get the value of an NVRAM variable. Should be locked. */
++int
++BCMINITFN(_nvram_set)(const char *name, const char *value)
+{
-+ void *regs;
-+ ulong base;
-+ uint irq;
-+ int i, n;
++ uint i;
++ struct nvram_tuple *t, *u, **prev;
+
-+ if ((regs = sb_setcore(sbh, SB_EXTIF, 0))) {
-+ extifregs_t *eir = (extifregs_t *) regs;
-+ sbconfig_t *sb;
++ /* Hash the name */
++ i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash));
+
-+ /* Determine external UART register base */
-+ sb = (sbconfig_t *)((ulong) eir + SBCONFIGOFF);
-+ base = EXTIF_CFGIF_BASE(sb_base(R_REG(&sb->sbadmatch1)));
++ /* Find the associated tuple in the hash table */
++ for (prev = &BCMINIT(nvram_hash)[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev);
+
-+ /* Determine IRQ */
-+ irq = sb_irq(sbh);
++ /* (Re)allocate tuple */
++ if (!(u = BCMINIT(_nvram_realloc)(t, name, value)))
++ return -12; /* -ENOMEM */
+
-+ /* Disable GPIO interrupt initially */
-+ W_REG(&eir->gpiointpolarity, 0);
-+ W_REG(&eir->gpiointmask, 0);
++ /* Value reallocated */
++ if (t && t == u)
++ return 0;
+
-+ /* Search for external UARTs */
-+ n = 2;
-+ for (i = 0; i < 2; i++) {
-+ regs = (void *) REG_MAP(base + (i * 8), 8);
-+ if (serial_exists(regs)) {
-+ /* Set GPIO 1 to be the external UART IRQ */
-+ W_REG(&eir->gpiointmask, 2);
-+ if (add)
-+ add(regs, irq, 13500000, 0);
-+ }
-+ }
++ /* Move old tuple to the dead table */
++ if (t) {
++ *prev = t->next;
++ t->next = nvram_dead;
++ nvram_dead = t;
++ }
+
-+ /* Add internal UART if enabled */
-+ if (R_REG(&eir->corecontrol) & CC_UE)
-+ if (add)
-+ add((void *) &eir->uartdata, irq, sb_clock(sbh), 2);
-+ } else if ((regs = sb_setcore(sbh, SB_CC, 0))) {
-+ chipcregs_t *cc = (chipcregs_t *) regs;
-+ uint32 rev, cap, pll, baud_base, div;
++ /* Add new tuple to the hash table */
++ u->next = BCMINIT(nvram_hash)[i];
++ BCMINIT(nvram_hash)[i] = u;
+
-+ /* Determine core revision and capabilities */
-+ rev = sb_corerev(sbh);
-+ cap = R_REG(&cc->capabilities);
-+ pll = cap & CAP_PLL_MASK;
++ return 0;
++}
+
-+ /* Determine IRQ */
-+ irq = sb_irq(sbh);
++/* Unset the value of an NVRAM variable. Should be locked. */
++int
++BCMINITFN(_nvram_unset)(const char *name)
++{
++ uint i;
++ struct nvram_tuple *t, **prev;
+
-+ if (pll == PLL_TYPE1) {
-+ /* PLL clock */
-+ baud_base = sb_clock_rate(pll,
-+ R_REG(&cc->clockcontrol_n),
-+ R_REG(&cc->clockcontrol_m2));
-+ div = 1;
-+ } else if (rev >= 3) {
-+ /* Internal backplane clock */
-+ baud_base = sb_clock_rate(pll,
-+ R_REG(&cc->clockcontrol_n),
-+ R_REG(&cc->clockcontrol_sb));
-+ div = 2; /* Minimum divisor */
-+ W_REG(&cc->uart_clkdiv, div);
-+ } else {
-+ /* Fixed internal backplane clock */
-+ baud_base = 88000000;
-+ div = 48;
-+ }
++ if (!name)
++ return 0;
+
-+ /* Clock source depends on strapping if UartClkOverride is unset */
-+ if ((rev > 0) && ((R_REG(&cc->corecontrol) & CC_UARTCLKO) == 0)) {
-+ if ((cap & CAP_UCLKSEL) == CAP_UINTCLK) {
-+ /* Internal divided backplane clock */
-+ baud_base /= div;
-+ } else {
-+ /* Assume external clock of 1.8432 MHz */
-+ baud_base = 1843200;
-+ }
-+ }
++ /* Hash the name */
++ i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash));
+
-+ /* Add internal UARTs */
-+ n = cap & CAP_UARTS_MASK;
-+ for (i = 0; i < n; i++) {
-+ /* Register offset changed after revision 0 */
-+ if (rev)
-+ regs = (void *)((ulong) &cc->uart0data + (i * 256));
-+ else
-+ regs = (void *)((ulong) &cc->uart0data + (i * 8));
++ /* Find the associated tuple in the hash table */
++ for (prev = &BCMINIT(nvram_hash)[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev);
+
-+ if (add)
-+ add(regs, irq, baud_base, 0);
-+ }
++ /* Move it to the dead table */
++ if (t) {
++ *prev = t->next;
++ t->next = nvram_dead;
++ nvram_dead = t;
+ }
++
++ return 0;
+}
+
-+/* Returns the SB interrupt flag of the current core. */
-+uint32
-+sb_flag(void *sbh)
++/* Get all NVRAM variables. Should be locked. */
++int
++BCMINITFN(_nvram_getall)(char *buf, int count)
+{
-+ void *regs;
-+ sbconfig_t *sb;
-+
-+ regs = sb_coreregs(sbh);
-+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++ uint i;
++ struct nvram_tuple *t;
++ int len = 0;
+
-+ return (R_REG(&sb->sbtpsflag) & SBTPS_NUM0_MASK);
-+}
++ bzero(buf, count);
+
-+static const uint32 sbips_int_mask[] = {
-+ 0,
-+ SBIPS_INT1_MASK,
-+ SBIPS_INT2_MASK,
-+ SBIPS_INT3_MASK,
-+ SBIPS_INT4_MASK
-+};
++ /* Write name=value\0 ... \0\0 */
++ for (i = 0; i < ARRAYSIZE(BCMINIT(nvram_hash)); i++) {
++ for (t = BCMINIT(nvram_hash)[i]; t; t = t->next) {
++ if ((count - len) > (strlen(t->name) + 1 + strlen(t->value) + 1))
++ len += sprintf(buf + len, "%s=%s", t->name, t->value) + 1;
++ else
++ break;
++ }
++ }
+
-+static const uint32 sbips_int_shift[] = {
-+ 0,
-+ 0,
-+ SBIPS_INT2_SHIFT,
-+ SBIPS_INT3_SHIFT,
-+ SBIPS_INT4_SHIFT
-+};
++ return 0;
++}
+
-+/*
-+ * Returns the MIPS IRQ assignment of the current core. If unassigned,
-+ * 0 is returned.
-+ */
-+uint
-+sb_irq(void *sbh)
++/* Regenerate NVRAM. Should be locked. */
++int
++BCMINITFN(_nvram_commit)(struct nvram_header *header)
+{
-+ uint idx;
-+ void *regs;
-+ sbconfig_t *sb;
-+ uint32 flag, sbipsflag;
-+ uint irq = 0;
++ char *init, *config, *refresh, *ncdl;
++ char *ptr, *end;
++ int i;
++ struct nvram_tuple *t;
++ struct nvram_header tmp;
++ uint8 crc;
+
-+ flag = sb_flag(sbh);
++ /* Regenerate header */
++ header->magic = NVRAM_MAGIC;
++ header->crc_ver_init = (NVRAM_VERSION << 8);
++ if (!(init = BCMINIT(_nvram_get)("sdram_init")) ||
++ !(config = BCMINIT(_nvram_get)("sdram_config")) ||
++ !(refresh = BCMINIT(_nvram_get)("sdram_refresh")) ||
++ !(ncdl = BCMINIT(_nvram_get)("sdram_ncdl"))) {
++ header->crc_ver_init |= SDRAM_INIT << 16;
++ header->config_refresh = SDRAM_CONFIG;
++ header->config_refresh |= SDRAM_REFRESH << 16;
++ header->config_ncdl = 0;
++ } else {
++ header->crc_ver_init |= (bcm_strtoul(init, NULL, 0) & 0xffff) << 16;
++ header->config_refresh = bcm_strtoul(config, NULL, 0) & 0xffff;
++ header->config_refresh |= (bcm_strtoul(refresh, NULL, 0) & 0xffff) << 16;
++ header->config_ncdl = bcm_strtoul(ncdl, NULL, 0);
++ }
+
-+ idx = sb_coreidx(sbh);
++ /* Clear data area */
++ ptr = (char *) header + sizeof(struct nvram_header);
++ bzero(ptr, NVRAM_SPACE - sizeof(struct nvram_header));
+
-+ if ((regs = sb_setcore(sbh, SB_MIPS, 0)) ||
-+ (regs = sb_setcore(sbh, SB_MIPS33, 0))) {
-+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++ /* Leave space for a double NUL at the end */
++ end = (char *) header + NVRAM_SPACE - 2;
+
-+ /* sbipsflag specifies which core is routed to interrupts 1 to 4 */
-+ sbipsflag = R_REG(&sb->sbipsflag);
-+ for (irq = 1; irq <= 4; irq++) {
-+ if (((sbipsflag & sbips_int_mask[irq]) >> sbips_int_shift[irq]) == flag)
++ /* Write out all tuples */
++ for (i = 0; i < ARRAYSIZE(BCMINIT(nvram_hash)); i++) {
++ for (t = BCMINIT(nvram_hash)[i]; t; t = t->next) {
++ if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end)
+ break;
++ ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1;
+ }
-+ if (irq == 5)
-+ irq = 0;
+ }
+
-+ sb_setcoreidx(sbh, idx);
++ /* End with a double NUL */
++ ptr += 2;
+
-+ return irq;
-+}
++ /* Set new length */
++ header->len = ROUNDUP(ptr - (char *) header, 4);
+
-+/* Clears the specified MIPS IRQ. */
-+static void
-+sb_clearirq(void *sbh, uint irq)
-+{
-+ void *regs;
-+ sbconfig_t *sb;
++ /* Little-endian CRC8 over the last 11 bytes of the header */
++ tmp.crc_ver_init = htol32(header->crc_ver_init);
++ tmp.config_refresh = htol32(header->config_refresh);
++ tmp.config_ncdl = htol32(header->config_ncdl);
++ crc = hndcrc8((char *) &tmp + 9, sizeof(struct nvram_header) - 9, CRC8_INIT_VALUE);
+
-+ if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
-+ !(regs = sb_setcore(sbh, SB_MIPS33, 0)))
-+ ASSERT(regs);
-+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++ /* Continue CRC8 over data bytes */
++ crc = hndcrc8((char *) &header[1], header->len - sizeof(struct nvram_header), crc);
+
-+ if (irq == 0)
-+ W_REG(&sb->sbintvec, 0);
-+ else
-+ OR_REG(&sb->sbipsflag, sbips_int_mask[irq]);
++ /* Set new CRC8 */
++ header->crc_ver_init |= crc;
++
++ /* Reinitialize hash table */
++ return BCMINIT(nvram_rehash)(header);
+}
+
-+/*
-+ * Assigns the specified MIPS IRQ to the specified core. Shared MIPS
-+ * IRQ 0 may be assigned more than once.
-+ */
-+static void
-+sb_setirq(void *sbh, uint irq, uint coreid, uint coreunit)
++/* Initialize hash table. Should be locked. */
++int
++BCMINITFN(_nvram_init)(void)
+{
-+ void *regs;
-+ sbconfig_t *sb;
-+ uint32 flag;
-+
-+ regs = sb_setcore(sbh, coreid, coreunit);
-+ ASSERT(regs);
-+ flag = sb_flag(sbh);
++ struct nvram_header *header;
++ int ret;
++ void *osh;
+
-+ if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
-+ !(regs = sb_setcore(sbh, SB_MIPS33, 0)))
-+ ASSERT(regs);
-+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++ /* get kernel osl handler */
++ osh = osl_attach(NULL);
+
-+ if (irq == 0)
-+ OR_REG(&sb->sbintvec, 1 << flag);
-+ else {
-+ flag <<= sbips_int_shift[irq];
-+ ASSERT(!(flag & ~sbips_int_mask[irq]));
-+ flag |= R_REG(&sb->sbipsflag) & ~sbips_int_mask[irq];
-+ W_REG(&sb->sbipsflag, flag);
++ if (!(header = (struct nvram_header *) MALLOC(osh, NVRAM_SPACE))) {
++ printf("nvram_init: out of memory, malloced %d bytes\n", MALLOCED(osh));
++ return -12; /* -ENOMEM */
+ }
-+}
+
-+/*
-+ * Initializes clocks and interrupts. SB and NVRAM access must be
-+ * initialized prior to calling.
-+ */
-+void
-+sb_mips_init(void *sbh)
-+{
-+ ulong hz, ns, tmp;
-+ extifregs_t *eir;
++ if ((ret = BCMINIT(_nvram_read)(header)) == 0 &&
++ header->magic == NVRAM_MAGIC)
++ BCMINIT(nvram_rehash)(header);
++
++ MFREE(osh, header, NVRAM_SPACE);
++ return ret;
++}
++
++/* Free hash table. Should be locked. */
++void
++BCMINITFN(_nvram_exit)(void)
++{
++ BCMINIT(nvram_free)();
++}
+diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/nvram_linux.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/nvram_linux.c
+--- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/nvram_linux.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/nvram_linux.c 2005-11-19 02:28:26.438059500 +0100
+@@ -0,0 +1,633 @@
++/*
++ * NVRAM variable manipulation (Linux kernel half)
++ *
++ * 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.
++ *
++ * $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/bootmem.h>
++#include <linux/wrapper.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/mtd/mtd.h>
++#include <asm/addrspace.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++
++#include <typedefs.h>
++#include <bcmendian.h>
++#include <bcmnvram.h>
++#include <bcmutils.h>
++#include <sbconfig.h>
++#include <sbchipc.h>
++#include <sbutils.h>
++#include <sbmips.h>
++#include <sflash.h>
++
++/* In BSS to minimize text size and page aligned so it can be mmap()-ed */
++static char nvram_buf[NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE)));
++
++#ifdef MODULE
++
++#define early_nvram_get(name) nvram_get(name)
++
++#else /* !MODULE */
++
++/* Global SB handle */
++extern void *bcm947xx_sbh;
++extern spinlock_t bcm947xx_sbh_lock;
++
++/* Convenience */
++#define sbh bcm947xx_sbh
++#define sbh_lock bcm947xx_sbh_lock
++#define KB * 1024
++#define MB * 1024 * 1024
++
++/* Probe for NVRAM header */
++static void __init
++early_nvram_init(void)
++{
++ struct nvram_header *header;
+ chipcregs_t *cc;
-+ char *value;
-+ uint irq;
++ struct sflash *info = NULL;
++ int i;
++ uint32 base, off, lim;
++ u32 *src, *dst;
++
++ if ((cc = sb_setcore(sbh, SB_CC, 0)) != NULL) {
++ base = KSEG1ADDR(SB_FLASH2);
++ switch (readl(&cc->capabilities) & CAP_FLASH_MASK) {
++ case PFLASH:
++ lim = SB_FLASH2_SZ;
++ break;
+
-+ /* Figure out current SB clock speed */
-+ if ((hz = sb_clock(sbh)) == 0)
-+ hz = 100000000;
-+ ns = 1000000000 / hz;
++ case SFLASH_ST:
++ case SFLASH_AT:
++ if ((info = sflash_init(cc)) == NULL)
++ return;
++ lim = info->size;
++ break;
+
-+ /* Setup external interface timing */
-+ if ((eir = sb_setcore(sbh, SB_EXTIF, 0))) {
-+ /* Initialize extif so we can get to the LEDs and external UART */
-+ W_REG(&eir->prog_config, CF_EN);
++ case FLASH_NONE:
++ default:
++ return;
++ }
++ } else {
++ /* extif assumed, Stop at 4 MB */
++ base = KSEG1ADDR(SB_FLASH1);
++ lim = SB_FLASH1_SZ;
++ }
+
-+ /* Set timing for the flash */
-+ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
-+ tmp = tmp | (CEIL(40, ns) << FW_W1_SHIFT); /* W1 = 40nS */
-+ tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
-+ W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
++ off = FLASH_MIN;
++ while (off <= lim) {
++ /* Windowed flash access */
++ header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
++ if (header->magic == NVRAM_MAGIC)
++ goto found;
++ off <<= 1;
++ }
+
-+ /* Set programmable interface timing for external uart */
-+ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
-+ tmp = tmp | (CEIL(20, ns) << FW_W2_SHIFT); /* W2 = 20nS */
-+ tmp = tmp | (CEIL(100, ns) << FW_W1_SHIFT); /* W1 = 100nS */
-+ tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
-+ W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
-+ } else if ((cc = sb_setcore(sbh, SB_CC, 0))) {
-+ /* Set timing for the flash */
-+ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
-+ tmp |= CEIL(10, ns) << FW_W1_SHIFT; /* W1 = 10nS */
-+ tmp |= CEIL(120, ns); /* W0 = 120nS */
-+ W_REG(&cc->parallelflashwaitcnt, tmp);
++ /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
++ header = (struct nvram_header *) KSEG1ADDR(base + 4 KB);
++ if (header->magic == NVRAM_MAGIC)
++ goto found;
++
++ header = (struct nvram_header *) KSEG1ADDR(base + 1 KB);
++ if (header->magic == NVRAM_MAGIC)
++ goto found;
++
++ printk("early_nvram_init: NVRAM not found\n");
++ return;
+
-+ W_REG(&cc->cs01memwaitcnt, tmp);
++found:
++ src = (u32 *) header;
++ dst = (u32 *) nvram_buf;
++ for (i = 0; i < sizeof(struct nvram_header); i += 4)
++ *dst++ = *src++;
++ for (; i < header->len && i < NVRAM_SPACE; i += 4)
++ *dst++ = ltoh32(*src++);
++}
++
++/* Early (before mm or mtd) read-only access to NVRAM */
++static char * __init
++early_nvram_get(const char *name)
++{
++ char *var, *value, *end, *eq;
++
++ if (!name)
++ return NULL;
++
++ /* Too early? */
++ if (sbh == NULL)
++ return NULL;
++
++ if (!nvram_buf[0])
++ early_nvram_init();
++
++ /* Look for name=value and return value */
++ var = &nvram_buf[sizeof(struct nvram_header)];
++ end = nvram_buf + sizeof(nvram_buf) - 2;
++ end[0] = end[1] = '\0';
++ for (; *var; var = value + strlen(value) + 1) {
++ if (!(eq = strchr(var, '=')))
++ break;
++ value = eq + 1;
++ if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
++ return value;
+ }
+
-+ /* Chip specific initialization */
-+ switch (sb_chip(sbh)) {
-+ case BCM4710_DEVICE_ID:
-+ /* Clear interrupt map */
-+ for (irq = 0; irq <= 4; irq++)
-+ sb_clearirq(sbh, irq);
-+ sb_setirq(sbh, 0, SB_CODEC, 0);
-+ sb_setirq(sbh, 0, SB_EXTIF, 0);
-+ sb_setirq(sbh, 2, SB_ENET, 1);
-+ sb_setirq(sbh, 3, SB_ILINE20, 0);
-+ sb_setirq(sbh, 4, SB_PCI, 0);
-+ ASSERT(eir);
-+ value = nvram_get("et0phyaddr");
-+ if (value && !strcmp(value, "31")) {
-+ /* Enable internal UART */
-+ W_REG(&eir->corecontrol, CC_UE);
-+ /* Give USB its own interrupt */
-+ sb_setirq(sbh, 1, SB_USB, 0);
-+ } else {
-+ /* Disable internal UART */
-+ W_REG(&eir->corecontrol, 0);
-+ /* Give Ethernet its own interrupt */
-+ sb_setirq(sbh, 1, SB_ENET, 0);
-+ sb_setirq(sbh, 0, SB_USB, 0);
-+ }
-+ break;
-+ case BCM4310_DEVICE_ID:
-+ MTC0(C0_BROADCOM, 0, MFC0(C0_BROADCOM, 0) & ~(1 << 22));
-+ break;
++ return NULL;
++}
++
++#endif /* !MODULE */
++
++extern char * _nvram_get(const char *name);
++extern int _nvram_set(const char *name, const char *value);
++extern int _nvram_unset(const char *name);
++extern int _nvram_getall(char *buf, int count);
++extern int _nvram_commit(struct nvram_header *header);
++extern int _nvram_init(void);
++extern void _nvram_exit(void);
++
++/* Globals */
++static spinlock_t nvram_lock = SPIN_LOCK_UNLOCKED;
++static struct semaphore nvram_sem;
++static unsigned long nvram_offset = 0;
++static int nvram_major = -1;
++static devfs_handle_t nvram_handle = NULL;
++static struct mtd_info *nvram_mtd = NULL;
++
++int
++_nvram_read(char *buf)
++{
++ struct nvram_header *header = (struct nvram_header *) buf;
++ size_t len;
++
++ if (!nvram_mtd ||
++ MTD_READ(nvram_mtd, nvram_mtd->size - NVRAM_SPACE, NVRAM_SPACE, &len, buf) ||
++ len != NVRAM_SPACE ||
++ header->magic != NVRAM_MAGIC) {
++ /* Maybe we can recover some data from early initialization */
++ memcpy(buf, nvram_buf, NVRAM_SPACE);
+ }
++
++ return 0;
+}
+
-+uint32
-+sb_mips_clock(void *sbh)
++struct nvram_tuple *
++_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value)
+{
-+ extifregs_t *eir;
-+ chipcregs_t *cc;
-+ uint32 n, m;
-+ uint idx;
-+ uint32 pll_type, rate = 0;
++ if ((nvram_offset + strlen(value) + 1) > NVRAM_SPACE)
++ return NULL;
+
-+ /* get index of the current core */
-+ idx = sb_coreidx(sbh);
-+ pll_type = PLL_TYPE1;
++ if (!t) {
++ if (!(t = kmalloc(sizeof(struct nvram_tuple) + strlen(name) + 1, GFP_ATOMIC)))
++ return NULL;
+
-+ /* switch to extif or chipc core */
-+ if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
-+ n = R_REG(&eir->clockcontrol_n);
-+ m = R_REG(&eir->clockcontrol_sb);
-+ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
-+ pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
-+ n = R_REG(&cc->clockcontrol_n);
-+ if ((pll_type == PLL_TYPE2) || (pll_type == PLL_TYPE4))
-+ m = R_REG(&cc->clockcontrol_mips);
-+ else if (pll_type == PLL_TYPE3) {
-+ rate = 200000000;
-+ goto out;
-+ } else
-+ m = R_REG(&cc->clockcontrol_sb);
-+ } else
-+ goto out;
++ /* Copy name */
++ t->name = (char *) &t[1];
++ strcpy(t->name, name);
+
-+ /* calculate rate */
-+ rate = sb_clock_rate(pll_type, n, m);
++ t->value = NULL;
++ }
+
-+out:
-+ /* switch back to previous core */
-+ sb_setcoreidx(sbh, idx);
++ /* Copy value */
++ if (!t->value || strcmp(t->value, value)) {
++ t->value = &nvram_buf[nvram_offset];
++ strcpy(t->value, value);
++ nvram_offset += strlen(value) + 1;
++ }
+
-+ return rate;
++ return t;
+}
+
-+static void
-+icache_probe(int *size, int *lsize)
++void
++_nvram_free(struct nvram_tuple *t)
+{
-+ uint32 config1;
-+ uint sets, ways;
++ if (!t)
++ nvram_offset = 0;
++ else
++ kfree(t);
++}
+
-+ config1 = MFC0(C0_CONFIG, 1);
++int
++nvram_set(const char *name, const char *value)
++{
++ unsigned long flags;
++ int ret;
++ struct nvram_header *header;
++
++ spin_lock_irqsave(&nvram_lock, flags);
++ if ((ret = _nvram_set(name, value))) {
++ /* Consolidate space and try again */
++ if ((header = kmalloc(NVRAM_SPACE, GFP_ATOMIC))) {
++ if (_nvram_commit(header) == 0)
++ ret = _nvram_set(name, value);
++ kfree(header);
++ }
++ }
++ spin_unlock_irqrestore(&nvram_lock, flags);
+
-+ /* Instruction Cache Size = Associativity * Line Size * Sets Per Way */
-+ if ((*lsize = ((config1 >> 19) & 7)))
-+ *lsize = 2 << *lsize;
-+ sets = 64 << ((config1 >> 22) & 7);
-+ ways = 1 + ((config1 >> 16) & 7);
-+ *size = *lsize * sets * ways;
++ return ret;
+}
+
-+#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
++char *
++real_nvram_get(const char *name)
++{
++ unsigned long flags;
++ char *value;
+
-+static void
-+handler(void)
++ spin_lock_irqsave(&nvram_lock, flags);
++ value = _nvram_get(name);
++ spin_unlock_irqrestore(&nvram_lock, flags);
++
++ return value;
++}
++
++char *
++nvram_get(const char *name)
+{
-+ /* Step 11 */
-+ __asm__ (
-+ ".set\tmips32\n\t"
-+ "ssnop\n\t"
-+ "ssnop\n\t"
-+ /* Disable interrupts */
-+ /* MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~(ALLINTS | STO_IE)); */
-+ "mfc0 $15, $12\n\t"
-+ "and $15, $15, -31746\n\t"
-+ "mtc0 $15, $12\n\t"
-+ "eret\n\t"
-+ "nop\n\t"
-+ "nop\n\t"
-+ ".set\tmips0"
-+ );
++ if (nvram_major >= 0)
++ return real_nvram_get(name);
++ else
++ return early_nvram_get(name);
++}
++
++int
++nvram_unset(const char *name)
++{
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&nvram_lock, flags);
++ ret = _nvram_unset(name);
++ spin_unlock_irqrestore(&nvram_lock, flags);
++
++ return ret;
+}
+
-+/* The following MUST come right after handler() */
+static void
-+afterhandler(void)
++erase_callback(struct erase_info *done)
+{
++ wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv;
++ wake_up(wait_q);
+}
+
-+/*
-+ * Set the MIPS, backplane and PCI clocks as closely as possible.
-+ */
-+bool
-+sb_mips_setclock(void *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock)
++int
++nvram_commit(void)
+{
-+ extifregs_t *eir = NULL;
-+ chipcregs_t *cc = NULL;
-+ mipsregs_t *mipsr = NULL;
-+ volatile uint32 *clockcontrol_n, *clockcontrol_sb, *clockcontrol_pci;
-+ uint32 orig_n, orig_sb, orig_pci, orig_m2, orig_mips, orig_ratio_parm, new_ratio;
-+ uint32 pll_type, sync_mode;
-+ uint idx, i;
-+ struct {
-+ uint32 mipsclock;
-+ uint16 n;
-+ uint32 sb;
-+ uint32 pci33;
-+ uint32 pci25;
-+ } type1_table[] = {
-+ { 96000000, 0x0303, 0x04020011, 0x11030011, 0x11050011 }, /* 96.000 32.000 24.000 */
-+ { 100000000, 0x0009, 0x04020011, 0x11030011, 0x11050011 }, /* 100.000 33.333 25.000 */
-+ { 104000000, 0x0802, 0x04020011, 0x11050009, 0x11090009 }, /* 104.000 31.200 24.960 */
-+ { 108000000, 0x0403, 0x04020011, 0x11050009, 0x02000802 }, /* 108.000 32.400 24.923 */
-+ { 112000000, 0x0205, 0x04020011, 0x11030021, 0x02000403 }, /* 112.000 32.000 24.889 */
-+ { 115200000, 0x0303, 0x04020009, 0x11030011, 0x11050011 }, /* 115.200 32.000 24.000 */
-+ { 120000000, 0x0011, 0x04020011, 0x11050011, 0x11090011 }, /* 120.000 30.000 24.000 */
-+ { 124800000, 0x0802, 0x04020009, 0x11050009, 0x11090009 }, /* 124.800 31.200 24.960 */
-+ { 128000000, 0x0305, 0x04020011, 0x11050011, 0x02000305 }, /* 128.000 32.000 24.000 */
-+ { 132000000, 0x0603, 0x04020011, 0x11050011, 0x02000305 }, /* 132.000 33.000 24.750 */
-+ { 136000000, 0x0c02, 0x04020011, 0x11090009, 0x02000603 }, /* 136.000 32.640 24.727 */
-+ { 140000000, 0x0021, 0x04020011, 0x11050021, 0x02000c02 }, /* 140.000 30.000 24.706 */
-+ { 144000000, 0x0405, 0x04020011, 0x01020202, 0x11090021 }, /* 144.000 30.857 24.686 */
-+ { 150857142, 0x0605, 0x04020021, 0x02000305, 0x02000605 }, /* 150.857 33.000 24.000 */
-+ { 152000000, 0x0e02, 0x04020011, 0x11050021, 0x02000e02 }, /* 152.000 32.571 24.000 */
-+ { 156000000, 0x0802, 0x04020005, 0x11050009, 0x11090009 }, /* 156.000 31.200 24.960 */
-+ { 160000000, 0x0309, 0x04020011, 0x11090011, 0x02000309 }, /* 160.000 32.000 24.000 */
-+ { 163200000, 0x0c02, 0x04020009, 0x11090009, 0x02000603 }, /* 163.200 32.640 24.727 */
-+ { 168000000, 0x0205, 0x04020005, 0x11030021, 0x02000403 }, /* 168.000 32.000 24.889 */
-+ { 176000000, 0x0602, 0x04020003, 0x11050005, 0x02000602 }, /* 176.000 33.000 24.000 */
-+ };
-+ typedef struct {
-+ uint32 mipsclock;
-+ uint32 sbclock;
-+ uint16 n;
-+ uint32 sb;
-+ uint32 pci33;
-+ uint32 m2;
-+ uint32 m3;
-+ uint32 ratio;
-+ uint32 ratio_parm;
-+ } n4m_table_t;
-+
-+ n4m_table_t type2_table[] = {
-+ { 180000000, 80000000, 0x0403, 0x01010000, 0x01020300, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
-+ { 180000000, 90000000, 0x0403, 0x01000100, 0x01020300, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 },
-+ { 200000000, 100000000, 0x0303, 0x01000000, 0x01000600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
-+ { 211200000, 105600000, 0x0902, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
-+ { 220800000, 110400000, 0x1500, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
-+ { 230400000, 115200000, 0x0604, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
-+ { 234000000, 104000000, 0x0b01, 0x01010000, 0x01010700, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
-+ { 240000000, 120000000, 0x0803, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
-+ { 252000000, 126000000, 0x0504, 0x01000100, 0x01020500, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 },
-+ { 264000000, 132000000, 0x0903, 0x01000200, 0x01020700, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
-+ { 270000000, 120000000, 0x0703, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
-+ { 276000000, 122666666, 0x1500, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
-+ { 280000000, 140000000, 0x0503, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
-+ { 288000000, 128000000, 0x0604, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
-+ { 288000000, 144000000, 0x0404, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
-+ { 300000000, 133333333, 0x0803, 0x01010000, 0x01020600, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
-+ { 300000000, 150000000, 0x0803, 0x01000100, 0x01020600, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 }
-+ };
++ char *buf;
++ size_t erasesize, len;
++ unsigned int i;
++ int ret;
++ struct nvram_header *header;
++ unsigned long flags;
++ u_int32_t offset;
++ DECLARE_WAITQUEUE(wait, current);
++ wait_queue_head_t wait_q;
++ struct erase_info erase;
+
-+ n4m_table_t type4_table[] = {
-+ { 192000000, 96000000, 0x0702, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 0x21, 0x0aaa0555 },
-+ { 200000000, 100000000, 0x0009, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 0x21, 0x0aaa0555 },
-+ { 216000000, 108000000, 0x0211, 0x11020005, 0x11030303, 0x11020005, 0x04000005, 0x21, 0x0aaa0555 },
-+ { 228000000, 101333333, 0x0e02, 0x11030003, 0x11210005, 0x11030305, 0x04000005, 0x94, 0x012a00a9 },
-+ { 228000000, 114000000, 0x0e02, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 0x21, 0x0aaa0555 },
-+ { 240000000, 120000000, 0x0109, 0x11030002, 0x01050203, 0x11030002, 0x04000003, 0x21, 0x0aaa0555 },
-+ { 252000000, 126000000, 0x0203, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 0x21, 0x0aaa0555 },
-+ { 264000000, 132000000, 0x0602, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 0x21, 0x0aaa0555 },
-+ { 272000000, 116571428, 0x0c02, 0x04000021, 0x02000909, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
-+ { 280000000, 120000000, 0x0209, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
-+ { 288000000, 123428571, 0x0111, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
-+ { 300000000, 120000000, 0x0009, 0x04000009, 0x01030203, 0x02000902, 0x04000002, 0x52, 0x02520129 }
-+ };
-+ uint icache_size, ic_lsize;
-+ ulong start, end, dst;
-+ bool ret = FALSE;
++ if (!nvram_mtd) {
++ printk("nvram_commit: NVRAM not found\n");
++ return -ENODEV;
++ }
+
-+ /* get index of the current core */
-+ idx = sb_coreidx(sbh);
++ if (in_interrupt()) {
++ printk("nvram_commit: not committing in interrupt\n");
++ return -EINVAL;
++ }
+
-+ /* switch to extif or chipc core */
-+ if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
-+ pll_type = PLL_TYPE1;
-+ clockcontrol_n = &eir->clockcontrol_n;
-+ clockcontrol_sb = &eir->clockcontrol_sb;
-+ clockcontrol_pci = &eir->clockcontrol_pci;
-+ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
-+ pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
-+ clockcontrol_n = &cc->clockcontrol_n;
-+ clockcontrol_sb = &cc->clockcontrol_sb;
-+ clockcontrol_pci = &cc->clockcontrol_pci;
-+ } else
-+ goto done;
++ /* Backup sector blocks to be erased */
++ erasesize = ROUNDUP(NVRAM_SPACE, nvram_mtd->erasesize);
++ if (!(buf = kmalloc(erasesize, GFP_KERNEL))) {
++ printk("nvram_commit: out of memory\n");
++ return -ENOMEM;
++ }
+
-+ /* Store the current clock register values */
-+ orig_n = R_REG(clockcontrol_n);
-+ orig_sb = R_REG(clockcontrol_sb);
-+ orig_pci = R_REG(clockcontrol_pci);
++ down(&nvram_sem);
+
-+ if (pll_type == PLL_TYPE1) {
-+ /* Keep the current PCI clock if not specified */
-+ if (pciclock == 0) {
-+ pciclock = sb_clock_rate(pll_type, R_REG(clockcontrol_n), R_REG(clockcontrol_pci));
-+ pciclock = (pciclock <= 25000000) ? 25000000 : 33000000;
++ if ((i = erasesize - NVRAM_SPACE) > 0) {
++ offset = nvram_mtd->size - erasesize;
++ len = 0;
++ ret = MTD_READ(nvram_mtd, offset, i, &len, buf);
++ if (ret || len != i) {
++ printk("nvram_commit: read error ret = %d, len = %d/%d\n", ret, len, i);
++ ret = -EIO;
++ goto done;
+ }
++ header = (struct nvram_header *)(buf + i);
++ } else {
++ offset = nvram_mtd->size - NVRAM_SPACE;
++ header = (struct nvram_header *)buf;
++ }
+
-+ /* Search for the closest MIPS clock less than or equal to a preferred value */
-+ for (i = 0; i < ARRAYSIZE(type1_table); i++) {
-+ ASSERT(type1_table[i].mipsclock ==
-+ sb_clock_rate(pll_type, type1_table[i].n, type1_table[i].sb));
-+ if (type1_table[i].mipsclock > mipsclock)
-+ break;
-+ }
-+ if (i == 0) {
-+ ret = FALSE;
++ /* Regenerate NVRAM */
++ spin_lock_irqsave(&nvram_lock, flags);
++ ret = _nvram_commit(header);
++ spin_unlock_irqrestore(&nvram_lock, flags);
++ if (ret)
++ goto done;
++
++ /* Erase sector blocks */
++ init_waitqueue_head(&wait_q);
++ for (; offset < nvram_mtd->size - NVRAM_SPACE + header->len; offset += nvram_mtd->erasesize) {
++ erase.mtd = nvram_mtd;
++ erase.addr = offset;
++ erase.len = nvram_mtd->erasesize;
++ erase.callback = erase_callback;
++ erase.priv = (u_long) &wait_q;
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_wait_queue(&wait_q, &wait);
++
++ /* Unlock sector blocks */
++ if (nvram_mtd->unlock)
++ nvram_mtd->unlock(nvram_mtd, offset, nvram_mtd->erasesize);
++
++ if ((ret = MTD_ERASE(nvram_mtd, &erase))) {
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&wait_q, &wait);
++ printk("nvram_commit: erase error\n");
+ goto done;
-+ } else {
-+ ret = TRUE;
-+ i--;
+ }
-+ ASSERT(type1_table[i].mipsclock <= mipsclock);
+
-+ /* No PLL change */
-+ if ((orig_n == type1_table[i].n) &&
-+ (orig_sb == type1_table[i].sb) &&
-+ (orig_pci == type1_table[i].pci33))
-+ goto done;
++ /* Wait for erase to finish */
++ schedule();
++ remove_wait_queue(&wait_q, &wait);
++ }
+
-+ /* Set the PLL controls */
-+ W_REG(clockcontrol_n, type1_table[i].n);
-+ W_REG(clockcontrol_sb, type1_table[i].sb);
-+ if (pciclock == 25000000)
-+ W_REG(clockcontrol_pci, type1_table[i].pci25);
-+ else
-+ W_REG(clockcontrol_pci, type1_table[i].pci33);
++ /* Write partition up to end of data area */
++ offset = nvram_mtd->size - erasesize;
++ i = erasesize - NVRAM_SPACE + header->len;
++ ret = MTD_WRITE(nvram_mtd, offset, i, &len, buf);
++ if (ret || len != i) {
++ printk("nvram_commit: write error\n");
++ ret = -EIO;
++ goto done;
++ }
+
-+ /* Reset */
-+ sb_watchdog(sbh, 1);
-+ while (1);
-+ } else if ((pll_type == PLL_TYPE2) || (pll_type == PLL_TYPE4)) {
-+ n4m_table_t *table = (pll_type == PLL_TYPE2) ? type2_table : type4_table;
-+ uint tabsz = (pll_type == PLL_TYPE2) ? ARRAYSIZE(type2_table) : ARRAYSIZE(type4_table);
++ offset = nvram_mtd->size - erasesize;
++ ret = MTD_READ(nvram_mtd, offset, 4, &len, buf);
+
-+ ASSERT(cc);
++ done:
++ up(&nvram_sem);
++ kfree(buf);
++ return ret;
++}
+
-+ /* Store the current clock register values */
-+ orig_m2 = R_REG(&cc->clockcontrol_m2);
-+ orig_mips = R_REG(&cc->clockcontrol_mips);
-+ orig_ratio_parm = 0;
++int
++nvram_getall(char *buf, int count)
++{
++ unsigned long flags;
++ int ret;
+
-+ /* Look up current ratio */
-+ for (i = 0; i < tabsz; i++) {
-+ if ((orig_n == table[i].n) &&
-+ (orig_sb == table[i].sb) &&
-+ (orig_pci == table[i].pci33) &&
-+ (orig_m2 == table[i].m2) &&
-+ (orig_mips == table[i].m3)) {
-+ orig_ratio_parm = table[i].ratio_parm;
-+ break;
-+ }
-+ }
++ spin_lock_irqsave(&nvram_lock, flags);
++ ret = _nvram_getall(buf, count);
++ spin_unlock_irqrestore(&nvram_lock, flags);
+
-+ /* Search for the closest MIPS clock greater or equal to a preferred value */
-+ for (i = 0; i < tabsz; i++) {
-+ ASSERT(table[i].mipsclock ==
-+ sb_clock_rate(pll_type, table[i].n, table[i].m3));
-+ if ((mipsclock <= table[i].mipsclock) &&
-+ ((sbclock == 0) || (sbclock <= table[i].sbclock)))
-+ break;
++ return ret;
++}
++
++EXPORT_SYMBOL(nvram_get);
++EXPORT_SYMBOL(nvram_getall);
++EXPORT_SYMBOL(nvram_set);
++EXPORT_SYMBOL(nvram_unset);
++EXPORT_SYMBOL(nvram_commit);
++
++/* User mode interface below */
++
++static ssize_t
++dev_nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++ char tmp[100], *name = tmp, *value;
++ ssize_t ret;
++ unsigned long off;
++
++ if (count > sizeof(tmp)) {
++ if (!(name = kmalloc(count, GFP_KERNEL)))
++ return -ENOMEM;
++ }
++
++ if (copy_from_user(name, buf, count)) {
++ ret = -EFAULT;
++ goto done;
++ }
++
++ if (*name == '\0') {
++ /* Get all variables */
++ ret = nvram_getall(name, count);
++ if (ret == 0) {
++ if (copy_to_user(buf, name, count)) {
++ ret = -EFAULT;
++ goto done;
++ }
++ ret = count;
+ }
-+ if (i == tabsz) {
-+ ret = FALSE;
++ } else {
++ if (!(value = nvram_get(name))) {
++ ret = 0;
+ goto done;
-+ } else {
-+ ret = TRUE;
+ }
+
-+ /* No PLL change */
-+ if ((orig_n == table[i].n) &&
-+ (orig_sb == table[i].sb) &&
-+ (orig_pci == table[i].pci33) &&
-+ (orig_m2 == table[i].m2) &&
-+ (orig_mips == table[i].m3))
++ /* Provide the offset into mmap() space */
++ off = (unsigned long) value - (unsigned long) nvram_buf;
++
++ if (put_user(off, (unsigned long *) buf)) {
++ ret = -EFAULT;
+ goto done;
++ }
+
-+ /* Set the PLL controls */
-+ W_REG(clockcontrol_n, table[i].n);
-+ W_REG(clockcontrol_sb, table[i].sb);
-+ W_REG(clockcontrol_pci, table[i].pci33);
-+ W_REG(&cc->clockcontrol_m2, table[i].m2);
-+ W_REG(&cc->clockcontrol_mips, table[i].m3);
++ ret = sizeof(unsigned long);
++ }
+
-+ /* No ratio change */
-+ if (orig_ratio_parm == table[i].ratio_parm)
-+ goto end_fill;
++ flush_cache_all();
++
++done:
++ if (name != tmp)
++ kfree(name);
+
-+ new_ratio = table[i].ratio_parm;
++ return ret;
++}
+
-+ icache_probe(&icache_size, &ic_lsize);
++static ssize_t
++dev_nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
++{
++ char tmp[100], *name = tmp, *value;
++ ssize_t ret;
+
-+ /* Preload the code into the cache */
-+ start = ((ulong) &&start_fill) & ~(ic_lsize - 1);
-+ end = ((ulong) &&end_fill + (ic_lsize - 1)) & ~(ic_lsize - 1);
-+ while (start < end) {
-+ cache_unroll(start, Fill_I);
-+ start += ic_lsize;
-+ }
++ if (count > sizeof(tmp)) {
++ if (!(name = kmalloc(count, GFP_KERNEL)))
++ return -ENOMEM;
++ }
+
-+ /* Copy the handler */
-+ start = (ulong) &handler;
-+ end = (ulong) &afterhandler;
-+ dst = KSEG1ADDR(0x180);
-+ for (i = 0; i < (end - start); i += 4)
-+ *((ulong *)(dst + i)) = *((ulong *)(start + i));
-+
-+ /* Preload handler into the cache one line at a time */
-+ for (i = 0; i < (end - start); i += 4)
-+ cache_unroll(dst + i, Fill_I);
++ if (copy_from_user(name, buf, count)) {
++ ret = -EFAULT;
++ goto done;
++ }
+
-+ /* Clear BEV bit */
-+ MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~ST0_BEV);
++ value = name;
++ name = strsep(&value, "=");
++ if (value)
++ ret = nvram_set(name, value) ? : count;
++ else
++ ret = nvram_unset(name) ? : count;
+
-+ /* Enable interrupts */
-+ MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) | (ALLINTS | ST0_IE));
++ done:
++ if (name != tmp)
++ kfree(name);
+
-+ /* Enable MIPS timer interrupt */
-+ if (!(mipsr = sb_setcore(sbh, SB_MIPS, 0)) &&
-+ !(mipsr = sb_setcore(sbh, SB_MIPS33, 0)))
-+ ASSERT(mipsr);
-+ W_REG(&mipsr->intmask, 1);
++ return ret;
++}
+
-+ start_fill:
-+ /* step 1, set clock ratios */
-+ MTC0(C0_BROADCOM, 3, new_ratio);
-+ MTC0(C0_BROADCOM, 1, 8);
++static int
++dev_nvram_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++ if (cmd != NVRAM_MAGIC)
++ return -EINVAL;
++ return nvram_commit();
++}
+
-+ /* step 2: program timer intr */
-+ W_REG(&mipsr->timer, 100);
-+ (void) R_REG(&mipsr->timer);
++static int
++dev_nvram_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ unsigned long offset = virt_to_phys(nvram_buf);
+
-+ /* step 3, switch to async */
-+ sync_mode = MFC0(C0_BROADCOM, 4);
-+ MTC0(C0_BROADCOM, 4, 1 << 22);
++ if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start,
++ vma->vm_page_prot))
++ return -EAGAIN;
+
-+ /* step 4, set cfg active */
-+ MTC0(C0_BROADCOM, 2, 0x9);
++ return 0;
++}
+
++static int
++dev_nvram_open(struct inode *inode, struct file * file)
++{
++ MOD_INC_USE_COUNT;
++ return 0;
++}
+
-+ /* steps 5 & 6 */
-+ __asm__ __volatile__ (
-+ ".set\tmips3\n\t"
-+ "wait\n\t"
-+ ".set\tmips0"
-+ );
++static int
++dev_nvram_release(struct inode *inode, struct file * file)
++{
++ MOD_DEC_USE_COUNT;
++ return 0;
++}
+
-+ /* step 7, clear cfg_active */
-+ MTC0(C0_BROADCOM, 2, 0);
-+
-+ /* Additional Step: set back to orig sync mode */
-+ MTC0(C0_BROADCOM, 4, sync_mode);
++static struct file_operations dev_nvram_fops = {
++ owner: THIS_MODULE,
++ open: dev_nvram_open,
++ release: dev_nvram_release,
++ read: dev_nvram_read,
++ write: dev_nvram_write,
++ ioctl: dev_nvram_ioctl,
++ mmap: dev_nvram_mmap,
++};
+
-+ /* step 8, fake soft reset */
-+ MTC0(C0_BROADCOM, 5, MFC0(C0_BROADCOM, 5) | 4);
++static void
++dev_nvram_exit(void)
++{
++ int order = 0;
++ struct page *page, *end;
+
-+ end_fill:
-+ /* step 9 set watchdog timer */
-+ sb_watchdog(sbh, 20);
-+ (void) R_REG(&cc->chipid);
++ if (nvram_handle)
++ devfs_unregister(nvram_handle);
+
-+ /* step 11 */
-+ __asm__ __volatile__ (
-+ ".set\tmips3\n\t"
-+ "sync\n\t"
-+ "wait\n\t"
-+ ".set\tmips0"
-+ );
-+ while (1);
-+ }
++ if (nvram_major >= 0)
++ devfs_unregister_chrdev(nvram_major, "nvram");
+
-+done:
-+ /* switch back to previous core */
-+ sb_setcoreidx(sbh, idx);
++ if (nvram_mtd)
++ put_mtd_device(nvram_mtd);
+
-+ return ret;
-+}
++ while ((PAGE_SIZE << order) < NVRAM_SPACE)
++ order++;
++ end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
++ for (page = virt_to_page(nvram_buf); page <= end; page++)
++ mem_map_unreserve(page);
+
++ _nvram_exit();
++}
+
-+/* returns the ncdl value to be programmed into sdram_ncdl for calibration */
-+uint32
-+sb_memc_get_ncdl(void *sbh)
++static int __init
++dev_nvram_init(void)
+{
-+ sbmemcregs_t *memc;
-+ uint32 ret = 0;
-+ uint32 config, rd, wr, misc, dqsg, cd, sm, sd;
-+ uint idx, rev;
++ int order = 0, ret = 0;
++ struct page *page, *end;
++ unsigned int i;
+
-+ idx = sb_coreidx(sbh);
++ /* Allocate and reserve memory to mmap() */
++ while ((PAGE_SIZE << order) < NVRAM_SPACE)
++ order++;
++ end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
++ for (page = virt_to_page(nvram_buf); page <= end; page++)
++ mem_map_reserve(page);
++
++#ifdef CONFIG_MTD
++ /* Find associated MTD device */
++ for (i = 0; i < MAX_MTD_DEVICES; i++) {
++ nvram_mtd = get_mtd_device(NULL, i);
++ if (nvram_mtd) {
++ if (!strcmp(nvram_mtd->name, "nvram") &&
++ nvram_mtd->size >= NVRAM_SPACE)
++ break;
++ put_mtd_device(nvram_mtd);
++ }
++ }
++ if (i >= MAX_MTD_DEVICES)
++ nvram_mtd = NULL;
++#endif
+
-+ memc = (sbmemcregs_t *)sb_setcore(sbh, SB_MEMC, 0);
-+ if (memc == 0)
-+ goto out;
++ /* Initialize hash table lock */
++ spin_lock_init(&nvram_lock);
+
-+ rev = sb_corerev(sbh);
++ /* Initialize commit semaphore */
++ init_MUTEX(&nvram_sem);
+
-+ config = R_REG(&memc->config);
-+ wr = R_REG(&memc->wrncdlcor);
-+ rd = R_REG(&memc->rdncdlcor);
-+ misc = R_REG(&memc->miscdlyctl);
-+ dqsg = R_REG(&memc->dqsgatencdl);
++ /* Register char device */
++ if ((nvram_major = devfs_register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) {
++ ret = nvram_major;
++ goto err;
++ }
+
-+ rd &= MEMC_RDNCDLCOR_RD_MASK;
-+ wr &= MEMC_WRNCDLCOR_WR_MASK;
-+ dqsg &= MEMC_DQSGATENCDL_G_MASK;
++ /* Initialize hash table */
++ _nvram_init();
+
-+ if (config & MEMC_CONFIG_DDR) {
-+ ret = (wr << 16) | (rd << 8) | dqsg;
-+ } else {
-+ if (rev > 0)
-+ cd = rd;
-+ else
-+ cd = (rd == MEMC_CD_THRESHOLD) ? rd : (wr + MEMC_CD_THRESHOLD);
-+ sm = (misc & MEMC_MISC_SM_MASK) >> MEMC_MISC_SM_SHIFT;
-+ sd = (misc & MEMC_MISC_SD_MASK) >> MEMC_MISC_SD_SHIFT;
-+ ret = (sm << 16) | (sd << 8) | cd;
++ /* Create /dev/nvram handle */
++ nvram_handle = devfs_register(NULL, "nvram", DEVFS_FL_NONE, nvram_major, 0,
++ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &dev_nvram_fops, NULL);
++
++ /* Set the SDRAM NCDL value into NVRAM if not already done */
++ if (getintvar(NULL, "sdram_ncdl") == 0) {
++ unsigned int ncdl;
++ char buf[] = "0x00000000";
++
++ if ((ncdl = sb_memc_get_ncdl(sbh))) {
++ sprintf(buf, "0x%08x", ncdl);
++ nvram_set("sdram_ncdl", buf);
++ nvram_commit();
++ }
+ }
+
-+out:
-+ /* switch back to previous core */
-+ sb_setcoreidx(sbh, idx);
++ return 0;
+
++ err:
++ dev_nvram_exit();
+ return ret;
+}
-diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/sbpci.c
---- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/sbpci.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/sbpci.c 2005-08-28 11:12:20.479851704 +0200
-@@ -0,0 +1,530 @@
++
++module_init(dev_nvram_init);
++module_exit(dev_nvram_exit);
+diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/sbmips.c
+--- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/sbmips.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/sbmips.c 2005-11-07 01:12:51.819809500 +0100
+@@ -0,0 +1,950 @@
+/*
-+ * Low-Level PCI and SB support for BCM47xx
++ * BCM47XX Sonics SiliconBackplane MIPS core routines
+ *
+ * Copyright 2001-2003, Broadcom Corporation
+ * All Rights Reserved.
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
-+ * $Id: sbpci.c,v 1.2 2005/02/28 13:34:25 jolt Exp $
++ * $Id: sbmips.c,v 1.1 2005/02/28 13:33:32 jolt Exp $
+ */
+
+#include <typedefs.h>
-+#include <pcicfg.h>
-+#include <bcmdevs.h>
-+#include <sbconfig.h>
-+#include <sbpci.h>
+#include <osl.h>
-+#include <bcmendian.h>
-+#include <bcmutils.h>
+#include <sbutils.h>
++#include <bcmdevs.h>
+#include <bcmnvram.h>
++#include <bcmutils.h>
+#include <hndmips.h>
-+
-+/* Can free sbpci_init() memory after boot */
-+#ifndef linux
-+#define __init
-+#endif
-+
-+/* Emulated configuration space */
-+static pci_config_regs sb_config_regs[SB_MAXCORES];
-+
-+/* Banned cores */
-+static uint16 pci_ban[32] = { 0 };
-+static uint pci_banned = 0;
-+
-+/* CardBus mode */
-+static bool cardbus = FALSE;
++#include <sbconfig.h>
++#include <sbextif.h>
++#include <sbchipc.h>
++#include <sbmemc.h>
+
+/*
-+ * Functions for accessing external PCI configuration space
++ * Memory segments (32bit kernel mode addresses)
+ */
++#undef KUSEG
++#undef KSEG0
++#undef KSEG1
++#undef KSEG2
++#undef KSEG3
++#define KUSEG 0x00000000
++#define KSEG0 0x80000000
++#define KSEG1 0xa0000000
++#define KSEG2 0xc0000000
++#define KSEG3 0xe0000000
+
-+/* Assume one-hot slot wiring */
-+#define PCI_SLOT_MAX 16
-+
-+static uint32
-+config_cmd(void *sbh, uint bus, uint dev, uint func, uint off)
-+{
-+ uint coreidx;
-+ sbpciregs_t *regs;
-+ uint32 addr = 0;
++/*
++ * Map an address to a certain kernel segment
++ */
++#undef KSEG0ADDR
++#undef KSEG1ADDR
++#undef KSEG2ADDR
++#undef KSEG3ADDR
++#define KSEG0ADDR(a) (((a) & 0x1fffffff) | KSEG0)
++#define KSEG1ADDR(a) (((a) & 0x1fffffff) | KSEG1)
++#define KSEG2ADDR(a) (((a) & 0x1fffffff) | KSEG2)
++#define KSEG3ADDR(a) (((a) & 0x1fffffff) | KSEG3)
+
-+ /* CardBusMode supports only one device */
-+ if (cardbus && dev > 1)
-+ return 0;
++/*
++ * The following macros are especially useful for __asm__
++ * inline assembler.
++ */
++#ifndef __STR
++#define __STR(x) #x
++#endif
++#ifndef STR
++#define STR(x) __STR(x)
++#endif
+
-+ coreidx = sb_coreidx(sbh);
-+ regs = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0);
++/* *********************************************************************
++ * CP0 Registers
++ ********************************************************************* */
+
-+ /* Type 0 transaction */
-+ if (bus == 1) {
-+ /* Skip unwired slots */
-+ if (dev < PCI_SLOT_MAX) {
-+ /* Slide the PCI window to the appropriate slot */
-+ W_REG(®s->sbtopci1, SBTOPCI_CFG0 | ((1 << (dev + 16)) & SBTOPCI1_MASK));
-+ addr = SB_PCI_CFG | ((1 << (dev + 16)) & ~SBTOPCI1_MASK) |
-+ (func << 8) | (off & ~3);
-+ }
-+ }
++#define C0_INX 0 /* CP0: TLB Index */
++#define C0_RAND 1 /* CP0: TLB Random */
++#define C0_TLBLO0 2 /* CP0: TLB EntryLo0 */
++#define C0_TLBLO C0_TLBLO0 /* CP0: TLB EntryLo0 */
++#define C0_TLBLO1 3 /* CP0: TLB EntryLo1 */
++#define C0_CTEXT 4 /* CP0: Context */
++#define C0_PGMASK 5 /* CP0: TLB PageMask */
++#define C0_WIRED 6 /* CP0: TLB Wired */
++#define C0_BADVADDR 8 /* CP0: Bad Virtual Address */
++#define C0_COUNT 9 /* CP0: Count */
++#define C0_TLBHI 10 /* CP0: TLB EntryHi */
++#define C0_COMPARE 11 /* CP0: Compare */
++#define C0_SR 12 /* CP0: Processor Status */
++#define C0_STATUS C0_SR /* CP0: Processor Status */
++#define C0_CAUSE 13 /* CP0: Exception Cause */
++#define C0_EPC 14 /* CP0: Exception PC */
++#define C0_PRID 15 /* CP0: Processor Revision Indentifier */
++#define C0_CONFIG 16 /* CP0: Config */
++#define C0_LLADDR 17 /* CP0: LLAddr */
++#define C0_WATCHLO 18 /* CP0: WatchpointLo */
++#define C0_WATCHHI 19 /* CP0: WatchpointHi */
++#define C0_XCTEXT 20 /* CP0: XContext */
++#define C0_DIAGNOSTIC 22 /* CP0: Diagnostic */
++#define C0_BROADCOM C0_DIAGNOSTIC /* CP0: Broadcom Register */
++#define C0_ECC 26 /* CP0: ECC */
++#define C0_CACHEERR 27 /* CP0: CacheErr */
++#define C0_TAGLO 28 /* CP0: TagLo */
++#define C0_TAGHI 29 /* CP0: TagHi */
++#define C0_ERREPC 30 /* CP0: ErrorEPC */
+
-+ /* Type 1 transaction */
-+ else {
-+ W_REG(®s->sbtopci1, SBTOPCI_CFG1);
-+ addr = SB_PCI_CFG | (bus << 16) | (dev << 11) | (func << 8) | (off & ~3);
-+ }
++/*
++ * Macros to access the system control coprocessor
++ */
+
-+ sb_setcoreidx(sbh, coreidx);
++#define MFC0(source, sel) \
++({ \
++ int __res; \
++ __asm__ __volatile__( \
++ ".set\tnoreorder\n\t" \
++ ".set\tnoat\n\t" \
++ ".word\t"STR(0x40010000 | ((source)<<11) | (sel))"\n\t" \
++ "move\t%0,$1\n\t" \
++ ".set\tat\n\t" \
++ ".set\treorder" \
++ :"=r" (__res) \
++ : \
++ :"$1"); \
++ __res; \
++})
+
-+ return addr;
-+}
++#define MTC0(source, sel, value) \
++do { \
++ __asm__ __volatile__( \
++ ".set\tnoreorder\n\t" \
++ ".set\tnoat\n\t" \
++ "move\t$1,%z0\n\t" \
++ ".word\t"STR(0x40810000 | ((source)<<11) | (sel))"\n\t" \
++ ".set\tat\n\t" \
++ ".set\treorder" \
++ : \
++ :"Jr" (value) \
++ :"$1"); \
++} while (0)
+
-+static int
-+extpci_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
-+{
-+ uint32 addr, *reg = NULL, val;
-+ int ret = 0;
++/*
++ * R4x00 interrupt enable / cause bits
++ */
++#undef IE_SW0
++#undef IE_SW1
++#undef IE_IRQ0
++#undef IE_IRQ1
++#undef IE_IRQ2
++#undef IE_IRQ3
++#undef IE_IRQ4
++#undef IE_IRQ5
++#define IE_SW0 (1<< 8)
++#define IE_SW1 (1<< 9)
++#define IE_IRQ0 (1<<10)
++#define IE_IRQ1 (1<<11)
++#define IE_IRQ2 (1<<12)
++#define IE_IRQ3 (1<<13)
++#define IE_IRQ4 (1<<14)
++#define IE_IRQ5 (1<<15)
+
-+ if (!(addr = config_cmd(sbh, bus, dev, func, off)) ||
-+ !(reg = (uint32 *) REG_MAP(addr, len)) ||
-+ BUSPROBE(val, reg))
-+ val = 0xffffffff;
++/*
++ * Bitfields in the R4xx0 cp0 status register
++ */
++#define ST0_IE 0x00000001
++#define ST0_EXL 0x00000002
++#define ST0_ERL 0x00000004
++#define ST0_KSU 0x00000018
++# define KSU_USER 0x00000010
++# define KSU_SUPERVISOR 0x00000008
++# define KSU_KERNEL 0x00000000
++#define ST0_UX 0x00000020
++#define ST0_SX 0x00000040
++#define ST0_KX 0x00000080
++#define ST0_DE 0x00010000
++#define ST0_CE 0x00020000
+
-+ val >>= 8 * (off & 3);
-+ if (len == 4)
-+ *((uint32 *) buf) = val;
-+ else if (len == 2)
-+ *((uint16 *) buf) = (uint16) val;
-+ else if (len == 1)
-+ *((uint8 *) buf) = (uint8) val;
-+ else
-+ ret = -1;
++/*
++ * Status register bits available in all MIPS CPUs.
++ */
++#define ST0_IM 0x0000ff00
++#define ST0_CH 0x00040000
++#define ST0_SR 0x00100000
++#define ST0_TS 0x00200000
++#define ST0_BEV 0x00400000
++#define ST0_RE 0x02000000
++#define ST0_FR 0x04000000
++#define ST0_CU 0xf0000000
++#define ST0_CU0 0x10000000
++#define ST0_CU1 0x20000000
++#define ST0_CU2 0x40000000
++#define ST0_CU3 0x80000000
++#define ST0_XX 0x80000000 /* MIPS IV naming */
+
-+ if (reg)
-+ REG_UNMAP(reg);
++/*
++ * Cache Operations
++ */
+
-+ return ret;
++#ifndef Fill_I
++#define Fill_I 0x14
++#endif
++
++#define cache_unroll(base,op) \
++ __asm__ __volatile__(" \
++ .set noreorder; \
++ .set mips3; \
++ cache %1, (%0); \
++ .set mips0; \
++ .set reorder" \
++ : \
++ : "r" (base), \
++ "i" (op));
++
++/*
++ * These are the UART port assignments, expressed as offsets from the base
++ * register. These assignments should hold for any serial port based on
++ * a 8250, 16450, or 16550(A).
++ */
++
++#define UART_MCR 4 /* Out: Modem Control Register */
++#define UART_MSR 6 /* In: Modem Status Register */
++#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
++
++/*
++ * Returns TRUE if an external UART exists at the given base
++ * register.
++ */
++static bool
++serial_exists(uint8 *regs)
++{
++ uint8 save_mcr, status1;
++
++ save_mcr = R_REG(®s[UART_MCR]);
++ W_REG(®s[UART_MCR], UART_MCR_LOOP | 0x0a);
++ status1 = R_REG(®s[UART_MSR]) & 0xf0;
++ W_REG(®s[UART_MCR], save_mcr);
++
++ return (status1 == 0x90);
+}
+
-+static int
-+extpci_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++/*
++ * Initializes UART access. The callback function will be called once
++ * per found UART.
++*/
++void
++sb_serial_init(void *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift))
+{
-+ uint32 addr, *reg = NULL, val;
-+ int ret = 0;
++ void *regs;
++ ulong base;
++ uint irq;
++ int i, n;
+
-+ if (!(addr = config_cmd(sbh, bus, dev, func, off)) ||
-+ !(reg = (uint32 *) REG_MAP(addr, len)) ||
-+ BUSPROBE(val, reg))
-+ goto done;
++ if ((regs = sb_setcore(sbh, SB_EXTIF, 0))) {
++ extifregs_t *eir = (extifregs_t *) regs;
++ sbconfig_t *sb;
+
-+ if (len == 4)
-+ val = *((uint32 *) buf);
-+ else if (len == 2) {
-+ val &= ~(0xffff << (8 * (off & 3)));
-+ val |= *((uint16 *) buf) << (8 * (off & 3));
-+ } else if (len == 1) {
-+ val &= ~(0xff << (8 * (off & 3)));
-+ val |= *((uint8 *) buf) << (8 * (off & 3));
-+ } else
-+ ret = -1;
++ /* Determine external UART register base */
++ sb = (sbconfig_t *)((ulong) eir + SBCONFIGOFF);
++ base = EXTIF_CFGIF_BASE(sb_base(R_REG(&sb->sbadmatch1)));
+
-+ W_REG(reg, val);
++ /* Determine IRQ */
++ irq = sb_irq(sbh);
+
-+ done:
-+ if (reg)
-+ REG_UNMAP(reg);
++ /* Disable GPIO interrupt initially */
++ W_REG(&eir->gpiointpolarity, 0);
++ W_REG(&eir->gpiointmask, 0);
+
-+ return ret;
-+}
++ /* Search for external UARTs */
++ n = 2;
++ for (i = 0; i < 2; i++) {
++ regs = (void *) REG_MAP(base + (i * 8), 8);
++ if (serial_exists(regs)) {
++ /* Set GPIO 1 to be the external UART IRQ */
++ W_REG(&eir->gpiointmask, 2);
++ if (add)
++ add(regs, irq, 13500000, 0);
++ }
++ }
+
-+/*
-+ * Functions for accessing translated SB configuration space
-+ */
++ /* Add internal UART if enabled */
++ if (R_REG(&eir->corecontrol) & CC_UE)
++ if (add)
++ add((void *) &eir->uartdata, irq, sb_clock(sbh), 2);
++ } else if ((regs = sb_setcore(sbh, SB_CC, 0))) {
++ chipcregs_t *cc = (chipcregs_t *) regs;
++ uint32 rev, cap, pll, baud_base, div;
+
-+static int
-+sb_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
-+{
-+ pci_config_regs *cfg;
++ /* Determine core revision and capabilities */
++ rev = sb_corerev(sbh);
++ cap = R_REG(&cc->capabilities);
++ pll = cap & CAP_PLL_MASK;
+
-+ if (dev >= SB_MAXCORES || (off + len) > sizeof(pci_config_regs))
-+ return -1;
-+ cfg = &sb_config_regs[dev];
++ /* Determine IRQ */
++ irq = sb_irq(sbh);
+
-+ ASSERT(ISALIGNED(off, len));
-+ ASSERT(ISALIGNED(buf, len));
++ if (pll == PLL_TYPE1) {
++ /* PLL clock */
++ baud_base = sb_clock_rate(pll,
++ R_REG(&cc->clockcontrol_n),
++ R_REG(&cc->clockcontrol_m2));
++ div = 1;
++ } else if (rev >= 3) {
++ /* Internal backplane clock */
++ baud_base = sb_clock_rate(pll,
++ R_REG(&cc->clockcontrol_n),
++ R_REG(&cc->clockcontrol_sb));
++ div = 2; /* Minimum divisor */
++ W_REG(&cc->uart_clkdiv, div);
++ } else {
++ /* Fixed internal backplane clock */
++ baud_base = 88000000;
++ div = 48;
++ }
+
-+ if (len == 4)
-+ *((uint32 *) buf) = ltoh32(*((uint32 *)((ulong) cfg + off)));
-+ else if (len == 2)
-+ *((uint16 *) buf) = ltoh16(*((uint16 *)((ulong) cfg + off)));
-+ else if (len == 1)
-+ *((uint8 *) buf) = *((uint8 *)((ulong) cfg + off));
-+ else
-+ return -1;
++ /* Clock source depends on strapping if UartClkOverride is unset */
++ if ((rev > 0) && ((R_REG(&cc->corecontrol) & CC_UARTCLKO) == 0)) {
++ if ((cap & CAP_UCLKSEL) == CAP_UINTCLK) {
++ /* Internal divided backplane clock */
++ baud_base /= div;
++ } else {
++ /* Assume external clock of 1.8432 MHz */
++ baud_base = 1843200;
++ }
++ }
+
-+ return 0;
++ /* Add internal UARTs */
++ n = cap & CAP_UARTS_MASK;
++ for (i = 0; i < n; i++) {
++ /* Register offset changed after revision 0 */
++ if (rev)
++ regs = (void *)((ulong) &cc->uart0data + (i * 256));
++ else
++ regs = (void *)((ulong) &cc->uart0data + (i * 8));
++
++ if (add)
++ add(regs, irq, baud_base, 0);
++ }
++ }
+}
+
-+static int
-+sb_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++/* Returns the SB interrupt flag of the current core. */
++uint32
++sb_flag(void *sbh)
+{
-+ uint coreidx, n;
+ void *regs;
+ sbconfig_t *sb;
-+ pci_config_regs *cfg;
+
-+ if (dev >= SB_MAXCORES || (off + len) > sizeof(pci_config_regs))
-+ return -1;
-+ cfg = &sb_config_regs[dev];
++ regs = sb_coreregs(sbh);
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
+
-+ ASSERT(ISALIGNED(off, len));
-+ ASSERT(ISALIGNED(buf, len));
++ return (R_REG(&sb->sbtpsflag) & SBTPS_NUM0_MASK);
++}
+
-+ /* Emulate BAR sizing */
-+ if (off >= OFFSETOF(pci_config_regs, base[0]) && off <= OFFSETOF(pci_config_regs, base[3]) &&
-+ len == 4 && *((uint32 *) buf) == ~0) {
-+ coreidx = sb_coreidx(sbh);
-+ if ((regs = sb_setcoreidx(sbh, dev))) {
-+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
-+ /* Highest numbered address match register */
-+ n = (R_REG(&sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT;
-+ if (off == OFFSETOF(pci_config_regs, base[0]))
-+ cfg->base[0] = ~(sb_size(R_REG(&sb->sbadmatch0)) - 1);
-+ /*else if (off == OFFSETOF(pci_config_regs, base[1]) && n >= 1)
-+ cfg->base[1] = ~(sb_size(R_REG(&sb->sbadmatch1)) - 1);
-+ else if (off == OFFSETOF(pci_config_regs, base[2]) && n >= 2)
-+ cfg->base[2] = ~(sb_size(R_REG(&sb->sbadmatch2)) - 1);
-+ else if (off == OFFSETOF(pci_config_regs, base[3]) && n >= 3)
-+ cfg->base[3] = ~(sb_size(R_REG(&sb->sbadmatch3)) - 1);*/
++static const uint32 sbips_int_mask[] = {
++ 0,
++ SBIPS_INT1_MASK,
++ SBIPS_INT2_MASK,
++ SBIPS_INT3_MASK,
++ SBIPS_INT4_MASK
++};
++
++static const uint32 sbips_int_shift[] = {
++ 0,
++ 0,
++ SBIPS_INT2_SHIFT,
++ SBIPS_INT3_SHIFT,
++ SBIPS_INT4_SHIFT
++};
++
++/*
++ * Returns the MIPS IRQ assignment of the current core. If unassigned,
++ * 0 is returned.
++ */
++uint
++sb_irq(void *sbh)
++{
++ uint idx;
++ void *regs;
++ sbconfig_t *sb;
++ uint32 flag, sbipsflag;
++ uint irq = 0;
++
++ flag = sb_flag(sbh);
++
++ idx = sb_coreidx(sbh);
++
++ if ((regs = sb_setcore(sbh, SB_MIPS, 0)) ||
++ (regs = sb_setcore(sbh, SB_MIPS33, 0))) {
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ /* sbipsflag specifies which core is routed to interrupts 1 to 4 */
++ sbipsflag = R_REG(&sb->sbipsflag);
++ for (irq = 1; irq <= 4; irq++) {
++ if (((sbipsflag & sbips_int_mask[irq]) >> sbips_int_shift[irq]) == flag)
++ break;
+ }
-+ sb_setcoreidx(sbh, coreidx);
-+ return 0;
++ if (irq == 5)
++ irq = 0;
+ }
+
-+ if (len == 4)
-+ *((uint32 *)((ulong) cfg + off)) = htol32(*((uint32 *) buf));
-+ else if (len == 2)
-+ *((uint16 *)((ulong) cfg + off)) = htol16(*((uint16 *) buf));
-+ else if (len == 1)
-+ *((uint8 *)((ulong) cfg + off)) = *((uint8 *) buf);
-+ else
-+ return -1;
++ sb_setcoreidx(sbh, idx);
+
-+ return 0;
++ return irq;
+}
+
-+int
-+sbpci_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++/* Clears the specified MIPS IRQ. */
++static void
++sb_clearirq(void *sbh, uint irq)
+{
-+ if (bus == 0)
-+ return sb_read_config(sbh, bus, dev, func, off, buf, len);
-+ else
-+ return extpci_read_config(sbh, bus, dev, func, off, buf, len);
-+}
++ void *regs;
++ sbconfig_t *sb;
+
-+int
-+sbpci_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
-+{
-+ if (bus == 0)
-+ return sb_write_config(sbh, bus, dev, func, off, buf, len);
-+ else
-+ return extpci_write_config(sbh, bus, dev, func, off, buf, len);
-+}
++ if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
++ !(regs = sb_setcore(sbh, SB_MIPS33, 0)))
++ ASSERT(regs);
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
+
-+void
-+sbpci_ban(uint16 core)
-+{
-+ if (pci_banned < ARRAYSIZE(pci_ban))
-+ pci_ban[pci_banned++] = core;
++ if (irq == 0)
++ W_REG(&sb->sbintvec, 0);
++ else
++ OR_REG(&sb->sbipsflag, sbips_int_mask[irq]);
+}
+
-+int __init
-+sbpci_init(void *sbh)
++/*
++ * Assigns the specified MIPS IRQ to the specified core. Shared MIPS
++ * IRQ 0 may be assigned more than once.
++ */
++static void
++sb_setirq(void *sbh, uint irq, uint coreid, uint coreunit)
+{
-+ uint chip, chiprev, chippkg, coreidx, host, i;
-+ sbpciregs_t *pci;
-+ sbconfig_t *sb;
-+ pci_config_regs *cfg;
+ void *regs;
-+ char varname[8];
-+ uint wlidx = 0;
-+ uint16 vendor, core;
-+ uint8 class, subclass, progif;
-+ uint32 val;
-+ uint32 sbips_int_mask[] = { 0, SBIPS_INT1_MASK, SBIPS_INT2_MASK, SBIPS_INT3_MASK, SBIPS_INT4_MASK };
-+ uint32 sbips_int_shift[] = { 0, 0, SBIPS_INT2_SHIFT, SBIPS_INT3_SHIFT, SBIPS_INT4_SHIFT };
++ sbconfig_t *sb;
++ uint32 flag;
+
-+ chip = sb_chip(sbh);
-+ chiprev = sb_chiprev(sbh);
-+ chippkg = sb_chippkg(sbh);
-+ coreidx = sb_coreidx(sbh);
++ regs = sb_setcore(sbh, coreid, coreunit);
++ ASSERT(regs);
++ flag = sb_flag(sbh);
+
-+ if (!(pci = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0)))
-+ return -1;
-+ sb_core_reset(sbh, 0);
++ if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
++ !(regs = sb_setcore(sbh, SB_MIPS33, 0)))
++ ASSERT(regs);
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
+
-+ if (((chip == BCM4310_DEVICE_ID) && (chiprev == 0)) ||
-+ ((chip == BCM4712_DEVICE_ID) && (chippkg == BCM4712SMALL_PKG_ID)))
-+ host = 0;
-+ else
-+ host = !BUSPROBE(val, &pci->control);
++ if (irq == 0)
++ OR_REG(&sb->sbintvec, 1 << flag);
++ else {
++ flag <<= sbips_int_shift[irq];
++ ASSERT(!(flag & ~sbips_int_mask[irq]));
++ flag |= R_REG(&sb->sbipsflag) & ~sbips_int_mask[irq];
++ W_REG(&sb->sbipsflag, flag);
++ }
++}
+
-+ if (!host) {
-+ /* Disable PCI interrupts in client mode */
-+ sb = (sbconfig_t *)((ulong) pci + SBCONFIGOFF);
-+ W_REG(&sb->sbintvec, 0);
++/*
++ * Initializes clocks and interrupts. SB and NVRAM access must be
++ * initialized prior to calling.
++ */
++void
++sb_mips_init(void *sbh)
++{
++ ulong hz, ns, tmp;
++ extifregs_t *eir;
++ chipcregs_t *cc;
++ char *value;
++ uint irq;
+
-+ /* Disable the PCI bridge in client mode */
-+ sbpci_ban(SB_PCI);
-+ printf("PCI: Disabled\n");
-+ } else {
-+ /* Reset the external PCI bus and enable the clock */
-+ W_REG(&pci->control, 0x5); /* enable the tristate drivers */
-+ W_REG(&pci->control, 0xd); /* enable the PCI clock */
-+ OSL_DELAY(100); /* delay 100 us */
-+ W_REG(&pci->control, 0xf); /* deassert PCI reset */
-+ W_REG(&pci->arbcontrol, PCI_INT_ARB); /* use internal arbiter */
-+ OSL_DELAY(1); /* delay 1 us */
++ /* Figure out current SB clock speed */
++ if ((hz = sb_clock(sbh)) == 0)
++ hz = 100000000;
++ ns = 1000000000 / hz;
+
-+ /* Enable CardBusMode */
-+ cardbus = nvram_match("cardbus", "1");
-+ if (cardbus) {
-+ printf("PCI: Enabling CardBus\n");
-+ /* GPIO 1 resets the CardBus device on bcm94710ap */
-+ sb_gpioout(sbh, 1, 1);
-+ sb_gpioouten(sbh, 1, 1);
-+ W_REG(&pci->sprom[0], R_REG(&pci->sprom[0]) | 0x400);
-+ }
++ /* Setup external interface timing */
++ if ((eir = sb_setcore(sbh, SB_EXTIF, 0))) {
++ /* Initialize extif so we can get to the LEDs and external UART */
++ W_REG(&eir->prog_config, CF_EN);
+
-+ /* 64 MB I/O access window */
-+ W_REG(&pci->sbtopci0, SBTOPCI_IO);
-+ /* 64 MB configuration access window */
-+ W_REG(&pci->sbtopci1, SBTOPCI_CFG0);
-+ /* 1 GB memory access window */
-+ W_REG(&pci->sbtopci2, SBTOPCI_MEM | SB_PCI_DMA);
++ /* Set timing for the flash */
++ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
++ tmp = tmp | (CEIL(40, ns) << FW_W1_SHIFT); /* W1 = 40nS */
++ tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
++ W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
+
-+ /* Enable PCI bridge BAR0 prefetch and burst */
-+ val = 6;
-+ sbpci_write_config(sbh, 1, 0, 0, PCI_CFG_CMD, &val, sizeof(val));
++ /* Set programmable interface timing for external uart */
++ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
++ tmp = tmp | (CEIL(20, ns) << FW_W2_SHIFT); /* W2 = 20nS */
++ tmp = tmp | (CEIL(100, ns) << FW_W1_SHIFT); /* W1 = 100nS */
++ tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
++ W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
++ } else if ((cc = sb_setcore(sbh, SB_CC, 0))) {
++ /* Set timing for the flash */
++ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
++ tmp |= CEIL(10, ns) << FW_W1_SHIFT; /* W1 = 10nS */
++ tmp |= CEIL(120, ns); /* W0 = 120nS */
++ W_REG(&cc->parallelflashwaitcnt, tmp);
+
-+ /* Enable PCI interrupts */
-+ W_REG(&pci->intmask, PCI_INTA);
++ W_REG(&cc->cs01memwaitcnt, tmp);
+ }
+
-+ /* Scan the SB bus */
-+ bzero(sb_config_regs, sizeof(sb_config_regs));
-+ for (cfg = sb_config_regs; cfg < &sb_config_regs[SB_MAXCORES]; cfg++) {
-+ cfg->vendor = 0xffff;
-+ if (!(regs = sb_setcoreidx(sbh, cfg - sb_config_regs)))
-+ continue;
-+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
-+
-+ /* Read ID register and parse vendor and core */
-+ val = R_REG(&sb->sbidhigh);
-+ vendor = (val & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT;
-+ core = (val & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
-+ progif = 0;
-+
-+ /* Check if this core is banned */
-+ for (i = 0; i < pci_banned; i++)
-+ if (core == pci_ban[i])
-+ break;
-+ if (i < pci_banned)
-+ continue;
-+
-+ /* Known vendor translations */
-+ switch (vendor) {
-+ case SB_VEND_BCM:
-+ vendor = VENDOR_BROADCOM;
++ /* Chip specific initialization */
++ switch (sb_chip(sbh)) {
++ case BCM4710_DEVICE_ID:
++ /* Clear interrupt map */
++ for (irq = 0; irq <= 4; irq++)
++ sb_clearirq(sbh, irq);
++ sb_setirq(sbh, 0, SB_CODEC, 0);
++ sb_setirq(sbh, 0, SB_EXTIF, 0);
++ sb_setirq(sbh, 2, SB_ENET, 1);
++ sb_setirq(sbh, 3, SB_ILINE20, 0);
++ sb_setirq(sbh, 4, SB_PCI, 0);
++ ASSERT(eir);
++ value = nvram_get("et0phyaddr");
++ if (value && !strcmp(value, "31")) {
++ /* Enable internal UART */
++ W_REG(&eir->corecontrol, CC_UE);
++ /* Give USB its own interrupt */
++ sb_setirq(sbh, 1, SB_USB, 0);
++ } else {
++ /* Disable internal UART */
++ W_REG(&eir->corecontrol, 0);
++ /* Give Ethernet its own interrupt */
++ sb_setirq(sbh, 1, SB_ENET, 0);
++ sb_setirq(sbh, 0, SB_USB, 0);
++ }
++ break;
++ case BCM4310_DEVICE_ID:
++ MTC0(C0_BROADCOM, 0, MFC0(C0_BROADCOM, 0) & ~(1 << 22));
++ break;
++ }
++}
++
++uint32
++sb_mips_clock(void *sbh)
++{
++ extifregs_t *eir;
++ chipcregs_t *cc;
++ uint32 n, m;
++ uint idx;
++ uint32 pll_type, rate = 0;
++
++ /* get index of the current core */
++ idx = sb_coreidx(sbh);
++ pll_type = PLL_TYPE1;
++
++ /* switch to extif or chipc core */
++ if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
++ n = R_REG(&eir->clockcontrol_n);
++ m = R_REG(&eir->clockcontrol_sb);
++ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
++ pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
++ n = R_REG(&cc->clockcontrol_n);
++ if ((pll_type == PLL_TYPE2) || (pll_type == PLL_TYPE4))
++ m = R_REG(&cc->clockcontrol_mips);
++ else if (pll_type == PLL_TYPE3) {
++ rate = 200000000;
++ goto out;
++ } else
++ m = R_REG(&cc->clockcontrol_sb);
++ } else
++ goto out;
++
++ /* calculate rate */
++ rate = sb_clock_rate(pll_type, n, m);
++
++out:
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ return rate;
++}
++
++static void
++icache_probe(int *size, int *lsize)
++{
++ uint32 config1;
++ uint sets, ways;
++
++ config1 = MFC0(C0_CONFIG, 1);
++
++ /* Instruction Cache Size = Associativity * Line Size * Sets Per Way */
++ if ((*lsize = ((config1 >> 19) & 7)))
++ *lsize = 2 << *lsize;
++ sets = 64 << ((config1 >> 22) & 7);
++ ways = 1 + ((config1 >> 16) & 7);
++ *size = *lsize * sets * ways;
++}
++
++#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
++
++static void
++handler(void)
++{
++ /* Step 11 */
++ __asm__ (
++ ".set\tmips32\n\t"
++ "ssnop\n\t"
++ "ssnop\n\t"
++ /* Disable interrupts */
++ /* MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~(ALLINTS | STO_IE)); */
++ "mfc0 $15, $12\n\t"
++ "and $15, $15, -31746\n\t"
++ "mtc0 $15, $12\n\t"
++ "eret\n\t"
++ "nop\n\t"
++ "nop\n\t"
++ ".set\tmips0"
++ );
++}
++
++/* The following MUST come right after handler() */
++static void
++afterhandler(void)
++{
++}
++
++/*
++ * Set the MIPS, backplane and PCI clocks as closely as possible.
++ */
++bool
++sb_mips_setclock(void *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock)
++{
++ extifregs_t *eir = NULL;
++ chipcregs_t *cc = NULL;
++ mipsregs_t *mipsr = NULL;
++ volatile uint32 *clockcontrol_n, *clockcontrol_sb, *clockcontrol_pci;
++ uint32 orig_n, orig_sb, orig_pci, orig_m2, orig_mips, orig_ratio_parm, new_ratio;
++ uint32 pll_type, sync_mode;
++ uint idx, i;
++ struct {
++ uint32 mipsclock;
++ uint16 n;
++ uint32 sb;
++ uint32 pci33;
++ uint32 pci25;
++ } type1_table[] = {
++ { 96000000, 0x0303, 0x04020011, 0x11030011, 0x11050011 }, /* 96.000 32.000 24.000 */
++ { 100000000, 0x0009, 0x04020011, 0x11030011, 0x11050011 }, /* 100.000 33.333 25.000 */
++ { 104000000, 0x0802, 0x04020011, 0x11050009, 0x11090009 }, /* 104.000 31.200 24.960 */
++ { 108000000, 0x0403, 0x04020011, 0x11050009, 0x02000802 }, /* 108.000 32.400 24.923 */
++ { 112000000, 0x0205, 0x04020011, 0x11030021, 0x02000403 }, /* 112.000 32.000 24.889 */
++ { 115200000, 0x0303, 0x04020009, 0x11030011, 0x11050011 }, /* 115.200 32.000 24.000 */
++ { 120000000, 0x0011, 0x04020011, 0x11050011, 0x11090011 }, /* 120.000 30.000 24.000 */
++ { 124800000, 0x0802, 0x04020009, 0x11050009, 0x11090009 }, /* 124.800 31.200 24.960 */
++ { 128000000, 0x0305, 0x04020011, 0x11050011, 0x02000305 }, /* 128.000 32.000 24.000 */
++ { 132000000, 0x0603, 0x04020011, 0x11050011, 0x02000305 }, /* 132.000 33.000 24.750 */
++ { 136000000, 0x0c02, 0x04020011, 0x11090009, 0x02000603 }, /* 136.000 32.640 24.727 */
++ { 140000000, 0x0021, 0x04020011, 0x11050021, 0x02000c02 }, /* 140.000 30.000 24.706 */
++ { 144000000, 0x0405, 0x04020011, 0x01020202, 0x11090021 }, /* 144.000 30.857 24.686 */
++ { 150857142, 0x0605, 0x04020021, 0x02000305, 0x02000605 }, /* 150.857 33.000 24.000 */
++ { 152000000, 0x0e02, 0x04020011, 0x11050021, 0x02000e02 }, /* 152.000 32.571 24.000 */
++ { 156000000, 0x0802, 0x04020005, 0x11050009, 0x11090009 }, /* 156.000 31.200 24.960 */
++ { 160000000, 0x0309, 0x04020011, 0x11090011, 0x02000309 }, /* 160.000 32.000 24.000 */
++ { 163200000, 0x0c02, 0x04020009, 0x11090009, 0x02000603 }, /* 163.200 32.640 24.727 */
++ { 168000000, 0x0205, 0x04020005, 0x11030021, 0x02000403 }, /* 168.000 32.000 24.889 */
++ { 176000000, 0x0602, 0x04020003, 0x11050005, 0x02000602 }, /* 176.000 33.000 24.000 */
++ };
++ typedef struct {
++ uint32 mipsclock;
++ uint32 sbclock;
++ uint16 n;
++ uint32 sb;
++ uint32 pci33;
++ uint32 m2;
++ uint32 m3;
++ uint32 ratio;
++ uint32 ratio_parm;
++ } n4m_table_t;
++
++ n4m_table_t type2_table[] = {
++ { 180000000, 80000000, 0x0403, 0x01010000, 0x01020300, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
++ { 180000000, 90000000, 0x0403, 0x01000100, 0x01020300, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 },
++ { 200000000, 100000000, 0x0303, 0x01000000, 0x01000600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
++ { 211200000, 105600000, 0x0902, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
++ { 220800000, 110400000, 0x1500, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
++ { 230400000, 115200000, 0x0604, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
++ { 234000000, 104000000, 0x0b01, 0x01010000, 0x01010700, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
++ { 240000000, 120000000, 0x0803, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
++ { 252000000, 126000000, 0x0504, 0x01000100, 0x01020500, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 },
++ { 264000000, 132000000, 0x0903, 0x01000200, 0x01020700, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
++ { 270000000, 120000000, 0x0703, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
++ { 276000000, 122666666, 0x1500, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
++ { 280000000, 140000000, 0x0503, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
++ { 288000000, 128000000, 0x0604, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
++ { 288000000, 144000000, 0x0404, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
++ { 300000000, 133333333, 0x0803, 0x01010000, 0x01020600, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
++ { 300000000, 150000000, 0x0803, 0x01000100, 0x01020600, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 }
++ };
++
++ n4m_table_t type4_table[] = {
++ { 192000000, 96000000, 0x0702, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 0x21, 0x0aaa0555 },
++ { 200000000, 100000000, 0x0009, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 0x21, 0x0aaa0555 },
++ { 216000000, 108000000, 0x0211, 0x11020005, 0x11030303, 0x11020005, 0x04000005, 0x21, 0x0aaa0555 },
++ { 228000000, 101333333, 0x0e02, 0x11030003, 0x11210005, 0x11030305, 0x04000005, 0x94, 0x012a00a9 },
++ { 228000000, 114000000, 0x0e02, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 0x21, 0x0aaa0555 },
++ { 240000000, 120000000, 0x0109, 0x11030002, 0x01050203, 0x11030002, 0x04000003, 0x21, 0x0aaa0555 },
++ { 252000000, 126000000, 0x0203, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 0x21, 0x0aaa0555 },
++ { 264000000, 132000000, 0x0602, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 0x21, 0x0aaa0555 },
++ { 272000000, 116571428, 0x0c02, 0x04000021, 0x02000909, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
++ { 280000000, 120000000, 0x0209, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
++ { 288000000, 123428571, 0x0111, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
++ { 300000000, 120000000, 0x0009, 0x04000009, 0x01030203, 0x02000902, 0x04000002, 0x52, 0x02520129 }
++ };
++ uint icache_size, ic_lsize;
++ ulong start, end, dst;
++ bool ret = FALSE;
++
++ /* get index of the current core */
++ idx = sb_coreidx(sbh);
++
++ /* switch to extif or chipc core */
++ if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
++ pll_type = PLL_TYPE1;
++ clockcontrol_n = &eir->clockcontrol_n;
++ clockcontrol_sb = &eir->clockcontrol_sb;
++ clockcontrol_pci = &eir->clockcontrol_pci;
++ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
++ pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
++ clockcontrol_n = &cc->clockcontrol_n;
++ clockcontrol_sb = &cc->clockcontrol_sb;
++ clockcontrol_pci = &cc->clockcontrol_pci;
++ } else
++ goto done;
++
++ /* Store the current clock register values */
++ orig_n = R_REG(clockcontrol_n);
++ orig_sb = R_REG(clockcontrol_sb);
++ orig_pci = R_REG(clockcontrol_pci);
++
++ if (pll_type == PLL_TYPE1) {
++ /* Keep the current PCI clock if not specified */
++ if (pciclock == 0) {
++ pciclock = sb_clock_rate(pll_type, R_REG(clockcontrol_n), R_REG(clockcontrol_pci));
++ pciclock = (pciclock <= 25000000) ? 25000000 : 33000000;
++ }
++
++ /* Search for the closest MIPS clock less than or equal to a preferred value */
++ for (i = 0; i < ARRAYSIZE(type1_table); i++) {
++ ASSERT(type1_table[i].mipsclock ==
++ sb_clock_rate(pll_type, type1_table[i].n, type1_table[i].sb));
++ if (type1_table[i].mipsclock > mipsclock)
++ break;
++ }
++ if (i == 0) {
++ ret = FALSE;
++ goto done;
++ } else {
++ ret = TRUE;
++ i--;
++ }
++ ASSERT(type1_table[i].mipsclock <= mipsclock);
++
++ /* No PLL change */
++ if ((orig_n == type1_table[i].n) &&
++ (orig_sb == type1_table[i].sb) &&
++ (orig_pci == type1_table[i].pci33))
++ goto done;
++
++ /* Set the PLL controls */
++ W_REG(clockcontrol_n, type1_table[i].n);
++ W_REG(clockcontrol_sb, type1_table[i].sb);
++ if (pciclock == 25000000)
++ W_REG(clockcontrol_pci, type1_table[i].pci25);
++ else
++ W_REG(clockcontrol_pci, type1_table[i].pci33);
++
++ /* Reset */
++ sb_watchdog(sbh, 1);
++ while (1);
++ } else if ((pll_type == PLL_TYPE2) || (pll_type == PLL_TYPE4)) {
++ n4m_table_t *table = (pll_type == PLL_TYPE2) ? type2_table : type4_table;
++ uint tabsz = (pll_type == PLL_TYPE2) ? ARRAYSIZE(type2_table) : ARRAYSIZE(type4_table);
++
++ ASSERT(cc);
++
++ /* Store the current clock register values */
++ orig_m2 = R_REG(&cc->clockcontrol_m2);
++ orig_mips = R_REG(&cc->clockcontrol_mips);
++ orig_ratio_parm = 0;
++
++ /* Look up current ratio */
++ for (i = 0; i < tabsz; i++) {
++ if ((orig_n == table[i].n) &&
++ (orig_sb == table[i].sb) &&
++ (orig_pci == table[i].pci33) &&
++ (orig_m2 == table[i].m2) &&
++ (orig_mips == table[i].m3)) {
++ orig_ratio_parm = table[i].ratio_parm;
++ break;
++ }
++ }
++
++ /* Search for the closest MIPS clock greater or equal to a preferred value */
++ for (i = 0; i < tabsz; i++) {
++ ASSERT(table[i].mipsclock ==
++ sb_clock_rate(pll_type, table[i].n, table[i].m3));
++ if ((mipsclock <= table[i].mipsclock) &&
++ ((sbclock == 0) || (sbclock <= table[i].sbclock)))
++ break;
++ }
++ if (i == tabsz) {
++ ret = FALSE;
++ goto done;
++ } else {
++ ret = TRUE;
++ }
++
++ /* No PLL change */
++ if ((orig_n == table[i].n) &&
++ (orig_sb == table[i].sb) &&
++ (orig_pci == table[i].pci33) &&
++ (orig_m2 == table[i].m2) &&
++ (orig_mips == table[i].m3))
++ goto done;
++
++ /* Set the PLL controls */
++ W_REG(clockcontrol_n, table[i].n);
++ W_REG(clockcontrol_sb, table[i].sb);
++ W_REG(clockcontrol_pci, table[i].pci33);
++ W_REG(&cc->clockcontrol_m2, table[i].m2);
++ W_REG(&cc->clockcontrol_mips, table[i].m3);
++
++ /* No ratio change */
++ if (orig_ratio_parm == table[i].ratio_parm)
++ goto end_fill;
++
++ new_ratio = table[i].ratio_parm;
++
++ icache_probe(&icache_size, &ic_lsize);
++
++ /* Preload the code into the cache */
++ start = ((ulong) &&start_fill) & ~(ic_lsize - 1);
++ end = ((ulong) &&end_fill + (ic_lsize - 1)) & ~(ic_lsize - 1);
++ while (start < end) {
++ cache_unroll(start, Fill_I);
++ start += ic_lsize;
++ }
++
++ /* Copy the handler */
++ start = (ulong) &handler;
++ end = (ulong) &afterhandler;
++ dst = KSEG1ADDR(0x180);
++ for (i = 0; i < (end - start); i += 4)
++ *((ulong *)(dst + i)) = *((ulong *)(start + i));
++
++ /* Preload handler into the cache one line at a time */
++ for (i = 0; i < (end - start); i += 4)
++ cache_unroll(dst + i, Fill_I);
++
++ /* Clear BEV bit */
++ MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~ST0_BEV);
++
++ /* Enable interrupts */
++ MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) | (ALLINTS | ST0_IE));
++
++ /* Enable MIPS timer interrupt */
++ if (!(mipsr = sb_setcore(sbh, SB_MIPS, 0)) &&
++ !(mipsr = sb_setcore(sbh, SB_MIPS33, 0)))
++ ASSERT(mipsr);
++ W_REG(&mipsr->intmask, 1);
++
++ start_fill:
++ /* step 1, set clock ratios */
++ MTC0(C0_BROADCOM, 3, new_ratio);
++ MTC0(C0_BROADCOM, 1, 8);
++
++ /* step 2: program timer intr */
++ W_REG(&mipsr->timer, 100);
++ (void) R_REG(&mipsr->timer);
++
++ /* step 3, switch to async */
++ sync_mode = MFC0(C0_BROADCOM, 4);
++ MTC0(C0_BROADCOM, 4, 1 << 22);
++
++ /* step 4, set cfg active */
++ MTC0(C0_BROADCOM, 2, 0x9);
++
++
++ /* steps 5 & 6 */
++ __asm__ __volatile__ (
++ ".set\tmips3\n\t"
++ "wait\n\t"
++ ".set\tmips0"
++ );
++
++ /* step 7, clear cfg_active */
++ MTC0(C0_BROADCOM, 2, 0);
++
++ /* Additional Step: set back to orig sync mode */
++ MTC0(C0_BROADCOM, 4, sync_mode);
++
++ /* step 8, fake soft reset */
++ MTC0(C0_BROADCOM, 5, MFC0(C0_BROADCOM, 5) | 4);
++
++ end_fill:
++ /* step 9 set watchdog timer */
++ sb_watchdog(sbh, 20);
++ (void) R_REG(&cc->chipid);
++
++ /* step 11 */
++ __asm__ __volatile__ (
++ ".set\tmips3\n\t"
++ "sync\n\t"
++ "wait\n\t"
++ ".set\tmips0"
++ );
++ while (1);
++ }
++
++done:
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ return ret;
++}
++
++
++/* returns the ncdl value to be programmed into sdram_ncdl for calibration */
++uint32
++sb_memc_get_ncdl(void *sbh)
++{
++ sbmemcregs_t *memc;
++ uint32 ret = 0;
++ uint32 config, rd, wr, misc, dqsg, cd, sm, sd;
++ uint idx, rev;
++
++ idx = sb_coreidx(sbh);
++
++ memc = (sbmemcregs_t *)sb_setcore(sbh, SB_MEMC, 0);
++ if (memc == 0)
++ goto out;
++
++ rev = sb_corerev(sbh);
++
++ config = R_REG(&memc->config);
++ wr = R_REG(&memc->wrncdlcor);
++ rd = R_REG(&memc->rdncdlcor);
++ misc = R_REG(&memc->miscdlyctl);
++ dqsg = R_REG(&memc->dqsgatencdl);
++
++ rd &= MEMC_RDNCDLCOR_RD_MASK;
++ wr &= MEMC_WRNCDLCOR_WR_MASK;
++ dqsg &= MEMC_DQSGATENCDL_G_MASK;
++
++ if (config & MEMC_CONFIG_DDR) {
++ ret = (wr << 16) | (rd << 8) | dqsg;
++ } else {
++ if (rev > 0)
++ cd = rd;
++ else
++ cd = (rd == MEMC_CD_THRESHOLD) ? rd : (wr + MEMC_CD_THRESHOLD);
++ sm = (misc & MEMC_MISC_SM_MASK) >> MEMC_MISC_SM_SHIFT;
++ sd = (misc & MEMC_MISC_SD_MASK) >> MEMC_MISC_SD_SHIFT;
++ ret = (sm << 16) | (sd << 8) | cd;
++ }
++
++out:
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ return ret;
++}
+diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/sbpci.c
+--- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/sbpci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/sbpci.c 2005-11-07 01:12:51.819809500 +0100
+@@ -0,0 +1,530 @@
++/*
++ * Low-Level PCI and SB support for BCM47xx
++ *
++ * Copyright 2001-2003, 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: sbpci.c,v 1.2 2005/02/28 13:34:25 jolt Exp $
++ */
++
++#include <typedefs.h>
++#include <pcicfg.h>
++#include <bcmdevs.h>
++#include <sbconfig.h>
++#include <sbpci.h>
++#include <osl.h>
++#include <bcmendian.h>
++#include <bcmutils.h>
++#include <sbutils.h>
++#include <bcmnvram.h>
++#include <hndmips.h>
++
++/* Can free sbpci_init() memory after boot */
++#ifndef linux
++#define __init
++#endif
++
++/* Emulated configuration space */
++static pci_config_regs sb_config_regs[SB_MAXCORES];
++
++/* Banned cores */
++static uint16 pci_ban[32] = { 0 };
++static uint pci_banned = 0;
++
++/* CardBus mode */
++static bool cardbus = FALSE;
++
++/*
++ * Functions for accessing external PCI configuration space
++ */
++
++/* Assume one-hot slot wiring */
++#define PCI_SLOT_MAX 16
++
++static uint32
++config_cmd(void *sbh, uint bus, uint dev, uint func, uint off)
++{
++ uint coreidx;
++ sbpciregs_t *regs;
++ uint32 addr = 0;
++
++ /* CardBusMode supports only one device */
++ if (cardbus && dev > 1)
++ return 0;
++
++ coreidx = sb_coreidx(sbh);
++ regs = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0);
++
++ /* Type 0 transaction */
++ if (bus == 1) {
++ /* Skip unwired slots */
++ if (dev < PCI_SLOT_MAX) {
++ /* Slide the PCI window to the appropriate slot */
++ W_REG(®s->sbtopci1, SBTOPCI_CFG0 | ((1 << (dev + 16)) & SBTOPCI1_MASK));
++ addr = SB_PCI_CFG | ((1 << (dev + 16)) & ~SBTOPCI1_MASK) |
++ (func << 8) | (off & ~3);
++ }
++ }
++
++ /* Type 1 transaction */
++ else {
++ W_REG(®s->sbtopci1, SBTOPCI_CFG1);
++ addr = SB_PCI_CFG | (bus << 16) | (dev << 11) | (func << 8) | (off & ~3);
++ }
++
++ sb_setcoreidx(sbh, coreidx);
++
++ return addr;
++}
++
++static int
++extpci_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ uint32 addr, *reg = NULL, val;
++ int ret = 0;
++
++ if (!(addr = config_cmd(sbh, bus, dev, func, off)) ||
++ !(reg = (uint32 *) REG_MAP(addr, len)) ||
++ BUSPROBE(val, reg))
++ val = 0xffffffff;
++
++ val >>= 8 * (off & 3);
++ if (len == 4)
++ *((uint32 *) buf) = val;
++ else if (len == 2)
++ *((uint16 *) buf) = (uint16) val;
++ else if (len == 1)
++ *((uint8 *) buf) = (uint8) val;
++ else
++ ret = -1;
++
++ if (reg)
++ REG_UNMAP(reg);
++
++ return ret;
++}
++
++static int
++extpci_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ uint32 addr, *reg = NULL, val;
++ int ret = 0;
++
++ if (!(addr = config_cmd(sbh, bus, dev, func, off)) ||
++ !(reg = (uint32 *) REG_MAP(addr, len)) ||
++ BUSPROBE(val, reg))
++ goto done;
++
++ if (len == 4)
++ val = *((uint32 *) buf);
++ else if (len == 2) {
++ val &= ~(0xffff << (8 * (off & 3)));
++ val |= *((uint16 *) buf) << (8 * (off & 3));
++ } else if (len == 1) {
++ val &= ~(0xff << (8 * (off & 3)));
++ val |= *((uint8 *) buf) << (8 * (off & 3));
++ } else
++ ret = -1;
++
++ W_REG(reg, val);
++
++ done:
++ if (reg)
++ REG_UNMAP(reg);
++
++ return ret;
++}
++
++/*
++ * Functions for accessing translated SB configuration space
++ */
++
++static int
++sb_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ pci_config_regs *cfg;
++
++ if (dev >= SB_MAXCORES || (off + len) > sizeof(pci_config_regs))
++ return -1;
++ cfg = &sb_config_regs[dev];
++
++ ASSERT(ISALIGNED(off, len));
++ ASSERT(ISALIGNED(buf, len));
++
++ if (len == 4)
++ *((uint32 *) buf) = ltoh32(*((uint32 *)((ulong) cfg + off)));
++ else if (len == 2)
++ *((uint16 *) buf) = ltoh16(*((uint16 *)((ulong) cfg + off)));
++ else if (len == 1)
++ *((uint8 *) buf) = *((uint8 *)((ulong) cfg + off));
++ else
++ return -1;
++
++ return 0;
++}
++
++static int
++sb_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ uint coreidx, n;
++ void *regs;
++ sbconfig_t *sb;
++ pci_config_regs *cfg;
++
++ if (dev >= SB_MAXCORES || (off + len) > sizeof(pci_config_regs))
++ return -1;
++ cfg = &sb_config_regs[dev];
++
++ ASSERT(ISALIGNED(off, len));
++ ASSERT(ISALIGNED(buf, len));
++
++ /* Emulate BAR sizing */
++ if (off >= OFFSETOF(pci_config_regs, base[0]) && off <= OFFSETOF(pci_config_regs, base[3]) &&
++ len == 4 && *((uint32 *) buf) == ~0) {
++ coreidx = sb_coreidx(sbh);
++ if ((regs = sb_setcoreidx(sbh, dev))) {
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++ /* Highest numbered address match register */
++ n = (R_REG(&sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT;
++ if (off == OFFSETOF(pci_config_regs, base[0]))
++ cfg->base[0] = ~(sb_size(R_REG(&sb->sbadmatch0)) - 1);
++ /*else if (off == OFFSETOF(pci_config_regs, base[1]) && n >= 1)
++ cfg->base[1] = ~(sb_size(R_REG(&sb->sbadmatch1)) - 1);
++ else if (off == OFFSETOF(pci_config_regs, base[2]) && n >= 2)
++ cfg->base[2] = ~(sb_size(R_REG(&sb->sbadmatch2)) - 1);
++ else if (off == OFFSETOF(pci_config_regs, base[3]) && n >= 3)
++ cfg->base[3] = ~(sb_size(R_REG(&sb->sbadmatch3)) - 1);*/
++ }
++ sb_setcoreidx(sbh, coreidx);
++ return 0;
++ }
++
++ if (len == 4)
++ *((uint32 *)((ulong) cfg + off)) = htol32(*((uint32 *) buf));
++ else if (len == 2)
++ *((uint16 *)((ulong) cfg + off)) = htol16(*((uint16 *) buf));
++ else if (len == 1)
++ *((uint8 *)((ulong) cfg + off)) = *((uint8 *) buf);
++ else
++ return -1;
++
++ return 0;
++}
++
++int
++sbpci_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ if (bus == 0)
++ return sb_read_config(sbh, bus, dev, func, off, buf, len);
++ else
++ return extpci_read_config(sbh, bus, dev, func, off, buf, len);
++}
++
++int
++sbpci_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ if (bus == 0)
++ return sb_write_config(sbh, bus, dev, func, off, buf, len);
++ else
++ return extpci_write_config(sbh, bus, dev, func, off, buf, len);
++}
++
++void
++sbpci_ban(uint16 core)
++{
++ if (pci_banned < ARRAYSIZE(pci_ban))
++ pci_ban[pci_banned++] = core;
++}
++
++int __init
++sbpci_init(void *sbh)
++{
++ uint chip, chiprev, chippkg, coreidx, host, i;
++ sbpciregs_t *pci;
++ sbconfig_t *sb;
++ pci_config_regs *cfg;
++ void *regs;
++ char varname[8];
++ uint wlidx = 0;
++ uint16 vendor, core;
++ uint8 class, subclass, progif;
++ uint32 val;
++ uint32 sbips_int_mask[] = { 0, SBIPS_INT1_MASK, SBIPS_INT2_MASK, SBIPS_INT3_MASK, SBIPS_INT4_MASK };
++ uint32 sbips_int_shift[] = { 0, 0, SBIPS_INT2_SHIFT, SBIPS_INT3_SHIFT, SBIPS_INT4_SHIFT };
++
++ chip = sb_chip(sbh);
++ chiprev = sb_chiprev(sbh);
++ chippkg = sb_chippkg(sbh);
++ coreidx = sb_coreidx(sbh);
++
++ if (!(pci = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0)))
++ return -1;
++ sb_core_reset(sbh, 0);
++
++ if (((chip == BCM4310_DEVICE_ID) && (chiprev == 0)) ||
++ ((chip == BCM4712_DEVICE_ID) && (chippkg == BCM4712SMALL_PKG_ID)))
++ host = 0;
++ else
++ host = !BUSPROBE(val, &pci->control);
++
++ if (!host) {
++ /* Disable PCI interrupts in client mode */
++ sb = (sbconfig_t *)((ulong) pci + SBCONFIGOFF);
++ W_REG(&sb->sbintvec, 0);
++
++ /* Disable the PCI bridge in client mode */
++ sbpci_ban(SB_PCI);
++ printf("PCI: Disabled\n");
++ } else {
++ /* Reset the external PCI bus and enable the clock */
++ W_REG(&pci->control, 0x5); /* enable the tristate drivers */
++ W_REG(&pci->control, 0xd); /* enable the PCI clock */
++ OSL_DELAY(100); /* delay 100 us */
++ W_REG(&pci->control, 0xf); /* deassert PCI reset */
++ W_REG(&pci->arbcontrol, PCI_INT_ARB); /* use internal arbiter */
++ OSL_DELAY(1); /* delay 1 us */
++
++ /* Enable CardBusMode */
++ cardbus = nvram_match("cardbus", "1");
++ if (cardbus) {
++ printf("PCI: Enabling CardBus\n");
++ /* GPIO 1 resets the CardBus device on bcm94710ap */
++ sb_gpioout(sbh, 1, 1);
++ sb_gpioouten(sbh, 1, 1);
++ W_REG(&pci->sprom[0], R_REG(&pci->sprom[0]) | 0x400);
++ }
++
++ /* 64 MB I/O access window */
++ W_REG(&pci->sbtopci0, SBTOPCI_IO);
++ /* 64 MB configuration access window */
++ W_REG(&pci->sbtopci1, SBTOPCI_CFG0);
++ /* 1 GB memory access window */
++ W_REG(&pci->sbtopci2, SBTOPCI_MEM | SB_PCI_DMA);
++
++ /* Enable PCI bridge BAR0 prefetch and burst */
++ val = 6;
++ sbpci_write_config(sbh, 1, 0, 0, PCI_CFG_CMD, &val, sizeof(val));
++
++ /* Enable PCI interrupts */
++ W_REG(&pci->intmask, PCI_INTA);
++ }
++
++ /* Scan the SB bus */
++ bzero(sb_config_regs, sizeof(sb_config_regs));
++ for (cfg = sb_config_regs; cfg < &sb_config_regs[SB_MAXCORES]; cfg++) {
++ cfg->vendor = 0xffff;
++ if (!(regs = sb_setcoreidx(sbh, cfg - sb_config_regs)))
++ continue;
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ /* Read ID register and parse vendor and core */
++ val = R_REG(&sb->sbidhigh);
++ vendor = (val & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT;
++ core = (val & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
++ progif = 0;
++
++ /* Check if this core is banned */
++ for (i = 0; i < pci_banned; i++)
++ if (core == pci_ban[i])
++ break;
++ if (i < pci_banned)
++ continue;
++
++ /* Known vendor translations */
++ switch (vendor) {
++ case SB_VEND_BCM:
++ vendor = VENDOR_BROADCOM;
+ break;
+ }
+
+}
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/sbutils.c
--- linux-2.6.12.5/arch/mips/bcm947xx/broadcom/sbutils.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/sbutils.c 2005-08-28 11:12:20.482851248 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/broadcom/sbutils.c 2005-11-07 01:12:51.823809750 +0100
@@ -0,0 +1,1895 @@
+/*
+ * Misc utility routines for accessing chip-specific features
+
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/bcm4710.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcm4710.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/bcm4710.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcm4710.h 2005-08-28 11:12:20.430859152 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcm4710.h 2005-11-07 01:12:51.823809750 +0100
@@ -0,0 +1,90 @@
+/*
+ * BCM4710 address space map and definitions
+#endif /* _bcm4710_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/bcmdevs.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmdevs.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/bcmdevs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmdevs.h 2005-08-28 11:12:20.431859000 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmdevs.h 2005-11-07 01:12:51.823809750 +0100
@@ -0,0 +1,238 @@
+/*
+ * Broadcom device-specific manifest constants.
+#endif /* _BCMDEVS_H */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/bcmendian.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmendian.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/bcmendian.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmendian.h 2005-08-28 11:12:20.431859000 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmendian.h 2005-11-07 01:12:51.823809750 +0100
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * $Id$
+#endif /* _BCMENDIAN_H_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/bcmenet47xx.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmenet47xx.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/bcmenet47xx.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmenet47xx.h 2005-08-28 11:12:20.432858848 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmenet47xx.h 2005-11-07 01:12:51.823809750 +0100
@@ -0,0 +1,229 @@
+/*
+ * Hardware-specific definitions for
+#endif /* _bcmenet_47xx_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/bcmenetmib.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmenetmib.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/bcmenetmib.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmenetmib.h 2005-08-28 11:12:20.432858848 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmenetmib.h 2005-11-07 01:12:51.823809750 +0100
@@ -0,0 +1,81 @@
+/*
+ * Hardware-specific MIB definition for
+#endif /* _bcmenetmib_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/bcmenetrxh.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmenetrxh.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/bcmenetrxh.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmenetrxh.h 2005-08-28 11:12:20.433858696 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmenetrxh.h 2005-11-07 01:12:51.827810000 +0100
@@ -0,0 +1,43 @@
+/*
+ * Hardware-specific Receive Data Header for the
+#endif /* _bcmenetrxh_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/bcmnvram.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmnvram.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/bcmnvram.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmnvram.h 2005-08-28 11:12:20.433858696 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmnvram.h 2005-11-07 01:12:51.827810000 +0100
@@ -0,0 +1,131 @@
+/*
+ * NVRAM variable manipulation
+#endif /* _bcmnvram_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/bcmsrom.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmsrom.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/bcmsrom.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmsrom.h 2005-08-28 11:12:20.433858696 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmsrom.h 2005-11-07 01:12:51.827810000 +0100
@@ -0,0 +1,24 @@
+/*
+ * Misc useful routines to access NIC srom
+#endif /* _bcmsrom_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/bcmutils.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmutils.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/bcmutils.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmutils.h 2005-08-28 11:12:20.435858392 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bcmutils.h 2005-11-07 01:12:51.827810000 +0100
@@ -0,0 +1,136 @@
+/*
+ * Misc useful os-independent macros and functions.
+#endif /* _bcmutils_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/bitfuncs.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bitfuncs.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/bitfuncs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bitfuncs.h 2005-08-28 11:12:20.435858392 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/bitfuncs.h 2005-11-07 01:12:51.827810000 +0100
@@ -0,0 +1,85 @@
+/*
+ * bit manipulation utility functions
+#endif /* _BITFUNCS_H */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/epivers.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/epivers.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/epivers.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/epivers.h 2005-08-28 11:12:20.435858392 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/epivers.h 2005-11-07 01:12:51.827810000 +0100
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2001-2003, Broadcom Corporation
+#endif /* _epivers_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/epivers.h.in linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/epivers.h.in
--- linux-2.6.12.5/arch/mips/bcm947xx/include/epivers.h.in 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/epivers.h.in 2005-08-28 11:12:20.436858240 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/epivers.h.in 2005-11-07 01:12:51.827810000 +0100
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2001-2003, Broadcom Corporation
+#endif /* _epivers_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/etsockio.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/etsockio.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/etsockio.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/etsockio.h 2005-08-28 11:12:20.436858240 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/etsockio.h 2005-11-07 01:12:51.827810000 +0100
@@ -0,0 +1,60 @@
+/*
+ * Driver-specific socket ioctls
+#endif
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/flash.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/flash.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/flash.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/flash.h 2005-08-28 11:12:20.437858088 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/flash.h 2005-11-07 01:12:51.827810000 +0100
@@ -0,0 +1,184 @@
+/*
+ * flash.h: Common definitions for flash access.
+#endif
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/flashutl.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/flashutl.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/flashutl.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/flashutl.h 2005-08-28 11:12:20.437858088 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/flashutl.h 2005-11-07 01:12:51.831810250 +0100
@@ -0,0 +1,34 @@
+/*
+ * BCM47XX FLASH driver interface
+#endif /* _flashutl_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/hnddma.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/hnddma.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/hnddma.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/hnddma.h 2005-08-28 11:12:20.438857936 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/hnddma.h 2005-11-07 01:12:51.831810250 +0100
@@ -0,0 +1,181 @@
+/*
+ * Generic Broadcom Home Networking Division (HND) DMA engine definitions.
+#endif /* _hnddma_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/hndmips.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/hndmips.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/hndmips.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/hndmips.h 2005-08-28 11:12:20.439857784 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/hndmips.h 2005-11-07 01:12:51.831810250 +0100
@@ -0,0 +1,16 @@
+/*
+ * Alternate include file for HND sbmips.h since CFE also ships with
+#include "sbmips.h"
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/linux_osl.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/linux_osl.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/linux_osl.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/linux_osl.h 2005-08-28 11:12:20.440857632 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/linux_osl.h 2005-11-07 01:12:51.831810250 +0100
@@ -0,0 +1,313 @@
+/*
+ * Linux OS Independent Layer
+#endif /* _linux_osl_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/linuxver.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/linuxver.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/linuxver.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/linuxver.h 2005-08-28 11:12:20.441857480 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/linuxver.h 2005-11-07 01:12:51.831810250 +0100
@@ -0,0 +1,326 @@
+/*
+ * Linux-specific abstractions to gain some independence from linux kernel versions.
+#endif /* _linuxver_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/nvports.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/nvports.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/nvports.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/nvports.h 2005-08-28 11:12:20.441857480 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/nvports.h 2005-11-07 01:12:51.831810250 +0100
@@ -0,0 +1,62 @@
+/*
+ * Broadcom Home Gateway Reference Design
+
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/osl.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/osl.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/osl.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/osl.h 2005-08-28 11:12:20.441857480 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/osl.h 2005-11-07 01:12:51.835810500 +0100
@@ -0,0 +1,38 @@
+/*
+ * OS Independent Layer
+#endif /* _osl_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/pcicfg.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/pcicfg.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/pcicfg.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/pcicfg.h 2005-08-28 11:12:20.442857328 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/pcicfg.h 2005-11-07 01:12:51.835810500 +0100
@@ -0,0 +1,362 @@
+/*
+ * pcicfg.h: PCI configuration constants and structures.
+#endif
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/proto/802.11.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/proto/802.11.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/proto/802.11.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/proto/802.11.h 2005-08-28 11:12:20.450856112 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/proto/802.11.h 2005-11-07 01:12:51.835810500 +0100
@@ -0,0 +1,679 @@
+/*
+ * Copyright 2001-2003, Broadcom Corporation
+#endif /* _802_11_H_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/proto/ethernet.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/proto/ethernet.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/proto/ethernet.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/proto/ethernet.h 2005-08-28 11:12:20.450856112 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/proto/ethernet.h 2005-11-07 01:12:51.835810500 +0100
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * $Id$
+#endif /* _NET_ETHERNET_H_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/rts/crc.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/rts/crc.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/rts/crc.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/rts/crc.h 2005-08-28 11:12:20.451855960 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/rts/crc.h 2005-11-07 01:12:51.835810500 +0100
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * $Id$
+#endif /* _RTS_CRC_H_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/s5.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/s5.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/s5.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/s5.h 2005-08-28 11:12:20.451855960 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/s5.h 2005-11-07 01:12:51.835810500 +0100
@@ -0,0 +1,103 @@
+#ifndef _S5_H_
+#define _S5_H_
+#endif /*!_S5_H_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/sbchipc.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbchipc.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/sbchipc.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbchipc.h 2005-08-28 11:12:20.468853376 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbchipc.h 2005-11-07 01:12:51.839810750 +0100
@@ -0,0 +1,281 @@
+/*
+ * SiliconBackplane Chipcommon core hardware definitions.
+#endif /* _SBCHIPC_H */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/sbconfig.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbconfig.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/sbconfig.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbconfig.h 2005-08-28 11:12:20.469853224 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbconfig.h 2005-11-07 01:12:51.839810750 +0100
@@ -0,0 +1,296 @@
+/*
+ * Broadcom SiliconBackplane hardware register definitions.
+#endif /* _SBCONFIG_H */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/sbextif.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbextif.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/sbextif.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbextif.h 2005-08-28 11:12:20.470853072 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbextif.h 2005-11-07 01:12:51.839810750 +0100
@@ -0,0 +1,242 @@
+/*
+ * Hardware-specific External Interface I/O core definitions
+#endif /* _SBEXTIF_H */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/sbmemc.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbmemc.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/sbmemc.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbmemc.h 2005-08-28 11:12:20.471852920 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbmemc.h 2005-11-07 01:12:51.839810750 +0100
@@ -0,0 +1,144 @@
+/*
+ * BCM47XX Sonics SiliconBackplane DDR/SDRAM controller core hardware definitions.
+#endif /* _SBMEMC_H */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/sbmips.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbmips.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/sbmips.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbmips.h 2005-08-28 11:12:20.471852920 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbmips.h 2005-11-07 01:12:51.839810750 +0100
@@ -0,0 +1,56 @@
+/*
+ * Broadcom SiliconBackplane MIPS definitions
+#endif /* _SBMIPS_H */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/sbpci.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbpci.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/sbpci.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbpci.h 2005-08-28 11:12:20.471852920 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbpci.h 2005-11-07 01:12:51.839810750 +0100
@@ -0,0 +1,113 @@
+/*
+ * BCM47XX Sonics SiliconBackplane PCI core hardware definitions.
+#endif /* _SBPCI_H */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/sbpcmcia.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbpcmcia.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/sbpcmcia.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbpcmcia.h 2005-08-28 11:12:20.472852768 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbpcmcia.h 2005-11-07 01:12:51.839810750 +0100
@@ -0,0 +1,131 @@
+/*
+ * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions.
+#endif /* _SBPCMCIA_H */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/sbsdram.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbsdram.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/sbsdram.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbsdram.h 2005-08-28 11:12:20.472852768 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbsdram.h 2005-11-07 01:12:51.843811000 +0100
@@ -0,0 +1,75 @@
+/*
+ * BCM47XX Sonics SiliconBackplane SDRAM controller core hardware definitions.
+#endif /* _SBSDRAM_H */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/sbutils.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbutils.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/sbutils.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbutils.h 2005-08-28 11:12:20.473852616 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/sbutils.h 2005-11-07 01:12:51.843811000 +0100
@@ -0,0 +1,90 @@
+/*
+ * Misc utility routines for accessing chip-specific features
+#endif /* _sbutils_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/trxhdr.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/trxhdr.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/trxhdr.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/trxhdr.h 2005-08-28 11:12:20.474852464 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/trxhdr.h 2005-11-07 01:12:51.843811000 +0100
@@ -0,0 +1,31 @@
+/*
+ * TRX image file header format.
+typedef struct trx_header TRXHDR, *PTRXHDR;
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/typedefs.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/typedefs.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/typedefs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/typedefs.h 2005-08-28 11:12:20.474852464 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/typedefs.h 2005-11-07 01:12:51.843811000 +0100
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2001-2003, Broadcom Corporation
+#endif /* _TYPEDEFS_H_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/include/wlioctl.h linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/wlioctl.h
--- linux-2.6.12.5/arch/mips/bcm947xx/include/wlioctl.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/wlioctl.h 2005-08-28 11:12:20.475852312 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/include/wlioctl.h 2005-11-07 01:12:51.843811000 +0100
@@ -0,0 +1,690 @@
+/*
+ * Custom OID/ioctl definitions for
+#endif /* _wlioctl_h_ */
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/int-handler.S linux-2.6.12.5-brcm/arch/mips/bcm947xx/int-handler.S
--- linux-2.6.12.5/arch/mips/bcm947xx/int-handler.S 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/int-handler.S 2005-08-28 16:58:08.027788792 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/int-handler.S 2005-11-07 01:12:51.843811000 +0100
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
+ END(bcm47xx_irq_handler)
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/irq.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/irq.c
--- linux-2.6.12.5/arch/mips/bcm947xx/irq.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/irq.c 2005-08-28 16:58:26.178029536 +0200
-@@ -0,0 +1,68 @@
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/irq.c 2005-11-19 02:16:15.531125500 +0100
+@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
+ *
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/irq_cpu.h>
-+#include <asm/gdb-stub.h>
+
+extern asmlinkage void bcm47xx_irq_handler(void);
+
+ set_except_vector(0, bcm47xx_irq_handler);
+ mips_cpu_irq_init(0);
+}
+diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/Makefile linux-2.6.12.5-brcm/arch/mips/bcm947xx/Makefile
+--- linux-2.6.12.5/arch/mips/bcm947xx/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/Makefile 2005-11-07 01:12:51.811809000 +0100
+@@ -0,0 +1,6 @@
++#
++# Makefile for the BCM47xx specific kernel interface routines
++# under Linux.
++#
++
++obj-y := irq.o int-handler.o prom.o setup.o time.o
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/prom.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/prom.c
--- linux-2.6.12.5/arch/mips/bcm947xx/prom.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/prom.c 2005-08-28 16:58:41.789656208 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/prom.c 2005-11-07 01:12:51.847811250 +0100
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
+}
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/setup.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/setup.c
--- linux-2.6.12.5/arch/mips/bcm947xx/setup.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/setup.c 2005-08-28 16:57:28.317825624 +0200
-@@ -0,0 +1,127 @@
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/setup.c 2005-11-29 01:23:30.667381000 +0100
+@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
++ * Copyright (C) 2005 Waldemar Brodkorb <wbx@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
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
++#include <asm/bootinfo.h>
+#include <asm/time.h>
+#include <asm/reboot.h>
+
+#include <sbconfig.h>
+#include <bcmdevs.h>
+
-+#if 1
-+
-+#define SER_PORT1(reg) (*((volatile unsigned char *)(0xb8000400+reg)))
-+
-+int putDebugChar(char c)
-+{
-+ while (!(SER_PORT1(UART_LSR) & UART_LSR_THRE));
-+ SER_PORT1(UART_TX) = c;
-+
-+ return 1;
-+}
-+
-+char getDebugChar(void)
-+{
-+ while (!(SER_PORT1(UART_LSR) & 1));
-+ return SER_PORT1(UART_RX);
-+}
-+
++extern void bcm47xx_time_init(void);
++extern void bcm47xx_timer_setup(struct irqaction *irq);
++void *sbh;
+
+static int ser_line = 0;
+
+ printk(KERN_ERR "Serial setup failed!\n");
+ }
+}
-+#endif
-+
-+extern void bcm47xx_time_init(void);
-+extern void bcm47xx_timer_setup(struct irqaction *irq);
+
+void *nvram_get(char *foo)
+{
+ return NULL;
+}
+
-+void *sbh;
+
+static void bcm47xx_machine_restart(char *command)
+{
++ printk("Please stand by while rebooting the system...\n");
++
+ /* Set the watchdog timer to reset immediately */
-+ cli();
++ local_irq_disable();
+ sb_watchdog(sbh, 1);
+ while (1);
+}
+static void bcm47xx_machine_halt(void)
+{
+ /* Disable interrupts and watchdog and spin forever */
-+ cli();
++ local_irq_disable();
+ sb_watchdog(sbh, 0);
+ while (1);
+}
+ sbh = sb_kattach();
+ sb_mips_init(sbh);
+ sbpci_init(sbh);
++
+ sb_serial_init(sbh, serial_add);
+
+ _machine_restart = bcm47xx_machine_restart;
+early_initcall(bcm47xx_init);
diff -Nur linux-2.6.12.5/arch/mips/bcm947xx/time.c linux-2.6.12.5-brcm/arch/mips/bcm947xx/time.c
--- linux-2.6.12.5/arch/mips/bcm947xx/time.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/time.c 2005-08-28 16:57:55.440702320 +0200
++++ linux-2.6.12.5-brcm/arch/mips/bcm947xx/time.c 2005-11-07 01:12:51.847811250 +0100
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
+ /* Enable the timer interrupt */
+ setup_irq(7, irq);
+}
+diff -Nur linux-2.6.12.5/arch/mips/Kconfig linux-2.6.12.5-brcm/arch/mips/Kconfig
+--- linux-2.6.12.5/arch/mips/Kconfig 2005-08-15 02:20:18.000000000 +0200
++++ linux-2.6.12.5-brcm/arch/mips/Kconfig 2005-11-07 01:12:51.811809000 +0100
+@@ -40,6 +40,15 @@
+ Members include the Acer PICA, MIPS Magnum 4000, MIPS Millenium and
+ Olivetti M700-10 workstations.
+
++config BCM947XX
++ bool "Support for BCM947xx based boards"
++ select DMA_NONCOHERENT
++ select HW_HAS_PCI
++ select IRQ_CPU
++ select CPU_LITTLE_ENDIAN
++ help
++ Support for BCM947xx based boards
++
+ config ACER_PICA_61
+ bool "Support for Acer PICA 1 chipset (EXPERIMENTAL)"
+ depends on MACH_JAZZ && EXPERIMENTAL
+@@ -974,7 +983,7 @@
+
+ config CPU_LITTLE_ENDIAN
+ bool "Generate little endian code"
+- default y if ACER_PICA_61 || CASIO_E55 || DDB5074 || DDB5476 || DDB5477 || MACH_DECSTATION || IBM_WORKPAD || LASAT || MIPS_COBALT || MIPS_ITE8172 || MIPS_IVR || SOC_AU1X00 || NEC_OSPREY || OLIVETTI_M700 || SNI_RM200_PCI || VICTOR_MPC30X || ZAO_CAPCELLA
++ default y if ACER_PICA_61 || CASIO_E55 || DDB5074 || DDB5476 || DDB5477 || MACH_DECSTATION || IBM_WORKPAD || LASAT || MIPS_COBALT || MIPS_ITE8172 || MIPS_IVR || SOC_AU1X00 || NEC_OSPREY || OLIVETTI_M700 || SNI_RM200_PCI || VICTOR_MPC30X || ZAO_CAPCELLA || BCM947XX
+ default n if MIPS_EV64120 || MIPS_EV96100 || MOMENCO_OCELOT || MOMENCO_OCELOT_G || SGI_IP22 || SGI_IP27 || SGI_IP32 || TOSHIBA_JMR3927
+ help
+ Some MIPS machines can be configured for either little or big endian
diff -Nur linux-2.6.12.5/arch/mips/kernel/cpu-probe.c linux-2.6.12.5-brcm/arch/mips/kernel/cpu-probe.c
--- linux-2.6.12.5/arch/mips/kernel/cpu-probe.c 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/arch/mips/kernel/cpu-probe.c 2005-08-28 11:12:20.538842736 +0200
++++ linux-2.6.12.5-brcm/arch/mips/kernel/cpu-probe.c 2005-11-07 01:12:51.847811250 +0100
@@ -555,6 +555,28 @@
}
}
break;
diff -Nur linux-2.6.12.5/arch/mips/kernel/head.S linux-2.6.12.5-brcm/arch/mips/kernel/head.S
--- linux-2.6.12.5/arch/mips/kernel/head.S 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/arch/mips/kernel/head.S 2005-08-28 11:12:20.539842584 +0200
++++ linux-2.6.12.5-brcm/arch/mips/kernel/head.S 2005-11-07 01:12:51.847811250 +0100
@@ -122,6 +122,14 @@
#endif
.endm
* Necessary for machines which link their kernels at KSEG0.
diff -Nur linux-2.6.12.5/arch/mips/kernel/proc.c linux-2.6.12.5-brcm/arch/mips/kernel/proc.c
--- linux-2.6.12.5/arch/mips/kernel/proc.c 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/arch/mips/kernel/proc.c 2005-08-28 11:12:20.553840456 +0200
++++ linux-2.6.12.5-brcm/arch/mips/kernel/proc.c 2005-11-07 01:12:51.847811250 +0100
@@ -75,7 +75,9 @@
[CPU_VR4133] "NEC VR4133",
[CPU_VR4181] "NEC VR4181",
};
+diff -Nur linux-2.6.12.5/arch/mips/Makefile linux-2.6.12.5-brcm/arch/mips/Makefile
+--- linux-2.6.12.5/arch/mips/Makefile 2005-08-15 02:20:18.000000000 +0200
++++ linux-2.6.12.5-brcm/arch/mips/Makefile 2005-11-07 01:12:51.811809000 +0100
+@@ -79,7 +79,7 @@
+ cflags-y += -I $(TOPDIR)/include/asm/gcc
+ cflags-y += -G 0 -mno-abicalls -fno-pic -pipe
+ cflags-y += $(call cc-option, -finline-limit=100000)
+-LDFLAGS_vmlinux += -G 0 -static -n
++LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
+ MODFLAGS += -mlong-calls
+
+ cflags-$(CONFIG_SB1XXX_CORELIS) += -mno-sched-prolog -fno-omit-frame-pointer
+@@ -170,6 +170,7 @@
+ cflags-$(CONFIG_CPU_MIPS32) += \
+ $(call set_gccflags,mips32,mips32,r4600,mips3,mips2) \
+ -Wa,--trap
++cflags-$(CONFIG_CPU_MIPS32) += -Wa,--trap
+
+ cflags-$(CONFIG_CPU_MIPS64) += \
+ $(call set_gccflags,mips64,mips64,r4600,mips3,mips2) \
+@@ -618,6 +619,14 @@
+ load-$(CONFIG_SIBYTE_SWARM) := 0xffffffff80100000
+
+ #
++# Broadcom BCM47XX boards
++#
++core-$(CONFIG_BCM947XX) += arch/mips/bcm947xx/ arch/mips/bcm947xx/broadcom/
++cflags-$(CONFIG_BCM947XX) += -Iarch/mips/bcm947xx/include
++load-$(CONFIG_BCM947XX) := 0xffffffff80001000
++
++
++#
+ # SNI RM200 PCI
+ #
+ core-$(CONFIG_SNI_RM200_PCI) += arch/mips/sni/
diff -Nur linux-2.6.12.5/arch/mips/mm/tlbex.c linux-2.6.12.5-brcm/arch/mips/mm/tlbex.c
--- linux-2.6.12.5/arch/mips/mm/tlbex.c 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/arch/mips/mm/tlbex.c 2005-08-28 11:12:20.587835288 +0200
++++ linux-2.6.12.5-brcm/arch/mips/mm/tlbex.c 2005-11-07 01:12:51.851811500 +0100
@@ -851,6 +851,8 @@
case CPU_4KSC:
case CPU_20KC:
tlbw(p);
break;
-diff -Nur linux-2.6.12.5/arch/mips/pci/Makefile linux-2.6.12.5-brcm/arch/mips/pci/Makefile
---- linux-2.6.12.5/arch/mips/pci/Makefile 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/arch/mips/pci/Makefile 2005-08-28 16:41:44.565297816 +0200
-@@ -18,6 +18,7 @@
- obj-$(CONFIG_MIPS_TX3927) += ops-jmr3927.o
- obj-$(CONFIG_PCI_VR41XX) += ops-vr41xx.o pci-vr41xx.o
- obj-$(CONFIG_NEC_CMBVR4133) += fixup-vr4133.o
-+obj-$(CONFIG_BCM947XX) += ops-sb.o fixup-bcm47xx.o pci-bcm47xx.o
-
- #
- # These are still pretty much in the old state, watch, go blind.
diff -Nur linux-2.6.12.5/arch/mips/pci/fixup-bcm47xx.c linux-2.6.12.5-brcm/arch/mips/pci/fixup-bcm47xx.c
--- linux-2.6.12.5/arch/mips/pci/fixup-bcm47xx.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/pci/fixup-bcm47xx.c 2005-08-28 11:12:20.611831640 +0200
++++ linux-2.6.12.5-brcm/arch/mips/pci/fixup-bcm47xx.c 2005-11-07 01:12:51.851811500 +0100
@@ -0,0 +1,23 @@
+#include <linux/init.h>
+#include <linux/pci.h>
+struct pci_fixup pcibios_fixups[] __initdata = {
+ { 0 }
+};
+diff -Nur linux-2.6.12.5/arch/mips/pci/Makefile linux-2.6.12.5-brcm/arch/mips/pci/Makefile
+--- linux-2.6.12.5/arch/mips/pci/Makefile 2005-08-15 02:20:18.000000000 +0200
++++ linux-2.6.12.5-brcm/arch/mips/pci/Makefile 2005-11-07 01:12:51.851811500 +0100
+@@ -18,6 +18,7 @@
+ obj-$(CONFIG_MIPS_TX3927) += ops-jmr3927.o
+ obj-$(CONFIG_PCI_VR41XX) += ops-vr41xx.o pci-vr41xx.o
+ obj-$(CONFIG_NEC_CMBVR4133) += fixup-vr4133.o
++obj-$(CONFIG_BCM947XX) += ops-sb.o fixup-bcm47xx.o pci-bcm47xx.o
+
+ #
+ # These are still pretty much in the old state, watch, go blind.
diff -Nur linux-2.6.12.5/arch/mips/pci/ops-sb.c linux-2.6.12.5-brcm/arch/mips/pci/ops-sb.c
--- linux-2.6.12.5/arch/mips/pci/ops-sb.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/pci/ops-sb.c 2005-08-28 11:12:20.612831488 +0200
++++ linux-2.6.12.5-brcm/arch/mips/pci/ops-sb.c 2005-11-07 01:12:51.851811500 +0100
@@ -0,0 +1,44 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+extern void *sbh;
+//extern spinlock_t bcm47xx_sbh_lock;
+
-+static int
-+sb_pci_read_config(struct pci_bus *bus, unsigned int devfn,
-+ int reg, int size, u32 *val)
-+{
-+ //unsigned long flags;
-+ int ret;
-+
-+
-+ //spin_lock_irqsave(&sbh_lock, flags);
-+ ret = sbpci_read_config(sbh, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), reg, val, size);
-+ //spin_unlock_irqrestore(&sbh_lock, flags);
-+
-+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-+}
-+
-+static int
-+sb_pci_write_config(struct pci_bus *bus, unsigned int devfn,
-+ int reg, int size, u32 val)
-+{
-+// unsigned long flags;
-+ int ret;
-+
-+// spin_lock_irqsave(&sbh_lock, flags);
-+ ret = sbpci_write_config(sbh, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), reg, &val, size);
-+// spin_unlock_irqrestore(&sbh_lock, flags);
-+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-+}
-+
-+struct pci_ops sb_pci_ops = {
-+ .read = sb_pci_read_config,
-+ .write = sb_pci_write_config,
-+};
-diff -Nur linux-2.6.12.5/arch/mips/pci/pci-bcm47xx.c linux-2.6.12.5-brcm/arch/mips/pci/pci-bcm47xx.c
---- linux-2.6.12.5/arch/mips/pci/pci-bcm47xx.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/arch/mips/pci/pci-bcm47xx.c 2005-08-28 11:12:20.612831488 +0200
-@@ -0,0 +1,61 @@
-+#include <linux/init.h>
-+#include <linux/pci.h>
-+#include <linux/types.h>
-+
-+#include <asm/cpu.h>
-+#include <asm/io.h>
-+
-+#include <typedefs.h>
-+#include <sbconfig.h>
-+
-+extern struct pci_ops sb_pci_ops;
-+
-+static struct resource sb_pci_mem_resource = {
-+ .name = "SB PCI Memory resources",
-+ .start = SB_ENUM_BASE,
-+ .end = SB_ENUM_LIM - 1,
-+ .flags = IORESOURCE_MEM,
-+};
-+
-+static struct resource sb_pci_io_resource = {
-+ .name = "SB PCI I/O resources",
-+ .start = 0x100,
-+ .end = 0x1FF,
-+ .flags = IORESOURCE_IO,
-+};
-+
-+static struct pci_controller bcm47xx_sb_pci_controller = {
-+ .pci_ops = &sb_pci_ops,
-+ .mem_resource = &sb_pci_mem_resource,
-+ .io_resource = &sb_pci_io_resource,
-+};
-+
-+static struct resource ext_pci_mem_resource = {
-+ .name = "Ext PCI Memory resources",
-+ .start = SB_PCI_DMA,
-+// .end = 0x7FFFFFFF,
-+ .end = 0x40FFFFFF,
-+ .flags = IORESOURCE_MEM,
-+};
-+
-+static struct resource ext_pci_io_resource = {
-+ .name = "Ext PCI I/O resources",
-+ .start = 0x200,
-+ .end = 0x2FF,
-+ .flags = IORESOURCE_IO,
-+};
-+
-+static struct pci_controller bcm47xx_ext_pci_controller = {
-+ .pci_ops = &sb_pci_ops,
-+ .mem_resource = &ext_pci_mem_resource,
-+ .io_resource = &ext_pci_io_resource,
-+};
-+
-+static int __init bcm47xx_pci_init(void)
-+{
-+ register_pci_controller(&bcm47xx_sb_pci_controller);
-+ register_pci_controller(&bcm47xx_ext_pci_controller);
-+ return 0;
-+}
-+
-+early_initcall(bcm47xx_pci_init);
-diff -Nur linux-2.6.12.5/arch/mips/pci/pci.c linux-2.6.12.5-brcm/arch/mips/pci/pci.c
---- linux-2.6.12.5/arch/mips/pci/pci.c 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/arch/mips/pci/pci.c 2005-08-28 11:12:20.629828904 +0200
-@@ -238,7 +238,8 @@
- if (dev->resource[i].flags & IORESOURCE_IO)
- offset = hose->io_offset;
- else if (dev->resource[i].flags & IORESOURCE_MEM)
-- offset = hose->mem_offset;
-+ offset = 0x26000000;
-+ // offset = hose->mem_offset;
-
- dev->resource[i].start += offset;
- dev->resource[i].end += offset;
-diff -Nur linux-2.6.12.5/drivers/mtd/maps/Kconfig linux-2.6.12.5-brcm/drivers/mtd/maps/Kconfig
---- linux-2.6.12.5/drivers/mtd/maps/Kconfig 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/drivers/mtd/maps/Kconfig 2005-08-28 16:21:23.595930936 +0200
-@@ -357,6 +357,12 @@
- Mapping for the Flaga digital module. If you don't have one, ignore
- this setting.
-
-+config MTD_BCM47XX
-+ tristate "BCM47xx flash device"
-+ depends on MIPS && MTD_CFI && BCM947XX
-+ help
-+ Support for the flash chips on the BCM947xx board.
-+
- config MTD_BEECH
- tristate "CFI Flash device mapped on IBM 405LP Beech"
- depends on MTD_CFI && PPC32 && 40x && BEECH
-diff -Nur linux-2.6.12.5/drivers/mtd/maps/Makefile linux-2.6.12.5-brcm/drivers/mtd/maps/Makefile
---- linux-2.6.12.5/drivers/mtd/maps/Makefile 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/drivers/mtd/maps/Makefile 2005-08-28 11:12:20.666823280 +0200
-@@ -31,6 +31,7 @@
- obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
- obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
- obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
-+obj-$(CONFIG_MTD_BCM47XX) += bcm47xx-flash.o
- obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
- obj-$(CONFIG_MTD_IPAQ) += ipaq-flash.o
- obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
-diff -Nur linux-2.6.12.5/drivers/mtd/maps/bcm47xx-flash.c linux-2.6.12.5-brcm/drivers/mtd/maps/bcm47xx-flash.c
---- linux-2.6.12.5/drivers/mtd/maps/bcm47xx-flash.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.12.5-brcm/drivers/mtd/maps/bcm47xx-flash.c 2005-09-04 04:50:19.246786848 +0200
-@@ -0,0 +1,249 @@
-+/*
-+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
-+ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
-+ *
-+ * original functions for finding root filesystem from Mike Baker
-+ *
-+ * 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 2001-2003, 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: bcm47xx-flash.c,v 1.1 2004/10/21 07:18:31 jolt Exp $
-+ *
-+ * Flash mapping for BCM947XX boards
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <asm/io.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/config.h>
-+#include <typedefs.h>
-+#include <bcmutils.h>
-+#include <bcmnvram.h>
-+#include <trxhdr.h>
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t size);
-+#endif
-+
-+#define CFE_SIZE 1024*384
-+#define NVRAM_SIZE 1024*128
-+
-+#define WINDOW_ADDR 0x1c000000
-+#define WINDOW_SIZE (0x400000*2)
-+#define BUSWIDTH 2
-+
-+static struct mtd_info *bcm947xx_mtd;
-+
-+static void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-+{
-+#define MIPS_MEMCPY_ALIGN 4
-+ map_word ret;
-+ ssize_t transfer;
-+ ssize_t done = 0;
-+ if ((len >= MIPS_MEMCPY_ALIGN) && (!(from & (MIPS_MEMCPY_ALIGN - 1))) && (!(((unsigned int)to & (MIPS_MEMCPY_ALIGN - 1))))) {
-+ done = len & ~(MIPS_MEMCPY_ALIGN - 1);
-+ memcpy_fromio(to, map->virt + from, done);
-+ }
-+ while (done < len) {
-+ ret = map->read(map, from + done);
-+ transfer = len - done;
-+ if (transfer > map->bankwidth)
-+ transfer = map->bankwidth;
-+ memcpy((void *)((unsigned long)to + done), &ret.x[0], transfer);
-+ done += transfer;
-+ }
-+}
-+
-+static struct map_info bcm947xx_map = {
-+ name: "Physically mapped flash",
-+ size: WINDOW_SIZE,
-+ bankwidth: BUSWIDTH,
-+ phys: WINDOW_ADDR,
-+};
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+
-+static struct mtd_partition bcm947xx_parts[] = {
-+ { name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
-+ { name: "linux", offset: 0, size: 0, },
-+ { name: "rootfs", offset: 0, size: 0, },
-+ { name: "nvram", offset: 0, size: 0, },
-+ { name: "OpenWrt", offset: 0, size: 0, },
-+ { name: NULL, },
-+};
-+
-+static int __init
-+find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part)
-+{
-+ struct trx_header *trx;
-+ unsigned char buf[512];
-+ int off;
-+ size_t len;
-+
-+ trx = (struct trx_header *) buf;
-+
-+ for (off = (512*1024); off < size; off += mtd->erasesize) {
-+ memset(buf, 0xe5, sizeof(buf));
-+
-+ /*
-+ * Read into buffer
-+ */
-+ if (MTD_READ(mtd, off, sizeof(buf), &len, buf) ||
-+ len != sizeof(buf))
-+ continue;
-+
-+ /* found a TRX header */
-+ if (le32_to_cpu(trx->magic) == TRX_MAGIC) {
-+ part->offset = le32_to_cpu(trx->offsets[2]) ? :
-+ le32_to_cpu(trx->offsets[1]);
-+ part->size = le32_to_cpu(trx->len);
-+
-+ part->size -= part->offset;
-+ part->offset += off;
-+
-+ goto done;
-+ }
-+ }
-+
-+ printk(KERN_NOTICE
-+ "%s: Couldn't find root filesystem\n",
-+ mtd->name);
-+ return -1;
-+
-+ done:
-+ return part->size;
-+}
-+
-+struct mtd_partition * __init
-+init_mtd_partitions(struct mtd_info *mtd, size_t size)
-+{
-+
-+ /* boot loader */
-+ bcm947xx_parts[0].offset = 0;
-+ bcm947xx_parts[0].size = CFE_SIZE;
-+
-+ /* nvram (old config partition) */
-+ bcm947xx_parts[3].offset = bcm947xx_parts[0].size;
-+ bcm947xx_parts[3].size = NVRAM_SIZE;
-+
-+ /* Size linux (kernel and rootfs) */
-+ bcm947xx_parts[1].offset = bcm947xx_parts[0].size + bcm947xx_parts[3].size;
-+ bcm947xx_parts[1].size = size - NVRAM_SIZE - bcm947xx_parts[0].size - bcm947xx_parts[3].size;
-+
-+ /* Find and size rootfs */
-+ if (find_root(mtd,size,&bcm947xx_parts[2])==0) {
-+ /* entirely jffs2 */
-+ bcm947xx_parts[2].size = bcm947xx_parts[3].offset - bcm947xx_parts[2].offset;
-+ bcm947xx_parts[4].name = NULL;
-+ } else {
-+ /* legacy setup */
-+ /* calculate leftover flash, and assign it to the jffs2 partition */
-+ bcm947xx_parts[4].offset = bcm947xx_parts[2].offset + bcm947xx_parts[2].size;
-+ if ((bcm947xx_parts[4].offset % mtd->erasesize) > 0) {
-+ bcm947xx_parts[4].offset += mtd->erasesize -
-+ (bcm947xx_parts[4].offset % mtd->erasesize);
-+ bcm947xx_parts[4].size = size - NVRAM_SIZE - bcm947xx_parts[4].offset;
-+ } else {
-+ bcm947xx_parts[4].size = bcm947xx_parts[3].offset - bcm947xx_parts[4].offset;
-+ }
-+ }
-+
-+ return bcm947xx_parts;
-+}
-+
-+EXPORT_SYMBOL(init_mtd_partitions);
-+#endif
-+
-+int __init init_bcm947xx_map(void)
-+{
-+ size_t size;
-+ int ret = 0;
-+#ifdef CONFIG_MTD_PARTITIONS
-+ struct mtd_partition *parts;
-+ int i;
-+#endif
-+
-+ bcm947xx_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+
-+ if (!bcm947xx_map.virt) {
-+ printk("Failed to ioremap\n");
-+ return -EIO;
-+ }
-+ simple_map_init(&bcm947xx_map);
-+
-+ bcm947xx_map.copy_from = bcm947xx_map_copy_from;
-+
-+ if (!(bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map))) {
-+ printk("Failed to do_map_probe\n");
-+ iounmap((void *)bcm947xx_map.virt);
-+ return -ENXIO;
-+ }
-+
-+ bcm947xx_mtd->owner = THIS_MODULE;
-+
-+ size = bcm947xx_mtd->size;
-+
-+ printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", bcm947xx_mtd->size, WINDOW_ADDR);
++static int
++sb_pci_read_config(struct pci_bus *bus, unsigned int devfn,
++ int reg, int size, u32 *val)
++{
++ //unsigned long flags;
++ int ret;
+
-+#ifdef CONFIG_MTD_PARTITIONS
-+ parts = init_mtd_partitions(bcm947xx_mtd, size);
-+ for (i = 0; parts[i].name; i++);
-+ ret = add_mtd_partitions(bcm947xx_mtd, parts, i);
-+ if (ret) {
-+ printk(KERN_ERR "Flash: add_mtd_partitions failed\n");
-+ goto fail;
-+ }
-+#endif
+
-+ return 0;
++ //spin_lock_irqsave(&sbh_lock, flags);
++ ret = sbpci_read_config(sbh, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), reg, val, size);
++ //spin_unlock_irqrestore(&sbh_lock, flags);
+
-+ fail:
-+ if (bcm947xx_mtd)
-+ map_destroy(bcm947xx_mtd);
-+ if (bcm947xx_map.map_priv_1)
-+ iounmap((void *) bcm947xx_map.map_priv_1);
-+ bcm947xx_map.map_priv_1 = 0;
-+ return ret;
++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
-+void __exit cleanup_bcm947xx_map(void)
-+{
-+#ifdef CONFIG_MTD_PARTITIONS
-+ del_mtd_partitions(bcm947xx_mtd);
-+#endif
-+ map_destroy(bcm947xx_mtd);
-+ iounmap((void *)bcm947xx_map.virt);
-+}
-+
-+module_init(init_bcm947xx_map);
-+module_exit(cleanup_bcm947xx_map);
-diff -Nur linux-2.6.12.5/drivers/net/b44.c linux-2.6.12.5-brcm/drivers/net/b44.c
---- linux-2.6.12.5/drivers/net/b44.c 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/drivers/net/b44.c 2005-08-28 11:12:20.691819480 +0200
-@@ -1,7 +1,8 @@
--/* b44.c: Broadcom 4400 device driver.
-+/* b44.c: Broadcom 4400/47xx device driver.
- *
- * Copyright (C) 2002 David S. Miller (davem@redhat.com)
-- * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
-+ * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi)
-+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
- *
- * Distribute under GPL.
- */
-@@ -78,7 +79,7 @@
- DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
-
- MODULE_AUTHOR("Florian Schirmer, Pekka Pietikainen, David S. Miller");
--MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver");
-+MODULE_DESCRIPTION("Broadcom 4400/47xx 10/100 PCI ethernet driver");
- MODULE_LICENSE("GPL");
- MODULE_VERSION(DRV_MODULE_VERSION);
-
-@@ -93,6 +94,8 @@
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
-+ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4713,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { } /* terminate list with empty entry */
- };
-
-@@ -106,24 +109,13 @@
- static void b44_poll_controller(struct net_device *dev);
- #endif
-
--static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
--{
-- return readl(bp->regs + reg);
--}
--
--static inline void bw32(const struct b44 *bp,
-- unsigned long reg, unsigned long val)
--{
-- writel(val, bp->regs + reg);
--}
--
- static int b44_wait_bit(struct b44 *bp, unsigned long reg,
- u32 bit, unsigned long timeout, const int clear)
- {
- unsigned long i;
-
- for (i = 0; i < timeout; i++) {
-- u32 val = br32(bp, reg);
-+ u32 val = br32(reg);
-
- if (clear && !(val & bit))
- break;
-@@ -154,7 +146,7 @@
-
- static u32 ssb_get_core_rev(struct b44 *bp)
- {
-- return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK);
-+ return (br32(B44_SBIDHIGH) & SBIDHIGH_RC_MASK);
- }
-
- static u32 ssb_pci_setup(struct b44 *bp, u32 cores)
-@@ -165,13 +157,13 @@
- pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, BCM4400_PCI_CORE_ADDR);
- pci_rev = ssb_get_core_rev(bp);
-
-- val = br32(bp, B44_SBINTVEC);
-+ val = br32(B44_SBINTVEC);
- val |= cores;
-- bw32(bp, B44_SBINTVEC, val);
-+ bw32(B44_SBINTVEC, val);
-
-- val = br32(bp, SSB_PCI_TRANS_2);
-+ val = br32(SSB_PCI_TRANS_2);
- val |= SSB_PCI_PREF | SSB_PCI_BURST;
-- bw32(bp, SSB_PCI_TRANS_2, val);
-+ bw32(SSB_PCI_TRANS_2, val);
-
- pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig);
-
-@@ -180,18 +172,18 @@
-
- static void ssb_core_disable(struct b44 *bp)
- {
-- if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET)
-+ if (br32(B44_SBTMSLOW) & SBTMSLOW_RESET)
- return;
-
-- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK));
-+ bw32(B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK));
- b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0);
- b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1);
-- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK |
-+ bw32(B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK |
- SBTMSLOW_REJECT | SBTMSLOW_RESET));
-- br32(bp, B44_SBTMSLOW);
-+ br32(B44_SBTMSLOW);
- udelay(1);
-- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET));
-- br32(bp, B44_SBTMSLOW);
-+ bw32(B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET));
-+ br32(B44_SBTMSLOW);
- udelay(1);
- }
-
-@@ -200,58 +192,65 @@
- u32 val;
-
- ssb_core_disable(bp);
-- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC));
-- br32(bp, B44_SBTMSLOW);
-+ bw32(B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC));
-+ br32(B44_SBTMSLOW);
- udelay(1);
-
- /* Clear SERR if set, this is a hw bug workaround. */
-- if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR)
-- bw32(bp, B44_SBTMSHIGH, 0);
-+ if (br32(B44_SBTMSHIGH) & SBTMSHIGH_SERR)
-+ bw32(B44_SBTMSHIGH, 0);
-
-- val = br32(bp, B44_SBIMSTATE);
-+ val = br32(B44_SBIMSTATE);
- if (val & (SBIMSTATE_IBE | SBIMSTATE_TO))
-- bw32(bp, B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO));
-+ bw32(B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO));
-
-- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC));
-- br32(bp, B44_SBTMSLOW);
-+ bw32(B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC));
-+ br32(B44_SBTMSLOW);
- udelay(1);
-
-- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK));
-- br32(bp, B44_SBTMSLOW);
-+ bw32(B44_SBTMSLOW, (SBTMSLOW_CLOCK));
-+ br32(B44_SBTMSLOW);
- udelay(1);
- }
-
-+static int b44_4713_instance;
-+
- static int ssb_core_unit(struct b44 *bp)
- {
--#if 0
-- u32 val = br32(bp, B44_SBADMATCH0);
-- u32 base;
--
-- type = val & SBADMATCH0_TYPE_MASK;
-- switch (type) {
-- case 0:
-- base = val & SBADMATCH0_BS0_MASK;
-- break;
--
-- case 1:
-- base = val & SBADMATCH0_BS1_MASK;
-- break;
--
-- case 2:
-- default:
-- base = val & SBADMATCH0_BS2_MASK;
-- break;
-- };
--#endif
-- return 0;
-+ if (bp->pdev->device == PCI_DEVICE_ID_BCM4713)
-+ return b44_4713_instance++;
-+ else
-+ return 0;
- }
-
- static int ssb_is_core_up(struct b44 *bp)
- {
-- return ((br32(bp, B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK))
-+ return ((br32(B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK))
- == SBTMSLOW_CLOCK);
- }
-
-+static void __b44_cam_read(struct b44 *bp, unsigned char *data, int index)
++static int
++sb_pci_write_config(struct pci_bus *bus, unsigned int devfn,
++ int reg, int size, u32 val)
+{
-+ u32 val;
-+
-+ bw32(B44_CAM_CTRL, (CAM_CTRL_READ |
-+ (index << CAM_CTRL_INDEX_SHIFT)));
++// unsigned long flags;
++ int ret;
+
-+ b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
++// spin_lock_irqsave(&sbh_lock, flags);
++ ret = sbpci_write_config(sbh, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), reg, &val, size);
++// spin_unlock_irqrestore(&sbh_lock, flags);
++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++}
+
-+ val = br32(B44_CAM_DATA_LO);
++struct pci_ops sb_pci_ops = {
++ .read = sb_pci_read_config,
++ .write = sb_pci_write_config,
++};
+diff -Nur linux-2.6.12.5/arch/mips/pci/pci-bcm47xx.c linux-2.6.12.5-brcm/arch/mips/pci/pci-bcm47xx.c
+--- linux-2.6.12.5/arch/mips/pci/pci-bcm47xx.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.12.5-brcm/arch/mips/pci/pci-bcm47xx.c 2005-11-07 01:12:51.851811500 +0100
+@@ -0,0 +1,61 @@
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/types.h>
+
-+ data[2] = (val >> 24) & 0xFF;
-+ data[3] = (val >> 16) & 0xFF;
-+ data[4] = (val >> 8) & 0xFF;
-+ data[5] = (val >> 0) & 0xFF;
++#include <asm/cpu.h>
++#include <asm/io.h>
+
-+ val = br32(B44_CAM_DATA_HI);
-+
-+ data[0] = (val >> 8) & 0xFF;
-+ data[1] = (val >> 0) & 0xFF;
-+}
++#include <typedefs.h>
++#include <sbconfig.h>
+
- static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
- {
- u32 val;
-@@ -260,19 +259,19 @@
- val |= ((u32) data[3]) << 16;
- val |= ((u32) data[4]) << 8;
- val |= ((u32) data[5]) << 0;
-- bw32(bp, B44_CAM_DATA_LO, val);
-+ bw32(B44_CAM_DATA_LO, val);
- val = (CAM_DATA_HI_VALID |
- (((u32) data[0]) << 8) |
- (((u32) data[1]) << 0));
-- bw32(bp, B44_CAM_DATA_HI, val);
-- bw32(bp, B44_CAM_CTRL, (CAM_CTRL_WRITE |
-+ bw32(B44_CAM_DATA_HI, val);
-+ bw32(B44_CAM_CTRL, (CAM_CTRL_WRITE |
- (index << CAM_CTRL_INDEX_SHIFT)));
- b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
- }
-
- static inline void __b44_disable_ints(struct b44 *bp)
- {
-- bw32(bp, B44_IMASK, 0);
-+ bw32(B44_IMASK, 0);
- }
-
- static void b44_disable_ints(struct b44 *bp)
-@@ -280,34 +279,40 @@
- __b44_disable_ints(bp);
-
- /* Flush posted writes. */
-- br32(bp, B44_IMASK);
-+ br32(B44_IMASK);
- }
-
- static void b44_enable_ints(struct b44 *bp)
- {
-- bw32(bp, B44_IMASK, bp->imask);
-+ bw32(B44_IMASK, bp->imask);
- }
-
- static int b44_readphy(struct b44 *bp, int reg, u32 *val)
- {
- int err;
-
-- bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
-- bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
-+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
-+ return 0;
++extern struct pci_ops sb_pci_ops;
+
-+ bw32(B44_EMAC_ISTAT, EMAC_INT_MII);
-+ bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START |
- (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) |
- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
- (reg << MDIO_DATA_RA_SHIFT) |
- (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT)));
- err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
-- *val = br32(bp, B44_MDIO_DATA) & MDIO_DATA_DATA;
-+ *val = br32(B44_MDIO_DATA) & MDIO_DATA_DATA;
-
- return err;
- }
-
- static int b44_writephy(struct b44 *bp, int reg, u32 val)
- {
-- bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
-- bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
-+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
-+ return 0;
++static struct resource sb_pci_mem_resource = {
++ .name = "SB PCI Memory resources",
++ .start = SB_ENUM_BASE,
++ .end = SB_ENUM_LIM - 1,
++ .flags = IORESOURCE_MEM,
++};
+
-+ bw32(B44_EMAC_ISTAT, EMAC_INT_MII);
-+ bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START |
- (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) |
- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
- (reg << MDIO_DATA_RA_SHIFT) |
-@@ -344,6 +349,9 @@
- u32 val;
- int err;
-
-+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
-+ return 0;
++static struct resource sb_pci_io_resource = {
++ .name = "SB PCI I/O resources",
++ .start = 0x100,
++ .end = 0x1FF,
++ .flags = IORESOURCE_IO,
++};
+
- err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
- if (err)
- return err;
-@@ -367,20 +375,20 @@
- bp->flags &= ~(B44_FLAG_TX_PAUSE | B44_FLAG_RX_PAUSE);
- bp->flags |= pause_flags;
-
-- val = br32(bp, B44_RXCONFIG);
-+ val = br32(B44_RXCONFIG);
- if (pause_flags & B44_FLAG_RX_PAUSE)
- val |= RXCONFIG_FLOW;
- else
- val &= ~RXCONFIG_FLOW;
-- bw32(bp, B44_RXCONFIG, val);
-+ bw32(B44_RXCONFIG, val);
-
-- val = br32(bp, B44_MAC_FLOW);
-+ val = br32(B44_MAC_FLOW);
- if (pause_flags & B44_FLAG_TX_PAUSE)
- val |= (MAC_FLOW_PAUSE_ENAB |
- (0xc0 & MAC_FLOW_RX_HI_WATER));
- else
- val &= ~MAC_FLOW_PAUSE_ENAB;
-- bw32(bp, B44_MAC_FLOW, val);
-+ bw32(B44_MAC_FLOW, val);
- }
-
- static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote)
-@@ -414,6 +422,9 @@
- u32 val;
- int err;
-
-+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
-+ return 0;
++static struct pci_controller bcm47xx_sb_pci_controller = {
++ .pci_ops = &sb_pci_ops,
++ .mem_resource = &sb_pci_mem_resource,
++ .io_resource = &sb_pci_io_resource,
++};
+
- if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
- goto out;
- if ((err = b44_writephy(bp, B44_MII_ALEDCTRL,
-@@ -476,11 +487,11 @@
-
- val = &bp->hw_stats.tx_good_octets;
- for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL) {
-- *val++ += br32(bp, reg);
-+ *val++ += br32(reg);
- }
- val = &bp->hw_stats.rx_good_octets;
- for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) {
-- *val++ += br32(bp, reg);
-+ *val++ += br32(reg);
- }
- }
-
-@@ -506,6 +517,19 @@
- {
- u32 bmsr, aux;
-
-+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
-+ bp->flags |= B44_FLAG_100_BASE_T;
-+ bp->flags |= B44_FLAG_FULL_DUPLEX;
-+ if (!netif_carrier_ok(bp->dev)) {
-+ u32 val = br32(B44_TX_CTRL);
-+ val |= TX_CTRL_DUPLEX;
-+ bw32(B44_TX_CTRL, val);
-+ netif_carrier_on(bp->dev);
-+ b44_link_report(bp);
-+ }
-+ return;
-+ }
++static struct resource ext_pci_mem_resource = {
++ .name = "Ext PCI Memory resources",
++ .start = SB_PCI_DMA,
++// .end = 0x7FFFFFFF,
++ .end = 0x40FFFFFF,
++ .flags = IORESOURCE_MEM,
++};
+
- if (!b44_readphy(bp, MII_BMSR, &bmsr) &&
- !b44_readphy(bp, B44_MII_AUXCTRL, &aux) &&
- (bmsr != 0xffff)) {
-@@ -520,14 +544,14 @@
-
- if (!netif_carrier_ok(bp->dev) &&
- (bmsr & BMSR_LSTATUS)) {
-- u32 val = br32(bp, B44_TX_CTRL);
-+ u32 val = br32(B44_TX_CTRL);
- u32 local_adv, remote_adv;
-
- if (bp->flags & B44_FLAG_FULL_DUPLEX)
- val |= TX_CTRL_DUPLEX;
- else
- val &= ~TX_CTRL_DUPLEX;
-- bw32(bp, B44_TX_CTRL, val);
-+ bw32(B44_TX_CTRL, val);
-
- if (!(bp->flags & B44_FLAG_FORCE_LINK) &&
- !b44_readphy(bp, MII_ADVERTISE, &local_adv) &&
-@@ -572,7 +596,7 @@
- {
- u32 cur, cons;
-
-- cur = br32(bp, B44_DMATX_STAT) & DMATX_STAT_CDMASK;
-+ cur = br32(B44_DMATX_STAT) & DMATX_STAT_CDMASK;
- cur /= sizeof(struct dma_desc);
-
- /* XXX needs updating when NETIF_F_SG is supported */
-@@ -596,7 +620,7 @@
- TX_BUFFS_AVAIL(bp) > B44_TX_WAKEUP_THRESH)
- netif_wake_queue(bp->dev);
-
-- bw32(bp, B44_GPTIMER, 0);
-+ bw32(B44_GPTIMER, 0);
- }
-
- /* Works like this. This chip writes a 'struct rx_header" 30 bytes
-@@ -713,7 +737,7 @@
- u32 cons, prod;
-
- received = 0;
-- prod = br32(bp, B44_DMARX_STAT) & DMARX_STAT_CDMASK;
-+ prod = br32(B44_DMARX_STAT) & DMARX_STAT_CDMASK;
- prod /= sizeof(struct dma_desc);
- cons = bp->rx_cons;
-
-@@ -792,7 +816,7 @@
- }
-
- bp->rx_cons = cons;
-- bw32(bp, B44_DMARX_PTR, cons * sizeof(struct dma_desc));
-+ bw32(B44_DMARX_PTR, cons * sizeof(struct dma_desc));
-
- return received;
- }
-@@ -856,8 +880,8 @@
-
- spin_lock_irqsave(&bp->lock, flags);
-
-- istat = br32(bp, B44_ISTAT);
-- imask = br32(bp, B44_IMASK);
-+ istat = br32(B44_ISTAT);
-+ imask = br32(B44_IMASK);
-
- /* ??? What the fuck is the purpose of the interrupt mask
- * ??? register if we have to mask it out by hand anyways?
-@@ -877,8 +901,8 @@
- dev->name);
- }
-
-- bw32(bp, B44_ISTAT, istat);
-- br32(bp, B44_ISTAT);
-+ bw32(B44_ISTAT, istat);
-+ br32(B44_ISTAT);
- }
- spin_unlock_irqrestore(&bp->lock, flags);
- return IRQ_RETVAL(handled);
-@@ -965,11 +989,11 @@
-
- wmb();
-
-- bw32(bp, B44_DMATX_PTR, entry * sizeof(struct dma_desc));
-+ bw32(B44_DMATX_PTR, entry * sizeof(struct dma_desc));
- if (bp->flags & B44_FLAG_BUGGY_TXPTR)
-- bw32(bp, B44_DMATX_PTR, entry * sizeof(struct dma_desc));
-+ bw32(B44_DMATX_PTR, entry * sizeof(struct dma_desc));
- if (bp->flags & B44_FLAG_REORDER_BUG)
-- br32(bp, B44_DMATX_PTR);
-+ br32(B44_DMATX_PTR);
-
- if (TX_BUFFS_AVAIL(bp) < 1)
- netif_stop_queue(dev);
-@@ -1137,32 +1161,35 @@
- {
- unsigned long reg;
-
-- bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
-+ bw32(B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
- for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL)
-- br32(bp, reg);
-+ br32(reg);
- for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL)
-- br32(bp, reg);
-+ br32(reg);
- }
-
- /* bp->lock is held. */
- static void b44_chip_reset(struct b44 *bp)
- {
-+ unsigned int sb_clock;
-+
- if (ssb_is_core_up(bp)) {
-- bw32(bp, B44_RCV_LAZY, 0);
-- bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE);
-+ bw32(B44_RCV_LAZY, 0);
-+ bw32(B44_ENET_CTRL, ENET_CTRL_DISABLE);
- b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 100, 1);
-- bw32(bp, B44_DMATX_CTRL, 0);
-+ bw32(B44_DMATX_CTRL, 0);
- bp->tx_prod = bp->tx_cons = 0;
-- if (br32(bp, B44_DMARX_STAT) & DMARX_STAT_EMASK) {
-+ if (br32(B44_DMARX_STAT) & DMARX_STAT_EMASK) {
- b44_wait_bit(bp, B44_DMARX_STAT, DMARX_STAT_SIDLE,
- 100, 0);
- }
-- bw32(bp, B44_DMARX_CTRL, 0);
-+ bw32(B44_DMARX_CTRL, 0);
- bp->rx_prod = bp->rx_cons = 0;
- } else {
-- ssb_pci_setup(bp, (bp->core_unit == 0 ?
-- SBINTVEC_ENET0 :
-- SBINTVEC_ENET1));
-+ if (bp->pdev->device != PCI_DEVICE_ID_BCM4713)
-+ ssb_pci_setup(bp, (bp->core_unit == 0 ?
-+ SBINTVEC_ENET0 :
-+ SBINTVEC_ENET1));
- }
-
- ssb_core_reset(bp);
-@@ -1170,20 +1197,26 @@
- b44_clear_stats(bp);
-
- /* Make PHY accessible. */
-- bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
-- (0x0d & MDIO_CTRL_MAXF_MASK)));
-- br32(bp, B44_MDIO_CTRL);
--
-- if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
-- bw32(bp, B44_ENET_CTRL, ENET_CTRL_EPSEL);
-- br32(bp, B44_ENET_CTRL);
-+ if (bp->pdev->device == PCI_DEVICE_ID_BCM4713)
-+ sb_clock = 100000000; /* 100 MHz */
-+ else
-+ sb_clock = 62500000; /* 62.5 MHz */
-+
-+ bw32(B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
-+ (((sb_clock + (B44_MDC_RATIO / 2)) / B44_MDC_RATIO)
-+ & MDIO_CTRL_MAXF_MASK)));
-+ br32(B44_MDIO_CTRL);
-+
-+ if (!(br32(B44_DEVCTRL) & DEVCTRL_IPP)) {
-+ bw32(B44_ENET_CTRL, ENET_CTRL_EPSEL);
-+ br32(B44_ENET_CTRL);
- bp->flags &= ~B44_FLAG_INTERNAL_PHY;
- } else {
-- u32 val = br32(bp, B44_DEVCTRL);
-+ u32 val = br32(B44_DEVCTRL);
-
- if (val & DEVCTRL_EPR) {
-- bw32(bp, B44_DEVCTRL, (val & ~DEVCTRL_EPR));
-- br32(bp, B44_DEVCTRL);
-+ bw32(B44_DEVCTRL, (val & ~DEVCTRL_EPR));
-+ br32(B44_DEVCTRL);
- udelay(100);
- }
- bp->flags |= B44_FLAG_INTERNAL_PHY;
-@@ -1200,13 +1233,13 @@
- /* bp->lock is held. */
- static void __b44_set_mac_addr(struct b44 *bp)
- {
-- bw32(bp, B44_CAM_CTRL, 0);
-+ bw32(B44_CAM_CTRL, 0);
- if (!(bp->dev->flags & IFF_PROMISC)) {
- u32 val;
-
- __b44_cam_write(bp, bp->dev->dev_addr, 0);
-- val = br32(bp, B44_CAM_CTRL);
-- bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
-+ val = br32(B44_CAM_CTRL);
-+ bw32(B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
- }
- }
-
-@@ -1240,30 +1273,30 @@
- b44_setup_phy(bp);
-
- /* Enable CRC32, set proper LED modes and power on PHY */
-- bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL);
-- bw32(bp, B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT));
-+ bw32(B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL);
-+ bw32(B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT));
-
- /* This sets the MAC address too. */
- __b44_set_rx_mode(bp->dev);
-
- /* MTU + eth header + possible VLAN tag + struct rx_header */
-- bw32(bp, B44_RXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN);
-- bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN);
-+ bw32(B44_RXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN);
-+ bw32(B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN);
-
-- bw32(bp, B44_TX_WMARK, 56); /* XXX magic */
-- bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
-- bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset);
-- bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
-+ bw32(B44_TX_WMARK, 56); /* XXX magic */
-+ bw32(B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
-+ bw32(B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset);
-+ bw32(B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
- (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
-- bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset);
-+ bw32(B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset);
-
-- bw32(bp, B44_DMARX_PTR, bp->rx_pending);
-+ bw32(B44_DMARX_PTR, bp->rx_pending);
- bp->rx_prod = bp->rx_pending;
-
-- bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
-+ bw32(B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
-
-- val = br32(bp, B44_ENET_CTRL);
-- bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
-+ val = br32(B44_ENET_CTRL);
-+ bw32(B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
- }
-
- static int b44_open(struct net_device *dev)
-@@ -1416,11 +1449,11 @@
- int i=0;
- unsigned char zero[6] = {0,0,0,0,0,0};
-
-- val = br32(bp, B44_RXCONFIG);
-+ val = br32(B44_RXCONFIG);
- val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
- if (dev->flags & IFF_PROMISC) {
- val |= RXCONFIG_PROMISC;
-- bw32(bp, B44_RXCONFIG, val);
-+ bw32(B44_RXCONFIG, val);
- } else {
- __b44_set_mac_addr(bp);
-
-@@ -1432,9 +1465,9 @@
- for(;i<64;i++) {
- __b44_cam_write(bp, zero, i);
- }
-- bw32(bp, B44_RXCONFIG, val);
-- val = br32(bp, B44_CAM_CTRL);
-- bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
-+ bw32(B44_RXCONFIG, val);
-+ val = br32(B44_CAM_CTRL);
-+ bw32(B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
- }
- }
-
-@@ -1704,19 +1737,41 @@
- {
- u8 eeprom[128];
- int err;
-+ unsigned long flags;
-
-- err = b44_read_eeprom(bp, &eeprom[0]);
-- if (err)
-- goto out;
--
-- bp->dev->dev_addr[0] = eeprom[79];
-- bp->dev->dev_addr[1] = eeprom[78];
-- bp->dev->dev_addr[2] = eeprom[81];
-- bp->dev->dev_addr[3] = eeprom[80];
-- bp->dev->dev_addr[4] = eeprom[83];
-- bp->dev->dev_addr[5] = eeprom[82];
--
-- bp->phy_addr = eeprom[90] & 0x1f;
-+ if (bp->pdev->device == PCI_DEVICE_ID_BCM4713) {
-+ /*
-+ * BCM47xx boards don't have a EEPROM. The MAC is stored in
-+ * a NVRAM area somewhere in the flash memory. As we don't
-+ * know the location and/or the format of the NVRAM area
-+ * here, we simply rely on the bootloader to write the
-+ * MAC into the CAM.
-+ */
-+ spin_lock_irqsave(&bp->lock, flags);
-+ __b44_cam_read(bp, bp->dev->dev_addr, 0);
-+ spin_unlock_irqrestore(&bp->lock, flags);
++static struct resource ext_pci_io_resource = {
++ .name = "Ext PCI I/O resources",
++ .start = 0x200,
++ .end = 0x2FF,
++ .flags = IORESOURCE_IO,
++};
+
-+ /*
-+ * BCM47xx boards don't have a PHY. Usually there is a switch
-+ * chip with multiple PHYs connected to the PHY port.
-+ */
-+ bp->phy_addr = B44_PHY_ADDR_NO_PHY;
-+ bp->dma_offset = 0;
-+ } else {
-+ err = b44_read_eeprom(bp, &eeprom[0]);
-+ if (err)
-+ return err;
-+
-+ bp->dev->dev_addr[0] = eeprom[79];
-+ bp->dev->dev_addr[1] = eeprom[78];
-+ bp->dev->dev_addr[2] = eeprom[81];
-+ bp->dev->dev_addr[3] = eeprom[80];
-+ bp->dev->dev_addr[4] = eeprom[83];
-+ bp->dev->dev_addr[5] = eeprom[82];
-+
-+ bp->phy_addr = eeprom[90] & 0x1f;
-+ bp->dma_offset = SB_PCI_DMA;
-+ }
-
- /* With this, plus the rx_header prepended to the data by the
- * hardware, we'll land the ethernet header on a 2-byte boundary.
-@@ -1726,13 +1781,12 @@
- bp->imask = IMASK_DEF;
-
- bp->core_unit = ssb_core_unit(bp);
-- bp->dma_offset = SB_PCI_DMA;
-
- /* XXX - really required?
- bp->flags |= B44_FLAG_BUGGY_TXPTR;
- */
--out:
-- return err;
++static struct pci_controller bcm47xx_ext_pci_controller = {
++ .pci_ops = &sb_pci_ops,
++ .mem_resource = &ext_pci_mem_resource,
++ .io_resource = &ext_pci_io_resource,
++};
+
++static int __init bcm47xx_pci_init(void)
++{
++ register_pci_controller(&bcm47xx_sb_pci_controller);
++ register_pci_controller(&bcm47xx_ext_pci_controller);
+ return 0;
- }
-
- static int __devinit b44_init_one(struct pci_dev *pdev,
-@@ -1810,7 +1864,7 @@
-
- spin_lock_init(&bp->lock);
-
-- bp->regs = ioremap(b44reg_base, b44reg_len);
-+ bp->regs = (unsigned long) ioremap(b44reg_base, b44reg_len);
- if (bp->regs == 0UL) {
- printk(KERN_ERR PFX "Cannot map device registers, "
- "aborting.\n");
-@@ -1871,7 +1925,8 @@
-
- pci_save_state(bp->pdev);
-
-- printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
-+ printk(KERN_INFO "%s: Broadcom %s 10/100BaseT Ethernet ", dev->name,
-+ (pdev->device == PCI_DEVICE_ID_BCM4713) ? "47xx" : "4400");
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- i == 5 ? '\n' : ':');
-@@ -1879,7 +1934,7 @@
- return 0;
-
- err_out_iounmap:
-- iounmap(bp->regs);
-+ iounmap((void *) bp->regs);
-
- err_out_free_dev:
- free_netdev(dev);
-@@ -1901,7 +1956,7 @@
- struct b44 *bp = netdev_priv(dev);
-
- unregister_netdev(dev);
-- iounmap(bp->regs);
-+ iounmap((void *) bp->regs);
- free_netdev(dev);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-diff -Nur linux-2.6.12.5/drivers/net/b44.h linux-2.6.12.5-brcm/drivers/net/b44.h
---- linux-2.6.12.5/drivers/net/b44.h 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/drivers/net/b44.h 2005-08-28 11:12:20.694819024 +0200
-@@ -292,6 +292,9 @@
- #define SSB_PCI_MASK1 0xfc000000
- #define SSB_PCI_MASK2 0xc0000000
-
-+#define br32(REG) readl(bp->regs + (REG))
-+#define bw32(REG,VAL) writel((VAL), bp->regs + (REG))
++}
+
- /* 4400 PHY registers */
- #define B44_MII_AUXCTRL 24 /* Auxiliary Control */
- #define MII_AUXCTRL_DUPLEX 0x0001 /* Full Duplex */
-@@ -345,6 +348,8 @@
- };
-
- #define B44_MCAST_TABLE_SIZE 32
-+#define B44_PHY_ADDR_NO_PHY 30
-+#define B44_MDC_RATIO 5000000
-
- /* SW copy of device statistics, kept up to date by periodic timer
- * which probes HW values. Must have same relative layout as HW
-@@ -410,7 +415,7 @@
- struct net_device_stats stats;
- struct b44_hw_stats hw_stats;
-
-- void __iomem *regs;
-+ unsigned long regs;
- struct pci_dev *pdev;
- struct net_device *dev;
++early_initcall(bcm47xx_pci_init);
+diff -Nur linux-2.6.12.5/arch/mips/pci/pci.c linux-2.6.12.5-brcm/arch/mips/pci/pci.c
+--- linux-2.6.12.5/arch/mips/pci/pci.c 2005-08-15 02:20:18.000000000 +0200
++++ linux-2.6.12.5-brcm/arch/mips/pci/pci.c 2005-11-07 01:12:51.851811500 +0100
+@@ -238,7 +238,8 @@
+ if (dev->resource[i].flags & IORESOURCE_IO)
+ offset = hose->io_offset;
+ else if (dev->resource[i].flags & IORESOURCE_MEM)
+- offset = hose->mem_offset;
++ offset = 0x26000000;
++ // offset = hose->mem_offset;
+ dev->resource[i].start += offset;
+ dev->resource[i].end += offset;
diff -Nur linux-2.6.12.5/include/asm-mips/bootinfo.h linux-2.6.12.5-brcm/include/asm-mips/bootinfo.h
--- linux-2.6.12.5/include/asm-mips/bootinfo.h 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/include/asm-mips/bootinfo.h 2005-08-28 11:12:20.695818872 +0200
++++ linux-2.6.12.5-brcm/include/asm-mips/bootinfo.h 2005-11-07 01:12:51.851811500 +0100
@@ -213,6 +213,12 @@
#define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */
#define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */
const char *get_system_type(void);
diff -Nur linux-2.6.12.5/include/asm-mips/cpu.h linux-2.6.12.5-brcm/include/asm-mips/cpu.h
--- linux-2.6.12.5/include/asm-mips/cpu.h 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/include/asm-mips/cpu.h 2005-08-28 11:12:20.695818872 +0200
++++ linux-2.6.12.5-brcm/include/asm-mips/cpu.h 2005-11-07 01:12:51.851811500 +0100
@@ -87,6 +87,13 @@
#define PRID_IMP_SR71000 0x0400
* ISA Level encodings
diff -Nur linux-2.6.12.5/include/asm-mips/mipsregs.h linux-2.6.12.5-brcm/include/asm-mips/mipsregs.h
--- linux-2.6.12.5/include/asm-mips/mipsregs.h 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/include/asm-mips/mipsregs.h 2005-08-28 11:12:20.722814768 +0200
++++ linux-2.6.12.5-brcm/include/asm-mips/mipsregs.h 2005-11-07 01:12:51.855811750 +0100
@@ -790,10 +790,18 @@
#define read_c0_config1() __read_32bit_c0_register($16, 1)
#define read_c0_config2() __read_32bit_c0_register($16, 2)
* The WatchLo register. There may be upto 8 of them.
diff -Nur linux-2.6.12.5/include/linux/init.h linux-2.6.12.5-brcm/include/linux/init.h
--- linux-2.6.12.5/include/linux/init.h 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/include/linux/init.h 2005-08-28 11:12:20.723814616 +0200
++++ linux-2.6.12.5-brcm/include/linux/init.h 2005-11-07 01:12:51.855811750 +0100
@@ -86,6 +86,8 @@
static initcall_t __initcall_##fn __attribute_used__ \
__attribute__((__section__(".initcall" level ".init"))) = fn
#define arch_initcall(fn) __define_initcall("3",fn)
diff -Nur linux-2.6.12.5/include/linux/pci_ids.h linux-2.6.12.5-brcm/include/linux/pci_ids.h
--- linux-2.6.12.5/include/linux/pci_ids.h 2005-08-15 02:20:18.000000000 +0200
-+++ linux-2.6.12.5-brcm/include/linux/pci_ids.h 2005-08-28 11:12:20.726814160 +0200
++++ linux-2.6.12.5-brcm/include/linux/pci_ids.h 2005-11-07 01:12:51.855811750 +0100
@@ -2110,6 +2110,7 @@
#define PCI_DEVICE_ID_TIGON3_5901_2 0x170e
#define PCI_DEVICE_ID_BCM4401 0x4401