summaryrefslogtreecommitdiffstats
path: root/package/linux/kernel-source/arch/mips/brcm-boards
diff options
context:
space:
mode:
Diffstat (limited to 'package/linux/kernel-source/arch/mips/brcm-boards')
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/Makefile23
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/Makefile100
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/README.mjn320
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/data.lds1
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/decompress_bunzip2.c758
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/decompress_bunzip2.lds17
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/decompress_bunzip2.lds.in17
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/head.S26
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/vmlinux.lds17
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/vmlinux.lds.in17
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/gpio.c158
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/nvram.c317
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/nvram_linux.c638
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/pcibios.c352
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/perfcntr.c67
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/prom.c41
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/sbmips.c951
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/sbpci.c563
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/setup.c251
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/sflash.c346
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/time.c117
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/generic/Makefile26
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/generic/gdb_hook.c120
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/generic/int-handler.S51
-rw-r--r--package/linux/kernel-source/arch/mips/brcm-boards/generic/irq.c130
25 files changed, 5124 insertions, 0 deletions
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/Makefile b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/Makefile
new file mode 100644
index 000000000..eae8eba49
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/Makefile
@@ -0,0 +1,23 @@
+#
+# Makefile for Broadcom BCM947XX boards
+#
+# Copyright 2004, 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$
+#
+
+O_TARGET := bcm947xx.o
+
+export-objs := nvram_linux.o setup.o
+obj-y := prom.o setup.o time.o sbmips.o sbpci.o pcibios.o perfcntr.o gpio.o
+obj-y += sflash.o nvram.o nvram_linux.o
+
+vpath %.c $(SRCBASE)/shared $(SRCBASE)/shared/nvram
+
+include $(TOPDIR)/Rules.make
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/Makefile b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/Makefile
new file mode 100644
index 000000000..400465326
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/Makefile
@@ -0,0 +1,100 @@
+#
+# Makefile for Broadcom BCM947XX boards
+#
+# 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$
+#
+# Copyright 2004 Manuel Novoa III <mjn3@codepoet.org>
+# Modified to support bzip'd kernels.
+# Of course, it would be better to integrate bunzip capability into CFE.
+#
+
+# Link at 3 MB offset in RAM
+#TEXT_START ?= 0x80300000
+TEXT_START ?= 0x80001000
+BZ_MEM_TOP := 0x81000000
+BZ_TEXT_START := BZ_MEM_TOP-0x4000
+BZ_STACK_TOP := BZ_TEXT_START-4
+
+OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .reginfo -R .note -R .comment -R .mdebug -S
+
+SRCBASE := $(TOPDIR)/../..
+VPATH := $(SRCBASE)/shared
+ASFLAGS += -D__ASSEMBLY__ -I$(SRCBASE)/include -DLOADADDR=$(LOADADDR)
+ASFLAGS += -DBZ_MEM_TOP=$(BZ_MEM_TOP)
+ASFLAGS += -DBZ_TEXT_START=$(BZ_TEXT_START)
+ASFLAGS += -DBZ_STACK_TOP=$(BZ_STACK_TOP)
+CFLAGS += -I$(SRCBASE)/include -DLOADADDR=$(LOADADDR)
+CFLAGS += -DBZ_MEM_TOP=$(BZ_MEM_TOP)
+CFLAGS += -DBZ_TEXT_START=$(BZ_TEXT_START)
+CFLAGS += -DBZ_STACK_TOP=$(BZ_STACK_TOP)
+ifdef CONFIG_MCOUNT
+CFLAGS := $(subst -pg,,$(CFLAGS))
+endif
+CFLAGS += -ffunction-sections $(call check_gcc, -fvtable-gc, )
+SEDFLAGS := s/BZ_TEXT_START/$(BZ_TEXT_START)/;s/BZ_MEM_TOP/$(BZ_MEM_TOP)/;s/TEXT_START/$(TEXT_START)/
+
+SYSTEM ?= $(TOPDIR)/vmlinux
+OBJECTS := head.o data.o
+
+all: bzImage vmlinuz
+
+# Don't build dependencies, this may die if $(CC) isn't gcc
+dep:
+
+# Create a gzipped version named vmlinuz for compatibility
+vmlinuz: piggy
+ gzip -c9 $< > $@
+
+# Our bzImage is a gzip'd binary that decompresses and runs
+# the appended bzip'd kernel.
+bzImage: bzLoaderImage.gz piggz
+ cat bzLoaderImage.gz piggz > $@
+
+bzLoaderImage.gz: bzLoaderImage
+ gzip -nc9 $< > $@
+
+bzLoaderImage: bzLoader
+ $(OBJCOPY) $< $@
+
+bzLoader: vmlinux.lds $(OBJECTS)
+ $(LD) -static --gc-sections -no-warn-mismatch -T vmlinux.lds -o $@ $(OBJECTS)
+
+vmlinux.lds: vmlinux.lds.in Makefile
+ @sed "$(SEDFLAGS)" < $< > $@
+
+piggz: piggy
+ bzip2 -c9 $< > $@
+
+piggy: $(SYSTEM)
+ $(OBJCOPY) $< $@
+
+data.o: data.lds data.image
+ $(LD) -no-warn-mismatch -T data.lds -r -o $@ -b binary data.image -b elf32-tradlittlemips
+
+data.lds:
+ @echo "SECTIONS { .data : { code_start = .; *(.data) code_stop = .; }}" > $@
+
+data.image: decompress_bunzip2.image
+ $(OBJCOPY) $< $@
+
+decompress_bunzip2.image: decompress_bunzip2.lds decompress_bunzip2.o
+ $(LD) -static --gc-sections -no-warn-mismatch -T decompress_bunzip2.lds -o $@ decompress_bunzip2.o
+
+decompress_bunzip2.lds: decompress_bunzip2.lds.in Makefile
+ @sed "$(SEDFLAGS)" < $< > $@
+
+mrproper: clean
+
+clean:
+ rm -f vmlinux vmlinuz piggz piggy *.lds *.o \
+ bzLoader bzLoaderImage bzLoaderImage.gz bzImage \
+ data.lds data.image \
+ decompress_bunzip2.lds decompress_bunzip2.image
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/README.mjn3 b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/README.mjn3
new file mode 100644
index 000000000..0e93e55f9
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/README.mjn3
@@ -0,0 +1,20 @@
+
+FIRST... See the dedication in the decompress_bunzip2.c file as it applies
+here too. Donations to hospice in Toni's memory would be appreciated.
+
+As far as the code goes... the bzImage is just a bzip'd kernel image with
+a small gzip'd decompressor/loader stuck on front. CFE ungzip's the loader
+app which then relocates the bunzip decompressor into higher memory and
+bunzip's the compressed kernel directly from flash. Then the instruction
+cache is flushed (to remove traces of the loader) and the kernel is executed.
+
+Of course, a better approach would be to add bunzip decompression to CFE.
+
+Notes...
+ 1) Instruction cache size and linesize are hardcoded (see the #warning).
+ 2) Currently assumes at least 16M or ram.
+ 3) Thanks to Mike Baker mbm at alt dot org for bouncing ideas back
+ and forth as well as diagnosing the last (icache) bug.
+
+Manuel Novoa III <mjn3@codepoet.org> May 30, 2004
+
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/data.lds b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/data.lds
new file mode 100644
index 000000000..ec48b2dfd
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/data.lds
@@ -0,0 +1 @@
+SECTIONS { .data : { code_start = .; *(.data) code_stop = .; }}
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/decompress_bunzip2.c b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/decompress_bunzip2.c
new file mode 100644
index 000000000..9a120796f
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/decompress_bunzip2.c
@@ -0,0 +1,758 @@
+/* vi: set sw=4 ts=4: */
+/* Small bzip2 deflate implementation, by Rob Landley (rob@landley.net).
+
+ Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
+ which also acknowledges contributions by Mike Burrows, David Wheeler,
+ Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
+ Robert Sedgewick, and Jon L. Bentley.
+
+ This code is licensed under the LGPLv2:
+ LGPL (http://www.gnu.org/copyleft/lgpl.html
+*/
+
+/*
+ Size and speed optimizations by Manuel Novoa III (mjn3@codepoet.org).
+
+ More efficient reading of huffman codes, a streamlined read_bunzip()
+ function, and various other tweaks. In (limited) tests, approximately
+ 20% faster than bzcat on x86 and about 10% faster on arm.
+
+ Note that about 2/3 of the time is spent in read_unzip() reversing
+ the Burrows-Wheeler transformation. Much of that time is delay
+ resulting from cache misses.
+
+ I would ask that anyone benefiting from this work, especially those
+ using it in commercial products, consider making a donation to my local
+ non-profit hospice organization in the name of the woman I loved, who
+ passed away Feb. 12, 2003.
+
+ In memory of Toni W. Hagan
+
+ Hospice of Acadiana, Inc.
+ 2600 Johnston St., Suite 200
+ Lafayette, LA 70503-3240
+
+ Phone (337) 232-1234 or 1-800-738-2226
+ Fax (337) 232-1297
+
+ http://www.hospiceacadiana.com/
+
+ Manuel
+ */
+
+/* May 21, 2004 Manuel Novoa III
+ * Modified to load a bzip'd kernel on the linksys wrt54g.
+ *
+ * May 30, 2004
+ * Further size reduction via inlining and disabling len check code.
+ */
+
+/**********************************************************************/
+
+/* Note... the LED code is specific to the v2.0 (and GS?) unit. */
+#undef ENABLE_LEDS
+/* #define ENABLE_LEDS 1 */
+
+/* Do we want to bother with checking the bzip'd data for errors? */
+#undef ENABLE_BUNZIP_CHECKING
+/* #define ENABLE_BUNZIP_CHECKING 1 */
+
+/**********************************************************************/
+/* #include <bcm4710.h> */
+#define BCM4710_FLASH 0x1fc00000 /* Flash */
+
+#define KSEG0 0x80000000
+#define KSEG1 0xa0000000
+
+#define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
+
+/* The following cache code was taken from the file bcm4710_cache.h
+ * which was necessarily GPL as it was used to build the linksys
+ * kernel for the wrt54g. */
+
+#warning icache [l]size hardcoded
+
+#define icache_size 8192
+#define ic_lsize 16
+
+#define Index_Invalidate_I 0x00
+
+#define cache_unroll(base,op) \
+ __asm__ __volatile__( \
+ ".set noreorder;\n" \
+ ".set mips3;\n" \
+ "cache %1, (%0);\n" \
+ ".set mips0;\n" \
+ ".set reorder\n" \
+ : \
+ : "r" (base), \
+ "i" (op));
+
+static __inline__ void blast_icache(void)
+{
+ unsigned long start = KSEG0;
+ unsigned long end = (start + icache_size);
+
+ while(start < end) {
+ cache_unroll(start,Index_Invalidate_I);
+ start += ic_lsize;
+ }
+}
+
+/**********************************************************************/
+#ifndef INT_MAX
+#define INT_MAX (((1 << 30)-1)*2 + 1)
+#endif
+/**********************************************************************/
+#ifdef ENABLE_BUNZIP_CHECKING
+
+#define REBOOT do {} while (1)
+
+#else
+
+#define REBOOT ((void) 0)
+
+#endif
+/**********************************************************************/
+#ifdef ENABLE_LEDS
+
+#define LED_POWER_ON 0x02 /* OFF == flashing */
+#define LED_DMZ_OFF 0x80
+#define LED_WLAN_OFF 0x01
+
+#define LED_CODE_0 (LED_POWER_ON | LED_DMZ_OFF | LED_WLAN_OFF)
+#define LED_CODE_1 (LED_POWER_ON | LED_DMZ_OFF)
+#define LED_CODE_2 (LED_POWER_ON | LED_WLAN_OFF)
+#define LED_CODE_3 (LED_POWER_ON)
+
+#define SET_LED_ERROR(X) \
+ do { \
+ *(volatile u8*)(KSEG1ADDR(0x18000064))=(X & ~LED_POWER_ON); \
+ *(volatile u8*)(KSEG1ADDR(0x18000068))=0; /* Disable changes */ \
+ REBOOT; \
+ } while (0)
+
+#define SET_LED(X) *(volatile u8*)(KSEG1ADDR(0x18000064))=X;
+
+
+typedef unsigned char u8;
+
+#else
+
+#define SET_LED_ERROR(X) REBOOT
+#define SET_LED(X) ((void)0)
+
+#endif
+
+/**********************************************************************/
+
+/* Constants for huffman coding */
+#define MAX_GROUPS 6
+#define GROUP_SIZE 50 /* 64 would have been more efficient */
+#define MAX_HUFCODE_BITS 20 /* Longest huffman code allowed */
+#define MAX_SYMBOLS 258 /* 256 literals + RUNA + RUNB */
+#define SYMBOL_RUNA 0
+#define SYMBOL_RUNB 1
+
+/* Status return values */
+#define RETVAL_OK 0
+#define RETVAL_LAST_BLOCK (-1)
+#define RETVAL_NOT_BZIP_DATA (-2)
+#define RETVAL_UNEXPECTED_INPUT_EOF (-3)
+#define RETVAL_UNEXPECTED_OUTPUT_EOF (-4)
+#define RETVAL_DATA_ERROR (-5)
+#define RETVAL_OUT_OF_MEMORY (-6)
+#define RETVAL_OBSOLETE_INPUT (-7)
+
+/* Other housekeeping constants */
+#define IOBUF_SIZE 4096
+
+/* This is what we know about each huffman coding group */
+struct group_data {
+ /* We have an extra slot at the end of limit[] for a sentinal value. */
+ int limit[MAX_HUFCODE_BITS+1],base[MAX_HUFCODE_BITS],permute[MAX_SYMBOLS];
+ int minLen, maxLen;
+};
+
+/* Structure holding all the housekeeping data, including IO buffers and
+ memory that persists between calls to bunzip */
+typedef struct {
+ /* State for interrupting output loop */
+ int writeCopies,writePos,writeRunCountdown,writeCount,writeCurrent;
+ /* I/O tracking data (file handles, buffers, positions, etc.) */
+#if defined(ENABLE_BUNZIP_CHECKING)
+ int /*in_fd,out_fd,*/ inbufCount,inbufPos /*,outbufPos*/;
+#else
+ int /*in_fd,out_fd,inbufCount,*/ inbufPos /*,outbufPos*/;
+#endif
+ unsigned char *inbuf /*,*outbuf*/;
+ unsigned int inbufBitCount, inbufBits;
+ /* The CRC values stored in the block header and calculated from the data */
+#ifdef ENABLE_BUNZIP_CHECKING
+ unsigned int crc32Table[256],headerCRC, totalCRC, writeCRC;
+ /* Intermediate buffer and its size (in bytes) */
+ unsigned int *dbuf, dbufSize;
+#else
+ unsigned int *dbuf;
+#endif
+ /* These things are a bit too big to go on the stack */
+ unsigned char selectors[32768]; /* nSelectors=15 bits */
+ struct group_data groups[MAX_GROUPS]; /* huffman coding tables */
+} bunzip_data;
+
+static int get_next_block(bunzip_data *bd);
+
+/**********************************************************************/
+/* Undo burrows-wheeler transform on intermediate buffer to produce output.
+ If start_bunzip was initialized with out_fd=-1, then up to len bytes of
+ data are written to outbuf. Return value is number of bytes written or
+ error (all errors are negative numbers). If out_fd!=-1, outbuf and len
+ are ignored, data is written to out_fd and return is RETVAL_OK or error.
+*/
+
+static __inline__ int read_bunzip(bunzip_data *bd, char *outbuf, int len)
+{
+ const unsigned int *dbuf;
+ int pos,current,previous,gotcount;
+#ifdef ENABLE_LEDS
+ int led_state = LED_CODE_2;
+#endif
+
+ /* If last read was short due to end of file, return last block now */
+ if(bd->writeCount<0) return bd->writeCount;
+
+ gotcount = 0;
+ dbuf=bd->dbuf;
+ pos=bd->writePos;
+ current=bd->writeCurrent;
+
+ /* We will always have pending decoded data to write into the output
+ buffer unless this is the very first call (in which case we haven't
+ huffman-decoded a block into the intermediate buffer yet). */
+
+ if (bd->writeCopies) {
+ /* Inside the loop, writeCopies means extra copies (beyond 1) */
+ --bd->writeCopies;
+ /* Loop outputting bytes */
+ for(;;) {
+#if 0 /* Might want to enable this if passing a limiting size. */
+/* #ifdef ENABLE_BUNZIP_CHECKING */
+ /* If the output buffer is full, snapshot state and return */
+ if(gotcount >= len) {
+ bd->writePos=pos;
+ bd->writeCurrent=current;
+ bd->writeCopies++;
+ return len;
+ }
+#endif
+ /* Write next byte into output buffer, updating CRC */
+ outbuf[gotcount++] = current;
+#ifdef ENABLE_BUNZIP_CHECKING
+ bd->writeCRC=(((bd->writeCRC)<<8)
+ ^bd->crc32Table[((bd->writeCRC)>>24)^current]);
+#endif
+ /* Loop now if we're outputting multiple copies of this byte */
+ if (bd->writeCopies) {
+ --bd->writeCopies;
+ continue;
+ }
+decode_next_byte:
+ if (!bd->writeCount--) break;
+ /* Follow sequence vector to undo Burrows-Wheeler transform */
+ previous=current;
+ pos=dbuf[pos];
+ current=pos&0xff;
+ pos>>=8;
+ /* After 3 consecutive copies of the same byte, the 4th is a repeat
+ count. We count down from 4 instead
+ * of counting up because testing for non-zero is faster */
+ if(--bd->writeRunCountdown) {
+ if(current!=previous) bd->writeRunCountdown=4;
+ } else {
+ /* We have a repeated run, this byte indicates the count */
+ bd->writeCopies=current;
+ current=previous;
+ bd->writeRunCountdown=5;
+ /* Sometimes there are just 3 bytes (run length 0) */
+ if(!bd->writeCopies) goto decode_next_byte;
+ /* Subtract the 1 copy we'd output anyway to get extras */
+ --bd->writeCopies;
+ }
+ }
+#ifdef ENABLE_BUNZIP_CHECKING
+ /* Decompression of this block completed successfully */
+ bd->writeCRC=~bd->writeCRC;
+ bd->totalCRC=((bd->totalCRC<<1) | (bd->totalCRC>>31)) ^ bd->writeCRC;
+ /* If this block had a CRC error, force file level CRC error. */
+ if(bd->writeCRC!=bd->headerCRC) {
+ bd->totalCRC=bd->headerCRC+1;
+ return RETVAL_LAST_BLOCK;
+ }
+#endif
+ }
+
+#ifdef ENABLE_LEDS
+ if (led_state == LED_CODE_2) {
+ led_state = LED_CODE_1;
+ } else {
+ led_state = LED_CODE_2;
+ }
+ SET_LED(led_state);
+#endif
+
+ /* Refill the intermediate buffer by huffman-decoding next block of input */
+ /* (previous is just a convenient unused temp variable here) */
+ previous=get_next_block(bd);
+#ifdef ENABLE_BUNZIP_CHECKING
+ if(previous) {
+ bd->writeCount=previous;
+ return (previous!=RETVAL_LAST_BLOCK) ? previous : gotcount;
+ }
+ bd->writeCRC=0xffffffffUL;
+#else
+ if (previous) return gotcount;
+#endif
+ pos=bd->writePos;
+ current=bd->writeCurrent;
+ goto decode_next_byte;
+}
+
+/**********************************************************************/
+/* WARNING!!! Must be the first function!!! */
+
+void load_and_run(unsigned long ra)
+{
+ int dbuf[900000]; /* Maximum requred */
+ bunzip_data bd;
+
+ unsigned int i;
+#ifdef ENABLE_BUNZIP_CHECKING
+ unsigned int j, c;
+ int r;
+#endif
+ char *p;
+
+#ifdef ENABLE_LEDS
+ *(volatile u8*)(KSEG1ADDR(0x18000068))=0x83; /* Allow all bits to change */
+ SET_LED(LED_CODE_0);
+#endif
+
+/* memset(&bd,0,sizeof(bunzip_data)); */
+ p = (char *) &bd;
+ for (i = 0 ; i < sizeof(bunzip_data) ; i++) {
+ p[i] = 0;
+ }
+
+ /* Find start of flash and adjust for pmon partition. */
+ p = ((char *) KSEG1ADDR(BCM4710_FLASH)) + 0x10000;
+
+ SET_LED(LED_CODE_1);
+ /* Find the start of the bzip'd data. */
+ while ((p[0]!='B') || (p[1]!='Z') || (p[2]!='h') /*|| (p[3]!='9')*/) ++p;
+ SET_LED(LED_CODE_2);
+
+ /* Setup input buffer */
+ bd.inbuf=p+4; /* Skip the "BZh9" header. */
+#ifdef ENABLE_BUNZIP_CHECKING
+ bd.inbufCount=INT_MAX;
+ /* Init the CRC32 table (big endian) */
+ for(i=0;i<256;i++) {
+ c=i<<24;
+ for(j=8;j;j--)
+ c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1);
+ bd.crc32Table[i]=c;
+ }
+
+ bd.dbufSize=900000;
+#endif
+ bd.dbuf=dbuf;
+
+ /* Actually do the bunzip */
+#ifdef ENABLE_BUNZIP_CHECKING
+ r = read_bunzip(&bd, ((char *) LOADADDR), INT_MAX);
+ if (r > 0) {
+ if (bd.headerCRC==bd.totalCRC) {
+ SET_LED(LED_CODE_3);
+ {
+ int code = LED_WLAN_OFF;
+ int i, j;
+ for (j=0 ; j < 4 ; j++) {
+ for (i=0; i<(1<<27) ; i++) {}
+ SET_LED(code);
+ code ^= LED_WLAN_OFF;
+ }
+ }
+ blast_icache();
+ /* Jump to load address */
+ ((void (*)(void)) LOADADDR)();
+ } else {
+ SET_LED_ERROR(LED_CODE_3);
+ }
+ } else {
+ SET_LED_ERROR(LED_CODE_2);
+ }
+#else
+ read_bunzip(&bd, ((char *) LOADADDR), INT_MAX);
+ blast_icache();
+ /* Jump to load address */
+ ((void (*)(void)) LOADADDR)();
+#endif
+}
+
+/**********************************************************************/
+/* Return the next nnn bits of input. All reads from the compressed input
+ are done through this function. All reads are big endian */
+static unsigned int get_bits(bunzip_data *bd, char bits_wanted)
+{
+ unsigned int bits=0;
+
+ /* If we need to get more data from the byte buffer, do so. (Loop getting
+ one byte at a time to enforce endianness and avoid unaligned access.) */
+ while (bd->inbufBitCount<bits_wanted) {
+ /* If we need to read more data from file into byte buffer, do so */
+#ifdef ENABLE_BUNZIP_CHECKING
+ if(bd->inbufPos==bd->inbufCount) {
+ SET_LED_ERROR(LED_CODE_0);
+ }
+#endif
+ /* Avoid 32-bit overflow (dump bit buffer to top of output) */
+ if(bd->inbufBitCount>=24) {
+ bits=bd->inbufBits&((1<<bd->inbufBitCount)-1);
+ bits_wanted-=bd->inbufBitCount;
+ bits<<=bits_wanted;
+ bd->inbufBitCount=0;
+ }
+ /* Grab next 8 bits of input from buffer. */
+ bd->inbufBits=(bd->inbufBits<<8)|bd->inbuf[bd->inbufPos++];
+ bd->inbufBitCount+=8;
+ }
+ /* Calculate result */
+ bd->inbufBitCount-=bits_wanted;
+ bits|=(bd->inbufBits>>bd->inbufBitCount)&((1<<bits_wanted)-1);
+
+ return bits;
+}
+
+/* Unpacks the next block and sets up for the inverse burrows-wheeler step. */
+
+static int get_next_block(bunzip_data *bd)
+{
+ struct group_data *hufGroup;
+#ifdef ENABLE_BUNZIP_CHECKING
+ int dbufCount,nextSym,dbufSize,groupCount,*base,*limit,selector,
+ i,j,k,t,runPos,symCount,symTotal,nSelectors,byteCount[256];
+#else
+ int dbufCount,nextSym,/*dbufSize,*/groupCount,*base,*limit,selector,
+ i,j,k,t,runPos,symCount,symTotal,nSelectors,byteCount[256];
+#endif
+ unsigned char uc, symToByte[256], mtfSymbol[256], *selectors;
+ unsigned int *dbuf,origPtr;
+
+ dbuf=bd->dbuf;
+#ifdef ENABLE_BUNZIP_CHECKING
+ dbufSize=bd->dbufSize;
+#endif
+ selectors=bd->selectors;
+ /* Read in header signature and CRC, then validate signature.
+ (last block signature means CRC is for whole file, return now) */
+ i = get_bits(bd,24);
+ j = get_bits(bd,24);
+#ifdef ENABLE_BUNZIP_CHECKING
+ bd->headerCRC=get_bits(bd,32);
+ if ((i == 0x177245) && (j == 0x385090)) return RETVAL_LAST_BLOCK;
+ if ((i != 0x314159) || (j != 0x265359)) return RETVAL_NOT_BZIP_DATA;
+ /* We can add support for blockRandomised if anybody complains. There was
+ some code for this in busybox 1.0.0-pre3, but nobody ever noticed that
+ it didn't actually work. */
+ if(get_bits(bd,1)) return RETVAL_OBSOLETE_INPUT;
+ if((origPtr=get_bits(bd,24)) > dbufSize) return RETVAL_DATA_ERROR;
+#else
+ get_bits(bd,32);
+ if ((i == 0x177245) && (j == 0x385090)) return RETVAL_LAST_BLOCK;
+ get_bits(bd,1);
+ origPtr=get_bits(bd,24);
+#endif
+ /* mapping table: if some byte values are never used (encoding things
+ like ascii text), the compression code removes the gaps to have fewer
+ symbols to deal with, and writes a sparse bitfield indicating which
+ values were present. We make a translation table to convert the symbols
+ back to the corresponding bytes. */
+ t=get_bits(bd, 16);
+ symTotal=0;
+ for (i=0;i<16;i++) {
+ if(t&(1<<(15-i))) {
+ k=get_bits(bd,16);
+ for(j=0;j<16;j++)
+ if(k&(1<<(15-j))) symToByte[symTotal++]=(16*i)+j;
+ }
+ }
+ /* How many different huffman coding groups does this block use? */
+ groupCount=get_bits(bd,3);
+#ifdef ENABLE_BUNZIP_CHECKING
+ if (groupCount<2 || groupCount>MAX_GROUPS) return RETVAL_DATA_ERROR;
+#endif
+ /* nSelectors: Every GROUP_SIZE many symbols we select a new huffman coding
+ group. Read in the group selector list, which is stored as MTF encoded
+ bit runs. (MTF=Move To Front, as each value is used it's moved to the
+ start of the list.) */
+#ifdef ENABLE_BUNZIP_CHECKING
+ if(!(nSelectors=get_bits(bd, 15))) return RETVAL_DATA_ERROR;
+#else
+ nSelectors=get_bits(bd, 15);
+#endif
+ for(i=0; i<groupCount; i++) mtfSymbol[i] = i;
+ for(i=0; i<nSelectors; i++) {
+ /* Get next value */
+#ifdef ENABLE_BUNZIP_CHECKING
+ for(j=0;get_bits(bd,1);j++) if (j>=groupCount) return RETVAL_DATA_ERROR;
+#else
+ for(j=0;get_bits(bd,1);j++) ;
+#endif
+ /* Decode MTF to get the next selector */
+ uc = mtfSymbol[j];
+ for(;j;j--) mtfSymbol[j] = mtfSymbol[j-1];
+ mtfSymbol[0]=selectors[i]=uc;
+ }
+ /* Read the huffman coding tables for each group, which code for symTotal
+ literal symbols, plus two run symbols (RUNA, RUNB) */
+ symCount=symTotal+2;
+ for (j=0; j<groupCount; j++) {
+ unsigned char length[MAX_SYMBOLS],temp[MAX_HUFCODE_BITS+1];
+ int minLen, maxLen, pp;
+ /* Read huffman code lengths for each symbol. They're stored in
+ a way similar to mtf; record a starting value for the first symbol,
+ and an offset from the previous value for everys symbol after that.
+ (Subtracting 1 before the loop and then adding it back at the end is
+ an optimization that makes the test inside the loop simpler: symbol
+ length 0 becomes negative, so an unsigned inequality catches it.) */
+ t=get_bits(bd, 5)-1;
+ for (i = 0; i < symCount; i++) {
+ for(;;) {
+#ifdef ENABLE_BUNZIP_CHECKING
+ if (((unsigned)t) > (MAX_HUFCODE_BITS-1))
+ return RETVAL_DATA_ERROR;
+#endif
+ /* If first bit is 0, stop. Else second bit indicates whether
+ to increment or decrement the value. Optimization: grab 2
+ bits and unget the second if the first was 0. */
+ k = get_bits(bd,2);
+ if (k < 2) {
+ bd->inbufBitCount++;
+ break;
+ }
+ /* Add one if second bit 1, else subtract 1. Avoids if/else */
+ t+=(((k+1)&2)-1);
+ }
+ /* Correct for the initial -1, to get the final symbol length */
+ length[i]=t+1;
+ }
+ /* Find largest and smallest lengths in this group */
+ minLen=maxLen=length[0];
+ for(i = 1; i < symCount; i++) {
+ if(length[i] > maxLen) maxLen = length[i];
+ else if(length[i] < minLen) minLen = length[i];
+ }
+ /* Calculate permute[], base[], and limit[] tables from length[].
+ *
+ * permute[] is the lookup table for converting huffman coded symbols
+ * into decoded symbols. base[] is the amount to subtract from the
+ * value of a huffman symbol of a given length when using permute[].
+ *
+ * limit[] indicates the largest numerical value a symbol with a given
+ * number of bits can have. This is how the huffman codes can vary in
+ * length: each code with a value>limit[length] needs another bit.
+ */
+ hufGroup=bd->groups+j;
+ hufGroup->minLen = minLen;
+ hufGroup->maxLen = maxLen;
+ /* Note that minLen can't be smaller than 1, so we adjust the base
+ and limit array pointers so we're not always wasting the first
+ entry. We do this again when using them (during symbol decoding).*/
+ base=hufGroup->base-1;
+ limit=hufGroup->limit-1;
+ /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */
+ pp=0;
+ for(i=minLen;i<=maxLen;i++) {
+ temp[i]=limit[i]=0;
+ for(t=0;t<symCount;t++)
+ if(length[t]==i) hufGroup->permute[pp++] = t;
+ }
+ /* Count symbols coded for at each bit length */
+ for (i=0;i<symCount;i++) temp[length[i]]++;
+ /* Calculate limit[] (the largest symbol-coding value at each bit
+ * length, which is (previous limit<<1)+symbols at this level), and
+ * base[] (number of symbols to ignore at each bit length, which is
+ * limit minus the cumulative count of symbols coded for already). */
+ pp=t=0;
+ for (i=minLen; i<maxLen; i++) {
+ pp+=temp[i];
+ /* We read the largest possible symbol size and then unget bits
+ after determining how many we need, and those extra bits could
+ be set to anything. (They're noise from future symbols.) At
+ each level we're really only interested in the first few bits,
+ so here we set all the trailing to-be-ignored bits to 1 so they
+ don't affect the value>limit[length] comparison. */
+ limit[i]= (pp << (maxLen - i)) - 1;
+ pp<<=1;
+ base[i+1]=pp-(t+=temp[i]);
+ }
+ limit[maxLen+1] = INT_MAX; /* Sentinal value for reading next sym. */
+ limit[maxLen]=pp+temp[maxLen]-1;
+ base[minLen]=0;
+ }
+ /* We've finished reading and digesting the block header. Now read this
+ block's huffman coded symbols from the file and undo the huffman coding
+ and run length encoding, saving the result into dbuf[dbufCount++]=uc */
+
+ /* Initialize symbol occurrence counters and symbol Move To Front table */
+ for(i=0;i<256;i++) {
+ byteCount[i] = 0;
+ mtfSymbol[i]=(unsigned char)i;
+ }
+ /* Loop through compressed symbols. */
+ runPos=dbufCount=symCount=selector=0;
+ for(;;) {
+ /* Determine which huffman coding group to use. */
+ if(!(symCount--)) {
+ symCount=GROUP_SIZE-1;
+#ifdef ENABLE_BUNZIP_CHECKING
+ if(selector>=nSelectors) return RETVAL_DATA_ERROR;
+#endif
+ hufGroup=bd->groups+selectors[selector++];
+ base=hufGroup->base-1;
+ limit=hufGroup->limit-1;
+ }
+ /* Read next huffman-coded symbol. */
+ /* Note: It is far cheaper to read maxLen bits and back up than it is
+ to read minLen bits and then an additional bit at a time, testing
+ as we go. Because there is a trailing last block (with file CRC),
+ there is no danger of the overread causing an unexpected EOF for a
+ valid compressed file. As a further optimization, we do the read
+ inline (falling back to a call to get_bits if the buffer runs
+ dry). The following (up to got_huff_bits:) is equivalent to
+ j=get_bits(bd,hufGroup->maxLen);
+ */
+ while (bd->inbufBitCount<hufGroup->maxLen) {
+#ifdef ENABLE_BUNZIP_CHECKING
+ if(bd->inbufPos==bd->inbufCount) {
+ j = get_bits(bd,hufGroup->maxLen);
+ goto got_huff_bits;
+ }
+#endif
+ bd->inbufBits=(bd->inbufBits<<8)|bd->inbuf[bd->inbufPos++];
+ bd->inbufBitCount+=8;
+ };
+ bd->inbufBitCount-=hufGroup->maxLen;
+ j = (bd->inbufBits>>bd->inbufBitCount)&((1<<hufGroup->maxLen)-1);
+got_huff_bits:
+ /* Figure how how many bits are in next symbol and unget extras */
+ i=hufGroup->minLen;
+ while(j>limit[i]) ++i;
+ bd->inbufBitCount += (hufGroup->maxLen - i);
+ /* Huffman decode value to get nextSym (with bounds checking) */
+#ifdef ENABLE_BUNZIP_CHECKING
+ if ((i > hufGroup->maxLen)
+ || (((unsigned)(j=(j>>(hufGroup->maxLen-i))-base[i]))
+ >= MAX_SYMBOLS))
+ return RETVAL_DATA_ERROR;
+#else
+ j=(j>>(hufGroup->maxLen-i))-base[i];
+#endif
+ nextSym = hufGroup->permute[j];
+ /* We have now decoded the symbol, which indicates either a new literal
+ byte, or a repeated run of the most recent literal byte. First,
+ check if nextSym indicates a repeated run, and if so loop collecting
+ how many times to repeat the last literal. */
+ if (((unsigned)nextSym) <= SYMBOL_RUNB) { /* RUNA or RUNB */
+ /* If this is the start of a new run, zero out counter */
+ if(!runPos) {
+ runPos = 1;
+ t = 0;
+ }
+ /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at
+ each bit position, add 1 or 2 instead. For example,
+ 1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2.
+ You can make any bit pattern that way using 1 less symbol than
+ the basic or 0/1 method (except all bits 0, which would use no
+ symbols, but a run of length 0 doesn't mean anything in this
+ context). Thus space is saved. */
+ t += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */
+ runPos <<= 1;
+ continue;
+ }
+ /* When we hit the first non-run symbol after a run, we now know
+ how many times to repeat the last literal, so append that many
+ copies to our buffer of decoded symbols (dbuf) now. (The last
+ literal used is the one at the head of the mtfSymbol array.) */
+ if(runPos) {
+ runPos=0;
+#ifdef ENABLE_BUNZIP_CHECKING
+ if(dbufCount+t>=dbufSize) return RETVAL_DATA_ERROR;
+#endif
+
+ uc = symToByte[mtfSymbol[0]];
+ byteCount[uc] += t;
+ while(t--) dbuf[dbufCount++]=uc;
+ }
+ /* Is this the terminating symbol? */
+ if(nextSym>symTotal) break;
+ /* At this point, nextSym indicates a new literal character. Subtract
+ one to get the position in the MTF array at which this literal is
+ currently to be found. (Note that the result can't be -1 or 0,
+ because 0 and 1 are RUNA and RUNB. But another instance of the
+ first symbol in the mtf array, position 0, would have been handled
+ as part of a run above. Therefore 1 unused mtf position minus
+ 2 non-literal nextSym values equals -1.) */
+#ifdef ENABLE_BUNZIP_CHECKING
+ if(dbufCount>=dbufSize) return RETVAL_DATA_ERROR;
+#endif
+ i = nextSym - 1;
+ uc = mtfSymbol[i];
+ /* Adjust the MTF array. Since we typically expect to move only a
+ * small number of symbols, and are bound by 256 in any case, using
+ * memmove here would typically be bigger and slower due to function
+ * call overhead and other assorted setup costs. */
+ do {
+ mtfSymbol[i] = mtfSymbol[i-1];
+ } while (--i);
+ mtfSymbol[0] = uc;
+ uc=symToByte[uc];
+ /* We have our literal byte. Save it into dbuf. */
+ byteCount[uc]++;
+ dbuf[dbufCount++] = (unsigned int)uc;
+ }
+ /* At this point, we've read all the huffman-coded symbols (and repeated
+ runs) for this block from the input stream, and decoded them into the
+ intermediate buffer. There are dbufCount many decoded bytes in dbuf[].
+ Now undo the Burrows-Wheeler transform on dbuf.
+ See http://dogma.net/markn/articles/bwt/bwt.htm
+ */
+ /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */
+ j=0;
+ for(i=0;i<256;i++) {
+ k=j+byteCount[i];
+ byteCount[i] = j;
+ j=k;
+ }
+ /* Figure out what order dbuf would be in if we sorted it. */
+ for (i=0;i<dbufCount;i++) {
+ uc=(unsigned char)(dbuf[i] & 0xff);
+ dbuf[byteCount[uc]] |= (i << 8);
+ byteCount[uc]++;
+ }
+ /* Decode first byte by hand to initialize "previous" byte. Note that it
+ doesn't get output, and if the first three characters are identical
+ it doesn't qualify as a run (hence writeRunCountdown=5). */
+ if(dbufCount) {
+#ifdef ENABLE_BUNZIP_CHECKING
+ if(origPtr>=dbufCount) return RETVAL_DATA_ERROR;
+#endif
+ bd->writePos=dbuf[origPtr];
+ bd->writeCurrent=(unsigned char)(bd->writePos&0xff);
+ bd->writePos>>=8;
+ bd->writeRunCountdown=5;
+ }
+ bd->writeCount=dbufCount;
+
+ return RETVAL_OK;
+}
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/decompress_bunzip2.lds b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/decompress_bunzip2.lds
new file mode 100644
index 000000000..6a91b49c2
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/decompress_bunzip2.lds
@@ -0,0 +1,17 @@
+OUTPUT_ARCH(mips)
+ENTRY(load_and_run)
+SECTIONS {
+ . = 0x81000000-0x4000;
+ .text : {
+ *(.text)
+ *(.rodata)
+ }
+
+ .data : {
+ *(.data)
+ }
+
+ .bss : {
+ *(.bss)
+ }
+}
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/decompress_bunzip2.lds.in b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/decompress_bunzip2.lds.in
new file mode 100644
index 000000000..95cf83ebd
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/decompress_bunzip2.lds.in
@@ -0,0 +1,17 @@
+OUTPUT_ARCH(mips)
+ENTRY(load_and_run)
+SECTIONS {
+ . = BZ_TEXT_START;
+ .text : {
+ *(.text)
+ *(.rodata)
+ }
+
+ .data : {
+ *(.data)
+ }
+
+ .bss : {
+ *(.bss)
+ }
+}
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/head.S b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/head.S
new file mode 100644
index 000000000..c3ecdc47f
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/head.S
@@ -0,0 +1,26 @@
+/* Copyright 2004 Manuel Novoa III (mjn3@codepoet.org) */
+/* Licensed under the linux kernel's version of the GPL. */
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+ .text
+ LEAF(startup)
+ .set noreorder
+
+ li t1, BZ_TEXT_START
+ add a0, t1, 0
+ la a1, code_start
+ la a2, code_stop
+$L1:
+ lw t0, 0(a1)
+ sw t0, 0(a0)
+ add a1, 4
+ add a0, 4
+ blt a1, a2, $L1
+
+ add sp, t1, -4
+ jal t1
+
+ .set reorder
+ END(startup)
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/vmlinux.lds b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/vmlinux.lds
new file mode 100644
index 000000000..9d95adbfa
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/vmlinux.lds
@@ -0,0 +1,17 @@
+OUTPUT_ARCH(mips)
+ENTRY(startup)
+SECTIONS {
+ . = 0x80001000;
+ .text : {
+ *(.text)
+ *(.rodata)
+ }
+
+ .data : {
+ *(.data)
+ }
+
+ .bss : {
+ *(.bss)
+ }
+}
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/vmlinux.lds.in b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/vmlinux.lds.in
new file mode 100644
index 000000000..20f2ea98e
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/compressed/vmlinux.lds.in
@@ -0,0 +1,17 @@
+OUTPUT_ARCH(mips)
+ENTRY(startup)
+SECTIONS {
+ . = TEXT_START;
+ .text : {
+ *(.text)
+ *(.rodata)
+ }
+
+ .data : {
+ *(.data)
+ }
+
+ .bss : {
+ *(.bss)
+ }
+}
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/gpio.c b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/gpio.c
new file mode 100644
index 000000000..d20b76333
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/gpio.c
@@ -0,0 +1,158 @@
+/*
+ * GPIO char driver
+ *
+ * Copyright 2004, 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/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <sbutils.h>
+#include <bcmdevs.h>
+
+static void *gpio_sbh;
+static int gpio_major;
+static devfs_handle_t gpio_dir;
+static struct {
+ char *name;
+ devfs_handle_t handle;
+} gpio_file[] = {
+ { "in", NULL },
+ { "out", NULL },
+ { "outen", NULL },
+ { "control", NULL }
+};
+
+static int
+gpio_open(struct inode *inode, struct file * file)
+{
+ if (MINOR(inode->i_rdev) > ARRAYSIZE(gpio_file))
+ return -ENODEV;
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int
+gpio_release(struct inode *inode, struct file * file)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static ssize_t
+gpio_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+ u32 val;
+
+ switch (MINOR(file->f_dentry->d_inode->i_rdev)) {
+ case 0:
+ val = sb_gpioin(gpio_sbh);
+ break;
+ case 1:
+ val = sb_gpioout(gpio_sbh, 0, 0);
+ break;
+ case 2:
+ val = sb_gpioouten(gpio_sbh, 0, 0);
+ break;
+ case 3:
+ val = sb_gpiocontrol(gpio_sbh, 0, 0);
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ if (put_user(val, (u32 *) buf))
+ return -EFAULT;
+
+ return sizeof(val);
+}
+
+static ssize_t
+gpio_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+ u32 val;
+
+ if (get_user(val, (u32 *) buf))
+ return -EFAULT;
+
+ switch (MINOR(file->f_dentry->d_inode->i_rdev)) {
+ case 0:
+ return -EACCES;
+ case 1:
+ sb_gpioout(gpio_sbh, ~0, val);
+ break;
+ case 2:
+ sb_gpioouten(gpio_sbh, ~0, val);
+ break;
+ case 3:
+ sb_gpiocontrol(gpio_sbh, ~0, val);
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ return sizeof(val);
+}
+
+static struct file_operations gpio_fops = {
+ owner: THIS_MODULE,
+ open: gpio_open,
+ release: gpio_release,
+ read: gpio_read,
+ write: gpio_write,
+};
+
+static int __init
+gpio_init(void)
+{
+ int i;
+
+ if (!(gpio_sbh = sb_kattach()))
+ return -ENODEV;
+
+ sb_gpiosetcore(gpio_sbh);
+
+ if ((gpio_major = devfs_register_chrdev(0, "gpio", &gpio_fops)) < 0)
+ return gpio_major;
+
+ gpio_dir = devfs_mk_dir(NULL, "gpio", NULL);
+
+ for (i = 0; i < ARRAYSIZE(gpio_file); i++) {
+ gpio_file[i].handle = devfs_register(gpio_dir,
+ gpio_file[i].name,
+ DEVFS_FL_DEFAULT, gpio_major, i,
+ S_IFCHR | S_IRUGO | S_IWUGO,
+ &gpio_fops, NULL);
+ }
+
+ return 0;
+}
+
+static void __exit
+gpio_exit(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAYSIZE(gpio_file); i++)
+ devfs_unregister(gpio_file[i].handle);
+ devfs_unregister(gpio_dir);
+ devfs_unregister_chrdev(gpio_major, "gpio");
+ sb_detach(gpio_sbh);
+}
+
+module_init(gpio_init);
+module_exit(gpio_exit);
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/nvram.c b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/nvram.c
new file mode 100644
index 000000000..af12ced3f
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/nvram.c
@@ -0,0 +1,317 @@
+/*
+ * NVRAM variable manipulation (common)
+ *
+ * Copyright 2004, 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 <typedefs.h>
+#include <osl.h>
+#include <bcmendian.h>
+#include <bcmnvram.h>
+#include <bcmutils.h>
+#include <sbsdram.h>
+
+extern struct nvram_tuple * _nvram_realloc(struct nvram_tuple *t, const char *name, const char *value);
+extern void _nvram_free(struct nvram_tuple *t);
+extern int _nvram_read(void *buf);
+
+char * _nvram_get(const char *name);
+int _nvram_set(const char *name, const char *value);
+int _nvram_unset(const char *name);
+int _nvram_getall(char *buf, int count);
+int _nvram_commit(struct nvram_header *header);
+int _nvram_init(void);
+void _nvram_exit(void);
+
+static struct nvram_tuple * nvram_hash[257];
+static struct nvram_tuple * nvram_dead;
+
+/* Free all tuples. Should be locked. */
+static void
+nvram_free(void)
+{
+ uint i;
+ struct nvram_tuple *t, *next;
+
+ /* Free hash table */
+ for (i = 0; i < ARRAYSIZE(nvram_hash); i++) {
+ for (t = nvram_hash[i]; t; t = next) {
+ next = t->next;
+ _nvram_free(t);
+ }
+ nvram_hash[i] = NULL;
+ }
+
+ /* Free dead table */
+ for (t = nvram_dead; t; t = next) {
+ next = t->next;
+ _nvram_free(t);
+ }
+ nvram_dead = NULL;
+
+ /* Indicate to per-port code that all tuples have been freed */
+ _nvram_free(NULL);
+}
+
+/* String hash */
+static INLINE uint
+hash(const char *s)
+{
+ uint hash = 0;
+
+ while (*s)
+ hash = 31 * hash + *s++;
+
+ return hash;
+}
+
+/* (Re)initialize the hash table. Should be locked. */
+static int
+nvram_rehash(struct nvram_header *header)
+{
+ char buf[] = "0xXXXXXXXX", *name, *value, *end, *eq;
+
+ /* (Re)initialize hash table */
+ nvram_free();
+
+ /* 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;
+ _nvram_set(name, value);
+ *eq = '=';
+ }
+
+ /* Set special SDRAM parameters */
+ if (!_nvram_get("sdram_init")) {
+ sprintf(buf, "0x%04X", (uint16)(header->crc_ver_init >> 16));
+ _nvram_set("sdram_init", buf);
+ }
+ if (!_nvram_get("sdram_config")) {
+ sprintf(buf, "0x%04X", (uint16)(header->config_refresh & 0xffff));
+ _nvram_set("sdram_config", buf);
+ }
+ if (!_nvram_get("sdram_refresh")) {
+ sprintf(buf, "0x%04X", (uint16)((header->config_refresh >> 16) & 0xffff));
+ _nvram_set("sdram_refresh", buf);
+ }
+ if (!_nvram_get("sdram_ncdl")) {
+ sprintf(buf, "0x%08X", header->config_ncdl);
+ _nvram_set("sdram_ncdl", buf);
+ }
+
+ return 0;
+}
+
+/* Get the value of an NVRAM variable. Should be locked. */
+char *
+_nvram_get(const char *name)
+{
+ uint i;
+ struct nvram_tuple *t;
+ char *value;
+
+ if (!name)
+ return NULL;
+
+ /* Hash the name */
+ i = hash(name) % ARRAYSIZE(nvram_hash);
+
+ /* Find the associated tuple in the hash table */
+ for (t = nvram_hash[i]; t && strcmp(t->name, name); t = t->next);
+
+ value = t ? t->value : NULL;
+
+ return value;
+}
+
+/* Get the value of an NVRAM variable. Should be locked. */
+int
+_nvram_set(const char *name, const char *value)
+{
+ uint i;
+ struct nvram_tuple *t, *u, **prev;
+
+ /* Hash the name */
+ i = hash(name) % ARRAYSIZE(nvram_hash);
+
+ /* Find the associated tuple in the hash table */
+ for (prev = &nvram_hash[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev);
+
+ /* (Re)allocate tuple */
+ if (!(u = _nvram_realloc(t, name, value)))
+ return -12; /* -ENOMEM */
+
+ /* Value reallocated */
+ if (t && t == u)
+ return 0;
+
+ /* Move old tuple to the dead table */
+ if (t) {
+ *prev = t->next;
+ t->next = nvram_dead;
+ nvram_dead = t;
+ }
+
+ /* Add new tuple to the hash table */
+ u->next = nvram_hash[i];
+ nvram_hash[i] = u;
+
+ return 0;
+}
+
+/* Unset the value of an NVRAM variable. Should be locked. */
+int
+_nvram_unset(const char *name)
+{
+ uint i;
+ struct nvram_tuple *t, **prev;
+
+ if (!name)
+ return 0;
+
+ /* Hash the name */
+ i = hash(name) % ARRAYSIZE(nvram_hash);
+
+ /* Find the associated tuple in the hash table */
+ for (prev = &nvram_hash[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev);
+
+ /* Move it to the dead table */
+ if (t) {
+ *prev = t->next;
+ t->next = nvram_dead;
+ nvram_dead = t;
+ }
+
+ return 0;
+}
+
+/* Get all NVRAM variables. Should be locked. */
+int
+_nvram_getall(char *buf, int count)
+{
+ uint i;
+ struct nvram_tuple *t;
+ int len = 0;
+
+ bzero(buf, count);
+
+ /* Write name=value\0 ... \0\0 */
+ for (i = 0; i < ARRAYSIZE(nvram_hash); i++) {
+ for (t = 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;
+ }
+ }
+
+ return 0;
+}
+
+/* Regenerate NVRAM. Should be locked. */
+int
+_nvram_commit(struct nvram_header *header)
+{
+ char *init, *config, *refresh, *ncdl;
+ char *ptr, *end;
+ int i;
+ struct nvram_tuple *t;
+ struct nvram_header tmp;
+ uint8 crc;
+
+ /* Regenerate header */
+ header->magic = NVRAM_MAGIC;
+ header->crc_ver_init = (NVRAM_VERSION << 8);
+ if (!(init = _nvram_get("sdram_init")) ||
+ !(config = _nvram_get("sdram_config")) ||
+ !(refresh = _nvram_get("sdram_refresh")) ||
+ !(ncdl = _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);
+ }
+
+ /* Clear data area */
+ ptr = (char *) header + sizeof(struct nvram_header);
+ bzero(ptr, NVRAM_SPACE - sizeof(struct nvram_header));
+
+ /* Leave space for a double NUL at the end */
+ end = (char *) header + NVRAM_SPACE - 2;
+
+ /* Write out all tuples */
+ for (i = 0; i < ARRAYSIZE(nvram_hash); i++) {
+ for (t = 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;
+ }
+ }
+
+ /* End with a double NUL */
+ ptr += 2;
+
+ /* Set new length */
+ header->len = ROUNDUP(ptr - (char *) header, 4);
+
+ /* 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 = crc8((char *) &tmp + 9, sizeof(struct nvram_header) - 9, CRC8_INIT_VALUE);
+
+ /* Continue CRC8 over data bytes */
+ crc = crc8((char *) &header[1], header->len - sizeof(struct nvram_header), crc);
+
+ /* Set new CRC8 */
+ header->crc_ver_init |= crc;
+
+ /* Reinitialize hash table */
+ return nvram_rehash(header);
+}
+
+/* Initialize hash table. Should be locked. */
+int
+_nvram_init(void)
+{
+ struct nvram_header *header;
+ int ret;
+
+ if (!(header = (struct nvram_header *) MALLOC(NVRAM_SPACE))) {
+ printf("nvram_init: out of memory\n");
+ return -12; /* -ENOMEM */
+ }
+
+ if ((ret = _nvram_read(header)) == 0 &&
+ header->magic == NVRAM_MAGIC)
+ nvram_rehash(header);
+
+ MFREE(header, NVRAM_SPACE);
+ return ret;
+}
+
+/* Free hash table. Should be locked. */
+void
+_nvram_exit(void)
+{
+ nvram_free();
+}
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/nvram_linux.c b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/nvram_linux.c
new file mode 100644
index 000000000..bbbc1eb73
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/nvram_linux.c
@@ -0,0 +1,638 @@
+/*
+ * NVRAM variable manipulation (Linux kernel half)
+ *
+ * Copyright 2004, 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;
+ struct sflash *info = NULL;
+ int i;
+ uint32 base, off, lim;
+
+ if ((cc = sb_setcore(sbh, SB_CC, 0)) != NULL) {
+ base = CC_FLASH_BASE;
+ switch (readl(&cc->capabilities) & CAP_FLASH_MASK) {
+ case PFLASH:
+ lim = CC_FLASH_MAX;
+ break;
+
+ case SFLASH_ST:
+ case SFLASH_AT:
+ if ((info = sflash_init(cc)) == NULL)
+ return;
+ lim = info->size;
+ break;
+
+ case FLASH_NONE:
+ default:
+ return;
+ }
+ } else {
+ /* extif assumed, Stop at 4 MB */
+ base = FLASH_BASE;
+ lim = FLASH_MAX;
+ }
+
+ off = FLASH_MIN;
+ while (off <= lim) {
+ /* Windowed flash access */
+ header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
+ if (header->magic == NVRAM_MAGIC) {
+ u32 *src = (u32 *) header;
+ u32 *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++);
+ return;
+ }
+
+ /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
+ if (off == 1 KB)
+ break;
+ else if (off == 4 KB)
+ off = 1 KB;
+ else if (off == lim)
+ off = 4 KB;
+ else
+ off <<= 1;
+ }
+}
+
+/* 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;
+
+ 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;
+ }
+
+ 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;
+}
+
+struct nvram_tuple *
+_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value)
+{
+ if ((nvram_offset + strlen(value) + 1) > NVRAM_SPACE)
+ return NULL;
+
+ if (!t) {
+ if (!(t = kmalloc(sizeof(struct nvram_tuple) + strlen(name) + 1, GFP_ATOMIC)))
+ return NULL;
+
+ /* Copy name */
+ t->name = (char *) &t[1];
+ strcpy(t->name, name);
+
+ t->value = NULL;
+ }
+
+ /* 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 t;
+}
+
+void
+_nvram_free(struct nvram_tuple *t)
+{
+ if (!t)
+ nvram_offset = 0;
+ else
+ kfree(t);
+}
+
+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);
+
+ return ret;
+}
+
+char *
+real_nvram_get(const char *name)
+{
+ unsigned long flags;
+ char *value;
+
+ spin_lock_irqsave(&nvram_lock, flags);
+ value = _nvram_get(name);
+ spin_unlock_irqrestore(&nvram_lock, flags);
+
+ return value;
+}
+
+char *
+nvram_get(const char *name)
+{
+ 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;
+}
+
+static void
+erase_callback(struct erase_info *done)
+{
+ wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv;
+ wake_up(wait_q);
+}
+
+int
+nvram_commit(void)
+{
+ 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;
+
+ printk("nvram_commit(): init\n");
+
+ if (!nvram_mtd) {
+ printk("nvram_commit: NVRAM not found\n");
+ return -ENODEV;
+ }
+
+ if (in_interrupt()) {
+ printk("nvram_commit: not committing in interrupt\n");
+ return -EINVAL;
+ }
+
+ /* 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;
+ }
+
+ down(&nvram_sem);
+#if 0
+ offset = nvram_mtd->size - erasesize;
+ i = erasesize - NVRAM_SPACE;
+ ret = MTD_READ(nvram_mtd, offset, i, &len, buf);
+ if (ret || len != i) {
+ printk("nvram_commit: read error\n");
+ ret = -EIO;
+ goto done;
+#endif
+ 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;
+ }
+
+ /* 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;
+ }
+
+ /* Wait for erase to finish */
+ schedule();
+ remove_wait_queue(&wait_q, &wait);
+ }
+
+ /* 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;
+ }
+ /*
+ * Reading a few bytes back here will put the device
+ * back to the correct mode on certain flashes */
+
+ offset = nvram_mtd->size - erasesize;
+ ret = MTD_READ(nvram_mtd, offset, 4, &len, buf);
+
+ done:
+ up(&nvram_sem);
+ kfree(buf);
+ printk("nvram_commit(): end\n");
+ return ret;
+}
+
+int
+nvram_getall(char *buf, int count)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&nvram_lock, flags);
+ ret = _nvram_getall(buf, count);
+ spin_unlock_irqrestore(&nvram_lock, flags);
+
+ 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;
+ }
+ } else {
+ if (!(value = nvram_get(name))) {
+ ret = 0;
+ goto done;
+ }
+
+ /* 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;
+ }
+
+ ret = sizeof(unsigned long);
+ }
+
+ flush_cache_all();
+
+done:
+ if (name != tmp)
+ kfree(name);
+
+ return ret;
+}
+
+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;
+
+ if (count > sizeof(tmp)) {
+ if (!(name = kmalloc(count, GFP_KERNEL)))
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(name, buf, count)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ value = name;
+ name = strsep(&value, "=");
+ if (value)
+ ret = nvram_set(name, value) ? : count;
+ else
+ ret = nvram_unset(name) ? : count;
+
+ done:
+ if (name != tmp)
+ kfree(name);
+
+ return ret;
+}
+
+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();
+}
+
+static int
+dev_nvram_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ unsigned long offset = virt_to_phys(nvram_buf);
+
+ if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int
+dev_nvram_open(struct inode *inode, struct file * file)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int
+dev_nvram_release(struct inode *inode, struct file * file)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+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,
+};
+
+static void
+dev_nvram_exit(void)
+{
+ int order = 0;
+ struct page *page, *end;
+
+ if (nvram_handle)
+ devfs_unregister(nvram_handle);
+
+ if (nvram_major >= 0)
+ devfs_unregister_chrdev(nvram_major, "nvram");
+
+ if (nvram_mtd)
+ put_mtd_device(nvram_mtd);
+
+ 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();
+}
+
+static int __init
+dev_nvram_init(void)
+{
+ int order = 0, ret = 0;
+ struct page *page, *end;
+ unsigned int i;
+
+ /* 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
+
+ /* Initialize hash table lock */
+ spin_lock_init(&nvram_lock);
+
+ /* Initialize commit semaphore */
+ init_MUTEX(&nvram_sem);
+
+ /* Register char device */
+ if ((nvram_major = devfs_register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) {
+ ret = nvram_major;
+ goto err;
+ }
+
+ /* Initialize hash table */
+ _nvram_init();
+
+ /* 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();
+ }
+ }
+
+ return 0;
+
+ err:
+ dev_nvram_exit();
+ return ret;
+}
+
+module_init(dev_nvram_init);
+module_exit(dev_nvram_exit);
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/pcibios.c b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/pcibios.c
new file mode 100644
index 000000000..4077a79f3
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/pcibios.c
@@ -0,0 +1,352 @@
+/*
+ * Low-Level PCI and SB support for BCM47xx (Linux support code)
+ *
+ * Copyright 2004, 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/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/paccess.h>
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <sbconfig.h>
+#include <sbpci.h>
+#include <pcicfg.h>
+#include <sbutils.h>
+#include <bcmdevs.h>
+#include <bcmnvram.h>
+
+/* Global SB handle */
+extern void *bcm947xx_sbh;
+extern spinlock_t bcm947xx_sbh_lock;
+
+/* Convenience */
+#define sbh bcm947xx_sbh
+#define sbh_lock bcm947xx_sbh_lock
+
+static int
+sbpci_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&sbh_lock, flags);
+ ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, value, sizeof(*value));
+ spin_unlock_irqrestore(&sbh_lock, flags);
+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static int
+sbpci_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&sbh_lock, flags);
+ ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, value, sizeof(*value));
+ spin_unlock_irqrestore(&sbh_lock, flags);
+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static int
+sbpci_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&sbh_lock, flags);
+ ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, value, sizeof(*value));
+ spin_unlock_irqrestore(&sbh_lock, flags);
+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static int
+sbpci_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&sbh_lock, flags);
+ ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, &value, sizeof(value));
+ spin_unlock_irqrestore(&sbh_lock, flags);
+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static int
+sbpci_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&sbh_lock, flags);
+ ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, &value, sizeof(value));
+ spin_unlock_irqrestore(&sbh_lock, flags);
+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static int
+sbpci_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&sbh_lock, flags);
+ ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, &value, sizeof(value));
+ spin_unlock_irqrestore(&sbh_lock, flags);
+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pcibios_ops = {
+ sbpci_read_config_byte,
+ sbpci_read_config_word,
+ sbpci_read_config_dword,
+ sbpci_write_config_byte,
+ sbpci_write_config_word,
+ sbpci_write_config_dword
+};
+
+
+void __init
+pcibios_init(void)
+{
+ ulong flags;
+
+ if (!(sbh = sb_kattach()))
+ panic("sb_kattach failed");
+ spin_lock_init(&sbh_lock);
+
+ spin_lock_irqsave(&sbh_lock, flags);
+ sbpci_init(sbh);
+ spin_unlock_irqrestore(&sbh_lock, flags);
+
+ set_io_port_base((unsigned long) ioremap_nocache(SB_PCI_MEM, 0x04000000));
+
+ /* Scan the SB bus */
+ pci_scan_bus(0, &pcibios_ops, NULL);
+
+}
+
+char * __init
+pcibios_setup(char *str)
+{
+ if (!strncmp(str, "ban=", 4)) {
+ sbpci_ban(simple_strtoul(str + 4, NULL, 0));
+ return NULL;
+ }
+
+ return (str);
+}
+
+static u32 pci_iobase = 0x100;
+static u32 pci_membase = SB_PCI_DMA;
+
+void __init
+pcibios_fixup_bus(struct pci_bus *b)
+{
+ struct list_head *ln;
+ struct pci_dev *d;
+ struct resource *res;
+ int pos, size;
+ u32 *base;
+ u8 irq;
+
+ printk("PCI: Fixing up bus %d\n", b->number);
+
+ /* Fix up SB */
+ if (b->number == 0) {
+ for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
+ d = pci_dev_b(ln);
+ /* Fix up interrupt lines */
+ pci_read_config_byte(d, PCI_INTERRUPT_LINE, &irq);
+ d->irq = irq + 2;
+ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
+ }
+ }
+
+ /* Fix up external PCI */
+ else {
+ for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
+ d = pci_dev_b(ln);
+ /* Fix up resource bases */
+ for (pos = 0; pos < 6; pos++) {
+ res = &d->resource[pos];
+ base = (res->flags & IORESOURCE_IO) ? &pci_iobase : &pci_membase;
+ if (res->end) {
+ size = res->end - res->start + 1;
+ if (*base & (size - 1))
+ *base = (*base + size) & ~(size - 1);
+ res->start = *base;
+ res->end = res->start + size - 1;
+ *base += size;
+ pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
+ }
+ /* Fix up PCI bridge BAR0 only */
+ if (b->number == 1 && PCI_SLOT(d->devfn) == 0)
+ break;
+ }
+ /* Fix up interrupt lines */
+ if (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))
+ d->irq = (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))->irq;
+ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
+ }
+ }
+}
+
+unsigned int
+pcibios_assign_all_busses(void)
+{
+ return 1;
+}
+
+void
+pcibios_align_resource(void *data, struct resource *res,
+ unsigned long size, unsigned long align)
+{
+}
+
+int
+pcibios_enable_resources(struct pci_dev *dev)
+{
+ u16 cmd, old_cmd;
+ int idx;
+ struct resource *r;
+
+ /* External PCI only */
+ if (dev->bus->number == 0)
+ return 0;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+ for(idx=0; idx<6; idx++) {
+ r = &dev->resource[idx];
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ if (dev->resource[PCI_ROM_RESOURCE].start)
+ cmd |= PCI_COMMAND_MEMORY;
+ if (cmd != old_cmd) {
+ printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ return 0;
+}
+
+int
+pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+ ulong flags;
+ uint coreidx;
+
+ /* External PCI device enable */
+ if (dev->bus->number != 0)
+ return pcibios_enable_resources(dev);
+
+ /* These cores come out of reset enabled */
+ if (dev->device == SB_MIPS ||
+ dev->device == SB_MIPS33 ||
+ dev->device == SB_EXTIF ||
+ dev->device == SB_CC)
+ return 0;
+
+ spin_lock_irqsave(&sbh_lock, flags);
+ coreidx = sb_coreidx(sbh);
+ if (!sb_setcoreidx(sbh, PCI_SLOT(dev->devfn)))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /*
+ * The USB core requires a special bit to be set during core
+ * reset to enable host (OHCI) mode. Resetting the SB core in
+ * pcibios_enable_device() is a hack for compatibility with
+ * vanilla usb-ohci so that it does not have to know about
+ * SB. A driver that wants to use the USB core in device mode
+ * should know about SB and should reset the bit back to 0
+ * after calling pcibios_enable_device().
+ */
+ if (sb_coreid(sbh) == SB_USB) {
+ sb_core_disable(sbh, sb_coreflags(sbh, 0, 0));
+ sb_core_reset(sbh, 1 << 29);
+ } else
+ sb_core_reset(sbh, 0);
+
+ sb_setcoreidx(sbh, coreidx);
+ spin_unlock_irqrestore(&sbh_lock, flags);
+
+ return 0;
+}
+
+void
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+ struct resource *res, int resource)
+{
+ unsigned long where, size;
+ u32 reg;
+
+ /* External PCI only */
+ if (dev->bus->number == 0)
+ return;
+
+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ size = res->end - res->start;
+ pci_read_config_dword(dev, where, &reg);
+ reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
+ pci_write_config_dword(dev, where, reg);
+}
+
+static void __init
+quirk_sbpci_bridge(struct pci_dev *dev)
+{
+ if (dev->bus->number != 1 || PCI_SLOT(dev->devfn) != 0)
+ return;
+
+ printk("PCI: Fixing up bridge\n");
+
+ /* Enable PCI bridge bus mastering and memory space */
+ pci_set_master(dev);
+ pcibios_enable_resources(dev);
+
+ /* Enable PCI bridge BAR1 prefetch and burst */
+ pci_write_config_dword(dev, PCI_BAR1_CONTROL, 3);
+}
+
+/*
+ * If we set up a device for bus mastering, we need to check the latency
+ * timer as certain crappy BIOSes forget to set it properly.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+ u8 lat;
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+ if (lat < 16)
+ lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+ else if (lat > pcibios_max_latency)
+ lat = pcibios_max_latency;
+ else
+ return;
+ printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+
+struct pci_fixup pcibios_fixups[] = {
+ { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, quirk_sbpci_bridge },
+ { 0 }
+};
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/perfcntr.c b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/perfcntr.c
new file mode 100644
index 000000000..aa0608e6e
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/perfcntr.c
@@ -0,0 +1,67 @@
+/*
+ * Broadcom BCM47xx Performance Counter /proc/cpuinfo support
+ *
+ * Copyright 2004, 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 <asm/mipsregs.h>
+
+/*
+ * BCM4710 performance counter register select values
+ * No even-odd control-counter mapping, just counters
+ */
+#define PERF_DCACHE_HIT 0
+#define PERF_DCACHE_MISS 1
+#define PERF_ICACHE_HIT 2
+#define PERF_ICACHE_MISS 3
+#define PERF_ICOUNT 4
+
+/*
+ * Move from Coprocessor 0 Register 25 Select n
+ * data <- CPR[0,25,n]
+ * GPR[1] <- data
+ */
+#define read_bcm4710_perf_cntr(n) \
+({ int __res; \
+ __asm__ __volatile__( \
+ ".set\tnoreorder\n\t" \
+ ".set\tnoat\n\t" \
+ ".word\t"STR(0x4001c800|(n))"\n\t" \
+ "move\t%0,$1\n\t" \
+ ".set\tat\n\t" \
+ ".set\treorder" \
+ :"=r" (__res)); \
+ __res;})
+
+asmlinkage unsigned int read_perf_cntr(unsigned int counter)
+{
+ switch (counter) {
+ case PERF_DCACHE_HIT: return read_bcm4710_perf_cntr(PERF_DCACHE_HIT);
+ case PERF_DCACHE_MISS: return read_bcm4710_perf_cntr(PERF_DCACHE_MISS);
+ case PERF_ICACHE_HIT: return read_bcm4710_perf_cntr(PERF_ICACHE_HIT);
+ case PERF_ICACHE_MISS: return read_bcm4710_perf_cntr(PERF_ICACHE_MISS);
+ case PERF_ICOUNT: return read_bcm4710_perf_cntr(PERF_ICOUNT);
+ }
+ return 0;
+}
+
+asmlinkage void write_perf_cntr(unsigned int counter, unsigned int val)
+{
+}
+
+asmlinkage unsigned int read_perf_cntl(unsigned int counter)
+{
+ return 0;
+}
+
+asmlinkage void write_perf_cntl(unsigned int counter, unsigned int val)
+{
+}
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/prom.c b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/prom.c
new file mode 100644
index 000000000..e41f44b9e
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/prom.c
@@ -0,0 +1,41 @@
+/*
+ * Early initialization code for BCM94710 boards
+ *
+ * Copyright 2004, 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/kernel.h>
+#include <linux/types.h>
+#include <asm/bootinfo.h>
+
+void __init
+prom_init(int argc, const char **argv)
+{
+ unsigned long mem;
+
+ mips_machgroup = MACH_GROUP_BRCM;
+ mips_machtype = MACH_BCM947XX;
+
+ /* Figure out memory size by finding aliases */
+ for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) {
+ if (*(unsigned long *)((unsigned long)(prom_init) + mem) ==
+ *(unsigned long *)(prom_init))
+ break;
+ }
+ add_memory_region(0, mem, BOOT_MEM_RAM);
+}
+
+void __init
+prom_free_prom_memory(void)
+{
+}
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/sbmips.c b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/sbmips.c
new file mode 100644
index 000000000..6daaeb78c
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/sbmips.c
@@ -0,0 +1,951 @@
+/*
+ * BCM47XX Sonics SiliconBackplane MIPS core routines
+ *
+ * Copyright 2004, 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 <typedefs.h>
+#include <osl.h>
+#include <sbutils.h>
+#include <bcmdevs.h>
+#include <bcmnvram.h>
+#include <bcmutils.h>
+#include <hndmips.h>
+#include <sbconfig.h>
+#include <sbextif.h>
+#include <sbchipc.h>
+#include <sbmemc.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
+
+/*
+ * 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)
+
+/*
+ * 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
+
+/* *********************************************************************
+ * CP0 Registers
+ ********************************************************************* */
+
+#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 */
+
+/*
+ * Macros to access the system control coprocessor
+ */
+
+#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; \
+})
+
+#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)
+
+/*
+ * 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)
+
+/*
+ * 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
+
+/*
+ * 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
+ */
+
+#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(&regs[UART_MCR]);
+ W_REG(&regs[UART_MCR], UART_MCR_LOOP | 0x0a);
+ status1 = R_REG(&regs[UART_MSR]) & 0xf0;
+ W_REG(&regs[UART_MCR], save_mcr);
+
+ return (status1 == 0x90);
+}
+
+/*
+ * 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))
+{
+ void *regs;
+ ulong base;
+ uint irq;
+ int i, n;
+
+ if ((regs = sb_setcore(sbh, SB_EXTIF, 0))) {
+ extifregs_t *eir = (extifregs_t *) regs;
+ sbconfig_t *sb;
+
+ /* Determine external UART register base */
+ sb = (sbconfig_t *)((ulong) eir + SBCONFIGOFF);
+ base = EXTIF_CFGIF_BASE(sb_base(R_REG(&sb->sbadmatch1)));
+
+ /* Determine IRQ */
+ irq = sb_irq(sbh);
+
+ /* Disable GPIO interrupt initially */
+ W_REG(&eir->gpiointpolarity, 0);
+ W_REG(&eir->gpiointmask, 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);
+ }
+ }
+
+ /* 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;
+
+ /* Determine core revision and capabilities */
+ rev = sb_corerev(sbh);
+ cap = R_REG(&cc->capabilities);
+ pll = cap & CAP_PLL_MASK;
+
+ /* Determine IRQ */
+ irq = sb_irq(sbh);
+
+ 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->clkdiv, ((R_REG(&cc->clkdiv) & ~CLKD_UART) | div));
+ } else {
+ /* Fixed internal backplane clock */
+ baud_base = 88000000;
+ div = 48;
+ }
+
+ /* 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;
+ }
+ }
+
+ /* 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);
+ }
+ }
+}
+
+/* Returns the SB interrupt flag of the current core. */
+uint32
+sb_flag(void *sbh)
+{
+ void *regs;
+ sbconfig_t *sb;
+
+ regs = sb_coreregs(sbh);
+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
+
+ return (R_REG(&sb->sbtpsflag) & SBTPS_NUM0_MASK);
+}
+
+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;
+ }
+ if (irq == 5)
+ irq = 0;
+ }
+
+ sb_setcoreidx(sbh, idx);
+
+ return irq;
+}
+
+/* Clears the specified MIPS IRQ. */
+static void
+sb_clearirq(void *sbh, uint irq)
+{
+ void *regs;
+ sbconfig_t *sb;
+
+ if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
+ !(regs = sb_setcore(sbh, SB_MIPS33, 0)))
+ ASSERT(regs);
+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
+
+ if (irq == 0)
+ W_REG(&sb->sbintvec, 0);
+ else
+ OR_REG(&sb->sbipsflag, sbips_int_mask[irq]);
+}
+
+/*
+ * 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)
+{
+ void *regs;
+ sbconfig_t *sb;
+ uint32 flag;
+
+ regs = sb_setcore(sbh, coreid, coreunit);
+ ASSERT(regs);
+ flag = sb_flag(sbh);
+
+ if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
+ !(regs = sb_setcore(sbh, SB_MIPS33, 0)))
+ ASSERT(regs);
+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
+
+ 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);
+ }
+}
+
+/*
+ * 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;
+
+ /* Figure out current SB clock speed */
+ if ((hz = sb_clock(sbh)) == 0)
+ hz = 100000000;
+ ns = 1000000000 / hz;
+
+ /* 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);
+
+ /* 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 */
+
+ /* 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->flash_waitcount, tmp);
+
+ W_REG(&cc->pcmcia_memwait, tmp);
+ }
+
+ /* 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;
+ typedef struct {
+ uint32 mipsclock;
+ uint16 n;
+ uint32 sb;
+ uint32 pci33;
+ uint32 pci25;
+ } n3m_table_t;
+ static n3m_table_t 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;
+
+ static 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 }
+ };
+
+ static 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, 0x0111, 0x11020005, 0x01030303, 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 --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/sbpci.c b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/sbpci.c
new file mode 100644
index 000000000..b3469134e
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/sbpci.c
@@ -0,0 +1,563 @@
+/*
+ * Low-Level PCI and SB support for BCM47xx
+ *
+ * Copyright 2004, 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 <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;
+
+/* Disable PCI host core */
+static bool pci_disabled = 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(&regs->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(&regs->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 (pci_disabled ||
+ !(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 (pci_disabled ||
+ !(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;
+}
+//#define CT4712_WR 1 /* Workaround for 4712 */
+
+int __init
+sbpci_init(void *sbh)
+{
+ uint chip, chiprev, chippkg, coreidx, host, i;
+ uint32 boardflags;
+ sbpciregs_t *pci;
+ sbconfig_t *sb;
+ pci_config_regs *cfg;
+ void *regs;
+ char varname[8];
+ int CT4712_WR;
+ 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);
+
+ /* In some board, */
+ if(nvram_match("boardtype", "bcm94710dev"))
+ CT4712_WR = 0;
+ else
+ CT4712_WR = 1;
+
+ boardflags = (uint32) getintvar(NULL, "boardflags");
+
+ if ((chip == BCM4310_DEVICE_ID) && (chiprev == 0))
+ pci_disabled = TRUE;
+
+ /*
+ * The 200-pin BCM4712 package does not bond out PCI. Even when
+ * PCI is bonded out, some boards may leave the pins
+ * floating.
+ */
+ if (((chip == BCM4712_DEVICE_ID) && (chippkg == BCM4712SMALL_PKG_ID)) ||
+ (boardflags & BFL_NOPCI) || CT4712_WR)
+ pci_disabled = TRUE;
+
+ /*
+ * If the PCI core should not be touched (disabled, not bonded
+ * out, or pins floating), do not even attempt to access core
+ * registers. Otherwise, try to determine if it is in host
+ * mode.
+ */
+ if (pci_disabled)
+ 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(150); /* 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;
+ }
+
+ /* Determine class based on known core codes */
+ switch (core) {
+ case SB_ILINE20:
+ class = PCI_CLASS_NET;
+ subclass = PCI_NET_ETHER;
+ core = BCM47XX_ILINE_ID;
+ break;
+ case SB_ILINE100:
+ class = PCI_CLASS_NET;
+ subclass = PCI_NET_ETHER;
+ core = BCM4610_ILINE_ID;
+ break;
+ case SB_ENET:
+ class = PCI_CLASS_NET;
+ subclass = PCI_NET_ETHER;
+ core = BCM47XX_ENET_ID;
+ break;
+ case SB_SDRAM:
+ case SB_MEMC:
+ class = PCI_CLASS_MEMORY;
+ subclass = PCI_MEMORY_RAM;
+ break;
+ case SB_PCI:
+ class = PCI_CLASS_BRIDGE;
+ subclass = PCI_BRIDGE_PCI;
+ break;
+ case SB_MIPS:
+ case SB_MIPS33:
+ class = PCI_CLASS_CPU;
+ subclass = PCI_CPU_MIPS;
+ break;
+ case SB_CODEC:
+ class = PCI_CLASS_COMM;
+ subclass = PCI_COMM_MODEM;
+ core = BCM47XX_V90_ID;
+ break;
+ case SB_USB:
+ class = PCI_CLASS_SERIAL;
+ subclass = PCI_SERIAL_USB;
+ progif = 0x10; /* OHCI */
+ core = BCM47XX_USB_ID;
+ break;
+ case SB_USB11H:
+ class = PCI_CLASS_SERIAL;
+ subclass = PCI_SERIAL_USB;
+ progif = 0x10; /* OHCI */
+ core = BCM47XX_USBH_ID;
+ break;
+ case SB_USB11D:
+ class = PCI_CLASS_SERIAL;
+ subclass = PCI_SERIAL_USB;
+ core = BCM47XX_USBD_ID;
+ break;
+ case SB_IPSEC:
+ class = PCI_CLASS_CRYPT;
+ subclass = PCI_CRYPT_NETWORK;
+ core = BCM47XX_IPSEC_ID;
+ break;
+ case SB_EXTIF:
+ case SB_CC:
+ class = PCI_CLASS_MEMORY;
+ subclass = PCI_MEMORY_FLASH;
+ break;
+ case SB_D11:
+ class = PCI_CLASS_NET;
+ subclass = PCI_NET_OTHER;
+ /* Let an nvram variable override this */
+ sprintf(varname, "wl%did", wlidx);
+ wlidx++;
+ if ((core = getintvar(NULL, varname)) == 0) {
+ if (chip == BCM4712_DEVICE_ID) {
+ if (chippkg == BCM4712SMALL_PKG_ID)
+ core = BCM4306_D11G_ID;
+ else
+ core = BCM4306_D11DUAL_ID;
+ } else {
+ /* 4310 */
+ core = BCM4310_D11B_ID;
+ }
+ }
+ break;
+
+ default:
+ class = subclass = progif = 0xff;
+ break;
+ }
+
+ /* Supported translations */
+ cfg->vendor = htol16(vendor);
+ cfg->device = htol16(core);
+ cfg->rev_id = chiprev;
+ cfg->prog_if = progif;
+ cfg->sub_class = subclass;
+ cfg->base_class = class;
+ cfg->base[0] = htol32(sb_base(R_REG(&sb->sbadmatch0)));
+ cfg->base[1] = htol32(sb_base(R_REG(&sb->sbadmatch1)));
+ cfg->base[2] = htol32(sb_base(R_REG(&sb->sbadmatch2)));
+ cfg->base[3] = htol32(sb_base(R_REG(&sb->sbadmatch3)));
+ cfg->base[4] = 0;
+ cfg->base[5] = 0;
+ if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI)
+ cfg->header_type = PCI_HEADER_BRIDGE;
+ else
+ cfg->header_type = PCI_HEADER_NORMAL;
+ /* Save core interrupt flag */
+ cfg->int_pin = R_REG(&sb->sbtpsflag) & SBTPS_NUM0_MASK;
+ /* Default to MIPS shared interrupt 0 */
+ cfg->int_line = 0;
+ /* MIPS sbipsflag maps core interrupt flags to interrupts 1 through 4 */
+ if ((regs = sb_setcore(sbh, SB_MIPS, 0)) ||
+ (regs = sb_setcore(sbh, SB_MIPS33, 0))) {
+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
+ val = R_REG(&sb->sbipsflag);
+ for (cfg->int_line = 1; cfg->int_line <= 4; cfg->int_line++) {
+ if (((val & sbips_int_mask[cfg->int_line]) >> sbips_int_shift[cfg->int_line]) == cfg->int_pin)
+ break;
+ }
+ if (cfg->int_line > 4)
+ cfg->int_line = 0;
+ }
+ /* Emulated core */
+ *((uint32 *) &cfg->sprom_control) = 0xffffffff;
+ }
+
+ sb_setcoreidx(sbh, coreidx);
+ return 0;
+}
+
+void
+sbpci_check(void *sbh)
+{
+ uint coreidx;
+ sbpciregs_t *pci;
+ uint32 sbtopci1;
+ uint32 buf[64], *ptr, i;
+ ulong pa;
+ volatile uint j;
+
+ coreidx = sb_coreidx(sbh);
+ pci = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0);
+
+ /* Clear the test array */
+ pa = (ulong) DMA_MAP(NULL, buf, sizeof(buf), DMA_RX, NULL);
+ ptr = (uint32 *) OSL_UNCACHED(&buf[0]);
+ memset(ptr, 0, sizeof(buf));
+
+ /* Point PCI window 1 to memory */
+ sbtopci1 = R_REG(&pci->sbtopci1);
+ W_REG(&pci->sbtopci1, SBTOPCI_MEM | (pa & SBTOPCI1_MASK));
+
+ /* Fill the test array via PCI window 1 */
+ ptr = (uint32 *) REG_MAP(SB_PCI_CFG + (pa & ~SBTOPCI1_MASK), sizeof(buf));
+ for (i = 0; i < ARRAYSIZE(buf); i++) {
+ for (j = 0; j < 2; j++);
+ W_REG(&ptr[i], i);
+ }
+ REG_UNMAP(ptr);
+
+ /* Restore PCI window 1 */
+ W_REG(&pci->sbtopci1, sbtopci1);
+
+ /* Check the test array */
+ DMA_UNMAP(NULL, pa, sizeof(buf), DMA_RX, NULL);
+ ptr = (uint32 *) OSL_UNCACHED(&buf[0]);
+ for (i = 0; i < ARRAYSIZE(buf); i++) {
+ if (ptr[i] != i)
+ break;
+ }
+
+ /* Change the clock if the test fails */
+ if (i < ARRAYSIZE(buf)) {
+ uint32 req, cur;
+
+ cur = sb_clock(sbh);
+ printf("PCI: Test failed at %d MHz\n", (cur + 500000) / 1000000);
+ for (req = 104000000; req < 176000000; req += 4000000) {
+ printf("PCI: Resetting to %d MHz\n", (req + 500000) / 1000000);
+ /* This will only reset if the clocks are valid and have changed */
+ sb_mips_setclock(sbh, req, 0, 0);
+ }
+ /* Should not reach here */
+ ASSERT(0);
+ }
+
+ sb_setcoreidx(sbh, coreidx);
+}
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/setup.c b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/setup.c
new file mode 100644
index 000000000..e1b0050a4
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/setup.c
@@ -0,0 +1,251 @@
+/*
+ * Generic setup routines for Broadcom MIPS boards
+ *
+ * Copyright 2004, 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/kernel.h>
+#include <linux/serialP.h>
+#include <linux/ide.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+#include <asm/reboot.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#endif
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <bcmnvram.h>
+#include <sbmips.h>
+#include <sbutils.h>
+#include <trxhdr.h>
+
+extern void bcm947xx_time_init(void);
+extern void bcm947xx_timer_setup(struct irqaction *irq);
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void set_debug_traps(void);
+extern void rs_kgdb_hook(struct serial_state *);
+extern void breakpoint(void);
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+extern struct ide_ops std_ide_ops;
+#endif
+
+/* Global SB handle */
+void *bcm947xx_sbh = NULL;
+spinlock_t bcm947xx_sbh_lock = SPIN_LOCK_UNLOCKED;
+EXPORT_SYMBOL(bcm947xx_sbh);
+EXPORT_SYMBOL(bcm947xx_sbh_lock);
+
+/* Convenience */
+#define sbh bcm947xx_sbh
+#define sbh_lock bcm947xx_sbh_lock
+
+/* Kernel command line */
+char arcs_cmdline[CL_SIZE] __initdata = CONFIG_CMDLINE;
+
+void
+bcm947xx_machine_restart(char *command)
+{
+ printk("Please stand by while rebooting the system...\n");
+
+ /* Set the watchdog timer to reset immediately */
+ __cli();
+ sb_watchdog(sbh, 1);
+ while (1);
+}
+
+void
+bcm947xx_machine_halt(void)
+{
+ printk("System halted\n");
+
+ /* Disable interrupts and watchdog and spin forever */
+ __cli();
+ sb_watchdog(sbh, 0);
+ while (1);
+}
+
+#ifdef CONFIG_SERIAL
+
+static struct serial_struct rs = {
+ line: 0,
+ flags: ASYNC_BOOT_AUTOCONF,
+ io_type: SERIAL_IO_MEM,
+};
+
+static void __init
+serial_add(void *regs, uint irq, uint baud_base, uint reg_shift)
+{
+ rs.iomem_base = regs;
+ rs.irq = irq + 2;
+ rs.baud_base = baud_base / 16;
+ rs.iomem_reg_shift = reg_shift;
+
+ early_serial_setup(&rs);
+
+ rs.line++;
+}
+
+static void __init
+serial_setup(void *sbh)
+{
+ sb_serial_init(sbh, serial_add);
+
+#ifdef CONFIG_REMOTE_DEBUG
+ /* Use the last port for kernel debugging */
+ if (rs.iomem_base)
+ rs_kgdb_hook(&rs);
+#endif
+}
+
+#endif /* CONFIG_SERIAL */
+
+void __init
+brcm_setup(void)
+{
+ char *value;
+
+ /* Get global SB handle */
+ sbh = sb_kattach();
+
+ /* Initialize clocks and interrupts */
+ sb_mips_init(sbh);
+
+#ifdef CONFIG_SERIAL
+ /* Initialize UARTs */
+ serial_setup(sbh);
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ide_ops = &std_ide_ops;
+#endif
+
+ /* Override default command line arguments */
+ value = nvram_get("kernel_args");
+ if (value && strlen(value) && strncmp(value, "empty", 5))
+ strncpy(arcs_cmdline, value, sizeof(arcs_cmdline));
+
+
+ /* Generic setup */
+ _machine_restart = bcm947xx_machine_restart;
+ _machine_halt = bcm947xx_machine_halt;
+ _machine_power_off = bcm947xx_machine_halt;
+
+ board_time_init = bcm947xx_time_init;
+ board_timer_setup = bcm947xx_timer_setup;
+}
+
+const char *
+get_system_type(void)
+{
+ return "Broadcom BCM947XX";
+}
+
+void __init
+bus_error_init(void)
+{
+}
+
+#ifdef CONFIG_MTD_PARTITIONS
+
+static struct mtd_partition bcm947xx_parts[] = {
+ { name: "pmon", 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 = (256*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[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=256*1024;
+
+ /* nvram */
+ bcm947xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
+ bcm947xx_parts[3].size = size - bcm947xx_parts[3].offset;
+
+ /* Size linux (kernel and rootfs) */
+ bcm947xx_parts[1].offset = bcm947xx_parts[0].size;
+ bcm947xx_parts[1].size = bcm947xx_parts[3].offset - bcm947xx_parts[1].offset;
+
+ /* 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;
+ bcm947xx_parts[4].offset = ROUNDUP(bcm947xx_parts[4].offset, mtd->erasesize);
+ bcm947xx_parts[4].size = bcm947xx_parts[3].offset - bcm947xx_parts[4].offset;
+ }
+
+ return bcm947xx_parts;
+}
+
+EXPORT_SYMBOL(init_mtd_partitions);
+
+#endif
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/sflash.c b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/sflash.c
new file mode 100644
index 000000000..4f69880ca
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/sflash.c
@@ -0,0 +1,346 @@
+/*
+ * Broadcom SiliconBackplane chipcommon serial flash interface
+ *
+ * Copyright 2004, 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 <typedefs.h>
+#include <bcmutils.h>
+#include <osl.h>
+#include <sbchipc.h>
+#include <sflash.h>
+
+/* Private global state */
+static struct sflash sflash;
+
+/* Issue a serial flash command */
+static INLINE void
+sflash_cmd(chipcregs_t *cc, uint opcode)
+{
+ W_REG(&cc->flashcontrol, SFLASH_START | opcode);
+ while (R_REG(&cc->flashcontrol) & SFLASH_BUSY);
+}
+
+/* Initialize serial flash access */
+struct sflash *
+sflash_init(chipcregs_t *cc)
+{
+ uint32 id, id2;
+
+ bzero(&sflash, sizeof(sflash));
+
+ sflash.type = R_REG(&cc->capabilities) & CAP_FLASH_MASK;
+
+ switch (sflash.type) {
+ case SFLASH_ST:
+ /* Probe for ST chips */
+ sflash_cmd(cc, SFLASH_ST_DP);
+ sflash_cmd(cc, SFLASH_ST_RES);
+ id = R_REG(&cc->flashdata);
+ switch (id) {
+ case 0x11:
+ /* ST M25P20 2 Mbit Serial Flash */
+ sflash.blocksize = 64 * 1024;
+ sflash.numblocks = 4;
+ break;
+ case 0x12:
+ /* ST M25P40 4 Mbit Serial Flash */
+ sflash.blocksize = 64 * 1024;
+ sflash.numblocks = 8;
+ break;
+ case 0x13:
+ /* ST M25P80 8 Mbit Serial Flash */
+ sflash.blocksize = 64 * 1024;
+ sflash.numblocks = 16;
+ break;
+ case 0x14:
+ /* ST M25P16 16 Mbit Serial Flash */
+ sflash.blocksize = 64 * 1024;
+ sflash.numblocks = 32;
+ break;
+ case 0xbf:
+ W_REG(&cc->flashaddress, 1);
+ sflash_cmd(cc, SFLASH_ST_RES);
+ id2 = R_REG(&cc->flashdata);
+ if (id2 == 0x44) {
+ /* SST M25VF80 4 Mbit Serial Flash */
+ sflash.blocksize = 64 * 1024;
+ sflash.numblocks = 8;
+ }
+ break;
+ }
+ break;
+
+ case SFLASH_AT:
+ /* Probe for Atmel chips */
+ sflash_cmd(cc, SFLASH_AT_STATUS);
+ id = R_REG(&cc->flashdata) & 0x3c;
+ switch (id) {
+ case 0x2c:
+ /* Atmel AT45DB161 16Mbit Serial Flash */
+ sflash.blocksize = 512;
+ sflash.numblocks = 4096;
+ break;
+ case 0x34:
+ /* Atmel AT45DB321 32Mbit Serial Flash */
+ sflash.blocksize = 512;
+ sflash.numblocks = 8192;
+ break;
+ case 0x3c:
+ /* Atmel AT45DB642 64Mbit Serial Flash */
+ sflash.blocksize = 1024;
+ sflash.numblocks = 8192;
+ break;
+ }
+ break;
+ }
+
+ sflash.size = sflash.blocksize * sflash.numblocks;
+ return sflash.size ? &sflash : NULL;
+}
+
+/* Read len bytes starting at offset into buf. Returns number of bytes read. */
+int
+sflash_read(chipcregs_t *cc, uint offset, uint len, uchar *buf)
+{
+ int cnt;
+ uint32 *from, *to;
+
+ if (!len)
+ return 0;
+
+ if ((offset + len) > sflash.size)
+ return -22;
+
+ if ((len >= 4) && (offset & 3))
+ cnt = 4 - (offset & 3);
+ else if ((len >= 4) && ((uint32)buf & 3))
+ cnt = 4 - ((uint32)buf & 3);
+ else
+ cnt = len;
+
+ from = (uint32 *)(CC_FLASH_BASE + offset);
+ to = (uint32 *)buf;
+
+ if (cnt < 4) {
+ bcopy(from, to, cnt);
+ return cnt;
+ }
+
+ while (cnt >= 4) {
+ *to++ = *from++;
+ cnt -= 4;
+ }
+
+ return (len - cnt);
+}
+
+/* Poll for command completion. Returns zero when complete. */
+int
+sflash_poll(chipcregs_t *cc, uint offset)
+{
+ if (offset >= sflash.size)
+ return -22;
+
+ switch (sflash.type) {
+ case SFLASH_ST:
+ /* Check for ST Write In Progress bit */
+ sflash_cmd(cc, SFLASH_ST_RDSR);
+ return R_REG(&cc->flashdata) & SFLASH_ST_WIP;
+ case SFLASH_AT:
+ /* Check for Atmel Ready bit */
+ sflash_cmd(cc, SFLASH_AT_STATUS);
+ return !(R_REG(&cc->flashdata) & SFLASH_AT_READY);
+ }
+
+ return 0;
+}
+
+/* Write len bytes starting at offset into buf. Returns number of bytes
+ * written. Caller should poll for completion.
+ */
+int
+sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
+{
+ struct sflash *sfl;
+ int ret = 0;
+ uint32 page, byte, mask;
+
+ if (!len)
+ return 0;
+
+ if ((offset + len) > sflash.size)
+ return -22;
+
+ sfl = &sflash;
+ switch (sfl->type) {
+ case SFLASH_ST:
+ ret = 1;
+ /* Enable writes */
+ sflash_cmd(cc, SFLASH_ST_WREN);
+ W_REG(&cc->flashaddress, offset);
+ W_REG(&cc->flashdata, *buf);
+ /* Page program */
+ sflash_cmd(cc, SFLASH_ST_PP);
+ break;
+ case SFLASH_AT:
+ mask = sfl->blocksize - 1;
+ page = (offset & ~mask) << 1;
+ byte = offset & mask;
+ /* Read main memory page into buffer 1 */
+ if (byte || len < sfl->blocksize) {
+ W_REG(&cc->flashaddress, page);
+ sflash_cmd(cc, SFLASH_AT_BUF1_LOAD);
+ /* 250 us for AT45DB321B */
+ SPINWAIT(sflash_poll(cc, offset), 1000);
+ ASSERT(!sflash_poll(cc, offset));
+ }
+ /* Write into buffer 1 */
+ for (ret = 0; ret < len && byte < sfl->blocksize; ret++) {
+ W_REG(&cc->flashaddress, byte++);
+ W_REG(&cc->flashdata, *buf++);
+ sflash_cmd(cc, SFLASH_AT_BUF1_WRITE);
+ }
+ /* Write buffer 1 into main memory page */
+ W_REG(&cc->flashaddress, page);
+ sflash_cmd(cc, SFLASH_AT_BUF1_PROGRAM);
+ break;
+ }
+
+ return ret;
+}
+
+/* Erase a region. Returns number of bytes scheduled for erasure.
+ * Caller should poll for completion.
+ */
+int
+sflash_erase(chipcregs_t *cc, uint offset)
+{
+ struct sflash *sfl;
+
+ if (offset >= sflash.size)
+ return -22;
+
+ sfl = &sflash;
+ switch (sfl->type) {
+ case SFLASH_ST:
+ sflash_cmd(cc, SFLASH_ST_WREN);
+ W_REG(&cc->flashaddress, offset);
+ sflash_cmd(cc, SFLASH_ST_SE);
+ return sfl->blocksize;
+ case SFLASH_AT:
+ W_REG(&cc->flashaddress, offset << 1);
+ sflash_cmd(cc, SFLASH_AT_PAGE_ERASE);
+ return sfl->blocksize;
+ }
+
+ return 0;
+}
+
+/*
+ * writes the appropriate range of flash, a NULL buf simply erases
+ * the region of flash
+ */
+int
+sflash_commit(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
+{
+ struct sflash *sfl;
+ uchar *block = NULL, *cur_ptr, *blk_ptr;
+ uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
+ uint blk_offset, blk_len, copied;
+ int bytes, ret = 0;
+
+ /* Check address range */
+ if (len <= 0)
+ return 0;
+
+ sfl = &sflash;
+ if ((offset + len) > sfl->size)
+ return -1;
+
+ blocksize = sfl->blocksize;
+ mask = blocksize - 1;
+
+ /* Allocate a block of mem */
+ if (!(block = MALLOC(blocksize)))
+ return -1;
+
+ while (len) {
+ /* Align offset */
+ cur_offset = offset & ~mask;
+ cur_length = blocksize;
+ cur_ptr = block;
+
+ remainder = blocksize - (offset & mask);
+ if (len < remainder)
+ cur_retlen = len;
+ else
+ cur_retlen = remainder;
+
+ /* buf == NULL means erase only */
+ if (buf) {
+ /* Copy existing data into holding block if necessary */
+ if ((offset & mask) || (len < blocksize)) {
+ blk_offset = cur_offset;
+ blk_len = cur_length;
+ blk_ptr = cur_ptr;
+
+ /* Copy entire block */
+ while(blk_len) {
+ copied = sflash_read(cc, blk_offset, blk_len, blk_ptr);
+ blk_offset += copied;
+ blk_len -= copied;
+ blk_ptr += copied;
+ }
+ }
+
+ /* Copy input data into holding block */
+ memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
+ }
+
+ /* Erase block */
+ if ((ret = sflash_erase(cc, (uint) cur_offset)) < 0)
+ goto done;
+ while (sflash_poll(cc, (uint) cur_offset));
+
+ /* buf == NULL means erase only */
+ if (!buf) {
+ offset += cur_retlen;
+ len -= cur_retlen;
+ continue;
+ }
+
+ /* Write holding block */
+ while (cur_length > 0) {
+ if ((bytes = sflash_write(cc,
+ (uint) cur_offset,
+ (uint) cur_length,
+ (uchar *) cur_ptr)) < 0) {
+ ret = bytes;
+ goto done;
+ }
+ while (sflash_poll(cc, (uint) cur_offset));
+ cur_offset += bytes;
+ cur_length -= bytes;
+ cur_ptr += bytes;
+ }
+
+ offset += cur_retlen;
+ len -= cur_retlen;
+ buf += cur_retlen;
+ }
+
+done:
+ if (block)
+ MFREE(block, blocksize);
+ return ret;
+}
+
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/time.c b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/time.c
new file mode 100644
index 000000000..9b7574663
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/bcm947xx/time.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2004, 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/serial_reg.h>
+#include <linux/interrupt.h>
+#include <asm/addrspace.h>
+#include <asm/io.h>
+#include <asm/time.h>
+
+#include <typedefs.h>
+#include <bcmnvram.h>
+#include <sbconfig.h>
+#include <sbextif.h>
+#include <sbutils.h>
+#include <sbmips.h>
+
+/* Global SB handle */
+extern void *bcm947xx_sbh;
+extern spinlock_t bcm947xx_sbh_lock;
+
+/* Convenience */
+#define sbh bcm947xx_sbh
+#define sbh_lock bcm947xx_sbh_lock
+
+extern int panic_timeout;
+static int watchdog = 0;
+static u8 *mcr = NULL;
+
+void __init
+bcm947xx_time_init(void)
+{
+ unsigned int hz;
+ extifregs_t *eir;
+
+ /*
+ * Use deterministic values for initial counter interrupt
+ * so that calibrate delay avoids encountering a counter wrap.
+ */
+ write_c0_count(0);
+ write_c0_compare(0xffff);
+
+ if (!(hz = sb_mips_clock(sbh)))
+ hz = 100000000;
+
+ printk("CPU: BCM%04x rev %d at %d MHz\n", sb_chip(sbh), sb_chiprev(sbh),
+ (hz + 500000) / 1000000);
+
+ /* Set MIPS counter frequency for fixed_rate_gettimeoffset() */
+ mips_hpt_frequency = hz / 2;
+
+ /* Set watchdog interval in ms */
+ watchdog = simple_strtoul(nvram_safe_get("watchdog"), NULL, 0);
+
+ /* Please set the watchdog to 3 sec if it is less than 3 but not equal to 0 */
+ if (watchdog > 0) {
+ if (watchdog < 3000)
+ watchdog = 3000;
+ }
+
+
+ /* Set panic timeout in seconds */
+ panic_timeout = watchdog / 1000;
+
+ /* Setup blink */
+ if ((eir = sb_setcore(sbh, SB_EXTIF, 0))) {
+ sbconfig_t *sb = (sbconfig_t *)((unsigned int) eir + SBCONFIGOFF);
+ unsigned long base = EXTIF_CFGIF_BASE(sb_base(readl(&sb->sbadmatch1)));
+ mcr = (u8 *) ioremap_nocache(base + UART_MCR, 1);
+ }
+}
+
+static void
+bcm947xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ /* Generic MIPS timer code */
+ timer_interrupt(irq, dev_id, regs);
+
+ /* Set the watchdog timer to reset after the specified number of ms */
+ if (watchdog > 0)
+ sb_watchdog(sbh, WATCHDOG_CLOCK / 1000 * watchdog);
+
+#ifdef CONFIG_HWSIM
+ (*((int *)0xa0000f1c))++;
+#else
+ /* Blink one of the LEDs in the external UART */
+ if (mcr && !(jiffies % (HZ/2)))
+ writeb(readb(mcr) ^ UART_MCR_OUT2, mcr);
+#endif
+}
+
+static struct irqaction bcm947xx_timer_irqaction = {
+ bcm947xx_timer_interrupt,
+ SA_INTERRUPT,
+ 0,
+ "timer",
+ NULL,
+ NULL
+};
+
+void __init
+bcm947xx_timer_setup(struct irqaction *irq)
+{
+ /* Enable the timer interrupt */
+ setup_irq(7, &bcm947xx_timer_irqaction);
+}
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/generic/Makefile b/package/linux/kernel-source/arch/mips/brcm-boards/generic/Makefile
new file mode 100644
index 000000000..e16a80e56
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/generic/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for generic Broadcom MIPS boards
+#
+# Copyright 2004, 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$
+#
+
+.S.s:
+ $(CPP) $(AFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(AFLAGS) -c $< -o $*.o
+
+O_TARGET := brcm.o
+
+obj-y := int-handler.o irq.o
+
+obj-$(CONFIG_REMOTE_DEBUG) += gdb_hook.o
+
+include $(TOPDIR)/Rules.make
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/generic/gdb_hook.c b/package/linux/kernel-source/arch/mips/brcm-boards/generic/gdb_hook.c
new file mode 100644
index 000000000..1345289bb
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/generic/gdb_hook.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2004, 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.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * This is the interface to the remote debugger stub.
+ *
+ */
+
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+
+#include <asm/serial.h>
+#include <asm/io.h>
+
+static struct async_struct kdb_port_info = {0};
+
+static __inline__ unsigned int serial_in(struct async_struct *info, int offset)
+{
+ return readb((unsigned long) info->iomem_base +
+ (offset<<info->iomem_reg_shift));
+}
+
+static __inline__ void serial_out(struct async_struct *info, int offset,
+ int value)
+{
+ writeb(value, (unsigned long) info->iomem_base +
+ (offset<<info->iomem_reg_shift));
+}
+
+void rs_kgdb_hook(struct serial_state *ser) {
+ int t;
+
+ kdb_port_info.state = ser;
+ kdb_port_info.magic = SERIAL_MAGIC;
+ kdb_port_info.port = ser->port;
+ kdb_port_info.flags = ser->flags;
+ kdb_port_info.iomem_base = ser->iomem_base;
+ kdb_port_info.iomem_reg_shift = ser->iomem_reg_shift;
+ kdb_port_info.MCR = UART_MCR_DTR | UART_MCR_RTS;
+
+ /*
+ * Clear all interrupts
+ */
+ serial_in(&kdb_port_info, UART_LSR);
+ serial_in(&kdb_port_info, UART_RX);
+ serial_in(&kdb_port_info, UART_IIR);
+ serial_in(&kdb_port_info, UART_MSR);
+
+ /*
+ * Now, initialize the UART
+ */
+ serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
+ serial_out(&kdb_port_info, UART_MCR, kdb_port_info.MCR);
+
+ /*
+ * and set the speed of the serial port
+ * (currently hardwired to 115200 8N1
+ */
+
+ /* baud rate is fixed to 115200 (is this sufficient?)*/
+ t = kdb_port_info.state->baud_base / 115200;
+ /* set DLAB */
+ serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
+ serial_out(&kdb_port_info, UART_DLL, t & 0xff);/* LS of divisor */
+ serial_out(&kdb_port_info, UART_DLM, t >> 8); /* MS of divisor */
+ /* reset DLAB */
+ serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8);
+}
+
+int putDebugChar(char c)
+{
+
+ if (!kdb_port_info.state) { /* need to init device first */
+ return 0;
+ }
+
+ while ((serial_in(&kdb_port_info, UART_LSR) & UART_LSR_THRE) == 0)
+ ;
+
+ serial_out(&kdb_port_info, UART_TX, c);
+
+ return 1;
+}
+
+char getDebugChar(void)
+{
+ if (!kdb_port_info.state) { /* need to init device first */
+ return 0;
+ }
+
+ while (!(serial_in(&kdb_port_info, UART_LSR) & 1))
+ ;
+
+ return(serial_in(&kdb_port_info, UART_RX));
+}
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/generic/int-handler.S b/package/linux/kernel-source/arch/mips/brcm-boards/generic/int-handler.S
new file mode 100644
index 000000000..de8f115c2
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/generic/int-handler.S
@@ -0,0 +1,51 @@
+/*
+ * Generic interrupt handler for Broadcom MIPS boards
+ *
+ * Copyright 2004, 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 <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+/*
+ * MIPS IRQ Source
+ * -------- ------
+ * 0 Software (ignored)
+ * 1 Software (ignored)
+ * 2 Combined hardware interrupt (hw0)
+ * 3 Hardware
+ * 4 Hardware
+ * 5 Hardware
+ * 6 Hardware
+ * 7 R4k timer
+ */
+
+ .text
+ .set noreorder
+ .set noat
+ .align 5
+ NESTED(brcmIRQ, PT_SIZE, sp)
+ SAVE_ALL
+ CLI
+ .set at
+ .set noreorder
+
+ jal brcm_irq_dispatch
+ move a0, sp
+
+ j ret_from_irq
+ nop
+
+ END(brcmIRQ)
diff --git a/package/linux/kernel-source/arch/mips/brcm-boards/generic/irq.c b/package/linux/kernel-source/arch/mips/brcm-boards/generic/irq.c
new file mode 100644
index 000000000..157c6b380
--- /dev/null
+++ b/package/linux/kernel-source/arch/mips/brcm-boards/generic/irq.c
@@ -0,0 +1,130 @@
+/*
+ * Generic interrupt control functions for Broadcom MIPS boards
+ *
+ * Copyright 2004, 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/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/gdb-stub.h>
+
+#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
+
+extern asmlinkage void brcmIRQ(void);
+extern asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs);
+
+void
+brcm_irq_dispatch(struct pt_regs *regs)
+{
+ u32 cause;
+
+ cause = read_c0_cause() &
+ read_c0_status() &
+ CAUSEF_IP;
+
+#ifdef CONFIG_KERNPROF
+ change_c0_status(cause | 1, 1);
+#else
+ clear_c0_status(cause);
+#endif
+
+ if (cause & CAUSEF_IP7)
+ do_IRQ(7, regs);
+ if (cause & CAUSEF_IP2)
+ do_IRQ(2, regs);
+ if (cause & CAUSEF_IP3)
+ do_IRQ(3, regs);
+ if (cause & CAUSEF_IP4)
+ do_IRQ(4, regs);
+ if (cause & CAUSEF_IP5)
+ do_IRQ(5, regs);
+ if (cause & CAUSEF_IP6)
+ do_IRQ(6, regs);
+}
+
+static void
+enable_brcm_irq(unsigned int irq)
+{
+ if (irq < 8)
+ set_c0_status(1 << (irq + 8));
+ else
+ set_c0_status(IE_IRQ0);
+}
+
+static void
+disable_brcm_irq(unsigned int irq)
+{
+ if (irq < 8)
+ clear_c0_status(1 << (irq + 8));
+ else
+ clear_c0_status(IE_IRQ0);
+}
+
+static void
+ack_brcm_irq(unsigned int irq)
+{
+ /* Already done in brcm_irq_dispatch */
+}
+
+static unsigned int
+startup_brcm_irq(unsigned int irq)
+{
+ enable_brcm_irq(irq);
+
+ return 0; /* never anything pending */
+}
+
+static void
+end_brcm_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_brcm_irq(irq);
+}
+
+static struct hw_interrupt_type brcm_irq_type = {
+ typename: "MIPS",
+ startup: startup_brcm_irq,
+ shutdown: disable_brcm_irq,
+ enable: enable_brcm_irq,
+ disable: disable_brcm_irq,
+ ack: ack_brcm_irq,
+ end: end_brcm_irq,
+ NULL
+};
+
+void __init
+init_IRQ(void)
+{
+ int i;
+
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = 0;
+ irq_desc[i].depth = 1;
+ irq_desc[i].handler = &brcm_irq_type;
+ }
+
+ set_except_vector(0, brcmIRQ);
+ change_c0_status(ST0_IM, ALLINTS);
+
+#ifdef CONFIG_REMOTE_DEBUG
+ printk("Breaking into debugger...\n");
+ set_debug_traps();
+ breakpoint();
+#endif
+}