diff options
Diffstat (limited to 'target/linux/brcm47xx')
44 files changed, 7824 insertions, 0 deletions
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/Makefile b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/Makefile new file mode 100644 index 0000000000..f80945c8b9 --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the BCM47xx specific kernel interface routines +# under Linux. +# + +obj-y := irq.o prom.o setup.o time.o +obj-y += nvram.o cfe_env.o diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/cfe_env.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/cfe_env.c new file mode 100644 index 0000000000..c1d5eeef59 --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/cfe_env.c @@ -0,0 +1,229 @@ +/* + * CFE environment variable access + * + * Copyright 2001-2003, Broadcom Corporation + * Copyright 2006, Felix Fietkau <nbd@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <asm/io.h> +#include <asm/uaccess.h> + +#define NVRAM_SIZE (0x1ff0) +static char _nvdata[NVRAM_SIZE]; +static char _valuestr[256]; + +/* + * TLV types. These codes are used in the "type-length-value" + * encoding of the items stored in the NVRAM device (flash or EEPROM) + * + * The layout of the flash/nvram is as follows: + * + * <type> <length> <data ...> <type> <length> <data ...> <type_end> + * + * The type code of "ENV_TLV_TYPE_END" marks the end of the list. + * The "length" field marks the length of the data section, not + * including the type and length fields. + * + * Environment variables are stored as follows: + * + * <type_env> <length> <flags> <name> = <value> + * + * If bit 0 (low bit) is set, the length is an 8-bit value. + * If bit 0 (low bit) is clear, the length is a 16-bit value + * + * Bit 7 set indicates "user" TLVs. In this case, bit 0 still + * indicates the size of the length field. + * + * Flags are from the constants below: + * + */ +#define ENV_LENGTH_16BITS 0x00 /* for low bit */ +#define ENV_LENGTH_8BITS 0x01 + +#define ENV_TYPE_USER 0x80 + +#define ENV_CODE_SYS(n,l) (((n)<<1)|(l)) +#define ENV_CODE_USER(n,l) ((((n)<<1)|(l)) | ENV_TYPE_USER) + +/* + * The actual TLV types we support + */ + +#define ENV_TLV_TYPE_END 0x00 +#define ENV_TLV_TYPE_ENV ENV_CODE_SYS(0,ENV_LENGTH_8BITS) + +/* + * Environment variable flags + */ + +#define ENV_FLG_NORMAL 0x00 /* normal read/write */ +#define ENV_FLG_BUILTIN 0x01 /* builtin - not stored in flash */ +#define ENV_FLG_READONLY 0x02 /* read-only - cannot be changed */ + +#define ENV_FLG_MASK 0xFF /* mask of attributes we keep */ +#define ENV_FLG_ADMIN 0x100 /* lets us internally override permissions */ + + +/* ********************************************************************* + * _nvram_read(buffer,offset,length) + * + * Read data from the NVRAM device + * + * Input parameters: + * buffer - destination buffer + * offset - offset of data to read + * length - number of bytes to read + * + * Return value: + * number of bytes read, or <0 if error occured + ********************************************************************* */ +static int +_nvram_read(unsigned char *nv_buf, unsigned char *buffer, int offset, int length) +{ + int i; + if (offset > NVRAM_SIZE) + return -1; + + for ( i = 0; i < length; i++) { + buffer[i] = ((volatile unsigned char*)nv_buf)[offset + i]; + } + return length; +} + + +static char* +_strnchr(const char *dest,int c,size_t cnt) +{ + while (*dest && (cnt > 0)) { + if (*dest == c) return (char *) dest; + dest++; + cnt--; + } + return NULL; +} + + + +/* + * Core support API: Externally visible. + */ + +/* + * Get the value of an NVRAM variable + * @param name name of variable to get + * @return value of variable or NULL if undefined + */ + +char* +cfe_env_get(unsigned char *nv_buf, char* name) +{ + int size; + unsigned char *buffer; + unsigned char *ptr; + unsigned char *envval; + unsigned int reclen; + unsigned int rectype; + int offset; + int flg; + + if (!strcmp(name, "nvram_type")) + return "cfe"; + + size = NVRAM_SIZE; + buffer = &_nvdata[0]; + + ptr = buffer; + offset = 0; + + /* Read the record type and length */ + if (_nvram_read(nv_buf, ptr,offset,1) != 1) { + goto error; + } + + while ((*ptr != ENV_TLV_TYPE_END) && (size > 1)) { + + /* Adjust pointer for TLV type */ + rectype = *(ptr); + offset++; + size--; + + /* + * Read the length. It can be either 1 or 2 bytes + * depending on the code + */ + if (rectype & ENV_LENGTH_8BITS) { + /* Read the record type and length - 8 bits */ + if (_nvram_read(nv_buf, ptr,offset,1) != 1) { + goto error; + } + reclen = *(ptr); + size--; + offset++; + } + else { + /* Read the record type and length - 16 bits, MSB first */ + if (_nvram_read(nv_buf, ptr,offset,2) != 2) { + goto error; + } + reclen = (((unsigned int) *(ptr)) << 8) + (unsigned int) *(ptr+1); + size -= 2; + offset += 2; + } + + if (reclen > size) + break; /* should not happen, bad NVRAM */ + + switch (rectype) { + case ENV_TLV_TYPE_ENV: + /* Read the TLV data */ + if (_nvram_read(nv_buf, ptr,offset,reclen) != reclen) + goto error; + flg = *ptr++; + envval = (unsigned char *) _strnchr(ptr,'=',(reclen-1)); + if (envval) { + *envval++ = '\0'; + memcpy(_valuestr,envval,(reclen-1)-(envval-ptr)); + _valuestr[(reclen-1)-(envval-ptr)] = '\0'; +#if 0 + printk(KERN_INFO "NVRAM:%s=%s\n", ptr, _valuestr); +#endif + if(!strcmp(ptr, name)){ + return _valuestr; + } + if((strlen(ptr) > 1) && !strcmp(&ptr[1], name)) + return _valuestr; + } + break; + + default: + /* Unknown TLV type, skip it. */ + break; + } + + /* + * Advance to next TLV + */ + + size -= (int)reclen; + offset += reclen; + + /* Read the next record type */ + ptr = buffer; + if (_nvram_read(nv_buf, ptr,offset,1) != 1) + goto error; + } + +error: + return NULL; + +} + diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/include/nvram.h b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/include/nvram.h new file mode 100644 index 0000000000..6bb18e8e5f --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/include/nvram.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __NVRAM_H +#define __NVRAM_H + +struct nvram_header { + u32 magic; + u32 len; + u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ + u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ + u32 config_ncdl; /* ncdl values for memc */ +}; + +struct nvram_tuple { + char *name; + char *value; + struct nvram_tuple *next; +}; + +#define NVRAM_HEADER 0x48534C46 /* 'FLSH' */ +#define NVRAM_VERSION 1 +#define NVRAM_HEADER_SIZE 20 +#define NVRAM_SPACE 0x8000 + +#define NVRAM_MAX_VALUE_LEN 255 +#define NVRAM_MAX_PARAM_LEN 64 + +char *nvram_get(const char *name); + +#endif diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/irq.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/irq.c new file mode 100644 index 0000000000..d707894353 --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/irq.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) + * Copyright (C) 2008 Michael Buesch <mb@bu3sch.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/smp.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/ssb/ssb.h> + +#include <asm/cpu.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/irq_cpu.h> + + +extern struct ssb_bus ssb; + + +void plat_irq_dispatch(void) +{ + u32 cause; + + cause = read_c0_cause() & read_c0_status() & CAUSEF_IP; + + clear_c0_status(cause); + + if (cause & CAUSEF_IP7) + do_IRQ(7); + if (cause & CAUSEF_IP2) + do_IRQ(2); + if (cause & CAUSEF_IP3) + do_IRQ(3); + if (cause & CAUSEF_IP4) + do_IRQ(4); + if (cause & CAUSEF_IP5) + do_IRQ(5); + if (cause & CAUSEF_IP6) + do_IRQ(6); +} + +void __init arch_init_irq(void) +{ + mips_cpu_irq_init(); +} + +int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + int res; + + res = ssb_pcibios_map_irq(dev, slot, pin); + if (res < 0) { + printk(KERN_ALERT "PCI: Failed to map IRQ of device %s\n", + dev->dev.bus_id); + return 0; + } + /* IRQ-0 and IRQ-1 are software interrupts. */ + WARN_ON((res == 0) || (res == 1)); + + return res; +} diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/nvram.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/nvram.c new file mode 100644 index 0000000000..3f32ad9d6e --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/nvram.c @@ -0,0 +1,125 @@ +/* + * BCM947xx nvram variable access + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, Felix Fietkau <nbd@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/ssb/ssb.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <asm/byteorder.h> +#include <asm/bootinfo.h> +#include <asm/addrspace.h> +#include <asm/io.h> +#include <asm/uaccess.h> + +#include <nvram.h> + +#define MB * 1048576 +extern struct ssb_bus ssb; + +static char nvram_buf[NVRAM_SPACE]; +static int cfe_env; +extern char *cfe_env_get(char *nv_buf, const char *name); + +/* Probe for NVRAM header */ +static void __init early_nvram_init(void) +{ + struct ssb_mipscore *mcore = &ssb.mipscore; + struct nvram_header *header; + int i; + u32 base, lim, off; + u32 *src, *dst; + + base = mcore->flash_window; + lim = mcore->flash_window_size; + cfe_env = 0; + + + /* XXX: hack for supporting the CFE environment stuff on WGT634U */ + if (lim >= 8 MB) { + src = (u32 *) KSEG1ADDR(base + 8 MB - 0x2000); + dst = (u32 *) nvram_buf; + + if ((*src & 0xff00ff) == 0x000001) { + printk("early_nvram_init: WGT634U NVRAM found.\n"); + + for (i = 0; i < 0x1ff0; i++) { + if (*src == 0xFFFFFFFF) + break; + *dst++ = *src++; + } + cfe_env = 1; + return; + } + } + + off = 0x20000; + while (off <= lim) { + /* Windowed flash access */ + header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE); + if (header->magic == NVRAM_HEADER) + goto found; + off <<= 1; + } + + /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ + header = (struct nvram_header *) KSEG1ADDR(base + 4096); + if (header->magic == NVRAM_HEADER) + goto found; + + header = (struct nvram_header *) KSEG1ADDR(base + 1024); + if (header->magic == NVRAM_HEADER) + goto found; + + return; + +found: + src = (u32 *) header; + dst = (u32 *) nvram_buf; + for (i = 0; i < sizeof(struct nvram_header); i += 4) + *dst++ = *src++; + for (; i < header->len && i < NVRAM_SPACE; i += 4) + *dst++ = le32_to_cpu(*src++); +} + +char *nvram_get(const char *name) +{ + char *var, *value, *end, *eq; + + if (!name) + return NULL; + + if (!nvram_buf[0]) + early_nvram_init(); + + if (cfe_env) + return cfe_env_get(nvram_buf, name); + + /* 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; +} + +EXPORT_SYMBOL(nvram_get); diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/prom.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/prom.c new file mode 100644 index 0000000000..41ea0870b7 --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/prom.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/bootmem.h> + +#include <asm/addrspace.h> +#include <asm/bootinfo.h> +#include <asm/pmon.h> +#include "../cfe/cfe_private.h" + +const char *get_system_type(void) +{ + return "Broadcom BCM47xx"; +} + +void __init prom_init(void) +{ + unsigned long mem; + + mips_machgroup = MACH_GROUP_BRCM; + mips_machtype = MACH_BCM47XX; + + cfe_setup(fw_arg0, fw_arg1, fw_arg2, fw_arg3); + + /* 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/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/setup.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/setup.c new file mode 100644 index 0000000000..41d7b0b758 --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/setup.c @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) + * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2006-2008 Michael Buesch <mb@bu3sch.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/init.h> +#include <linux/types.h> +#include <linux/tty.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/serial_reg.h> +#include <linux/serial_8250.h> +#include <asm/bootinfo.h> +#include <asm/time.h> +#include <asm/reboot.h> +#include <asm/cfe.h> +#include <linux/pm.h> +#include <linux/ssb/ssb.h> +#include <linux/ssb/ssb_embedded.h> + +#include <nvram.h> + +extern void bcm47xx_pci_init(void); +extern void bcm47xx_time_init(void); + +struct ssb_bus ssb; + + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + int err; + + err = ssb_pcibios_plat_dev_init(dev); + if (err) { + printk(KERN_ALERT "PCI: Failed to init device %s\n", + pci_name(dev)); + } + + return err; +} + +static void bcm47xx_machine_restart(char *command) +{ + printk(KERN_ALERT "Please stand by while rebooting the system...\n"); + local_irq_disable(); + /* CFE has a reboot callback, but that does not work. + * Oopses with: Reserved instruction in kernel code. + */ + + /* Set the watchdog timer to reset immediately */ + if (ssb_watchdog_timer_set(&ssb, 1)) + printk(KERN_EMERG "SSB watchdog-triggered reboot failed!\n"); + while (1) + cpu_relax(); +} + +static void bcm47xx_machine_halt(void) +{ + /* Disable interrupts and watchdog and spin forever */ + local_irq_disable(); + if (ssb_watchdog_timer_set(&ssb, 0)) + printk(KERN_EMERG "Failed to disable SSB watchdog!\n"); + while (1) + cpu_relax(); +} + +static void e_aton(char *str, char *dest) +{ + int i = 0; + + if (str == NULL) { + memset(dest, 0, 6); + return; + } + + for (;;) { + dest[i++] = (char) simple_strtoul(str, NULL, 16); + str += 2; + if (!*str++ || i == 6) + break; + } +} + +static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) +{ + char *s; + + memset(sprom, 0xFF, sizeof(struct ssb_sprom)); + + sprom->revision = 1; + if ((s = nvram_get("il0macaddr"))) + e_aton(s, sprom->il0mac); + if ((s = nvram_get("et0macaddr"))) + e_aton(s, sprom->et0mac); + if ((s = nvram_get("et1macaddr"))) + e_aton(s, sprom->et1mac); + if ((s = nvram_get("et0phyaddr"))) + sprom->et0phyaddr = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("et1phyaddr"))) + sprom->et1phyaddr = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("et0mdcport"))) + sprom->et0mdcport = !!simple_strtoul(s, NULL, 10); + if ((s = nvram_get("et1mdcport"))) + sprom->et1mdcport = !!simple_strtoul(s, NULL, 10); + if ((s = nvram_get("pa0b0"))) + sprom->pa0b0 = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("pa0b1"))) + sprom->pa0b1 = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("pa0b2"))) + sprom->pa0b2 = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("pa1b0"))) + sprom->pa1b0 = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("pa1b1"))) + sprom->pa1b1 = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("pa1b2"))) + sprom->pa1b2 = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("wl0gpio0"))) + sprom->gpio0 = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("wl0gpio1"))) + sprom->gpio1 = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("wl0gpio2"))) + sprom->gpio2 = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("wl0gpio3"))) + sprom->gpio3 = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("pa0maxpwr"))) + sprom->maxpwr_bg = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("pa1maxpwr"))) + sprom->maxpwr_a = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("pa0itssit"))) + sprom->itssi_bg = simple_strtoul(s, NULL, 0); + if ((s = nvram_get("pa1itssit"))) + sprom->itssi_a = simple_strtoul(s, NULL, 0); + sprom->boardflags_lo = 0; + if ((s = nvram_get("boardflags"))) + sprom->boardflags_lo = simple_strtoul(s, NULL, 0); + sprom->boardflags_hi = 0; + if ((s = nvram_get("boardflags2"))) + sprom->boardflags_hi = simple_strtoul(s, NULL, 0); +} + +static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv) +{ + char *s; + + iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM; + if ((s = nvram_get("boardtype"))) + iv->boardinfo.type = (u16)simple_strtoul(s, NULL, 0); + if ((s = nvram_get("boardrev"))) + iv->boardinfo.rev = (u16)simple_strtoul(s, NULL, 0); + + bcm47xx_fill_sprom(&iv->sprom); + + if ((s = nvram_get("cardbus"))) + iv->has_cardbus_slot = !!simple_strtoul(s, NULL, 10); + + return 0; +} + +void __init plat_mem_setup(void) +{ + int i, err; + char *s; + struct ssb_mipscore *mcore; + + err = ssb_bus_ssbbus_register(&ssb, SSB_ENUM_BASE, bcm47xx_get_invariants); + if (err) { + const char *msg = "Failed to initialize SSB bus (err %d)\n"; + cfe_printk(msg, err); /* Make sure the message gets out of the box. */ + panic(msg, err); + } + mcore = &ssb.mipscore; + + s = nvram_get("kernel_args"); + if (s && !strncmp(s, "console=ttyS1", 13)) { + struct ssb_serial_port port; + + cfe_printk("Swapping serial ports!\n"); + /* swap serial ports */ + memcpy(&port, &mcore->serial_ports[0], sizeof(port)); + memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1], sizeof(port)); + memcpy(&mcore->serial_ports[1], &port, sizeof(port)); + } + + for (i = 0; i < mcore->nr_serial_ports; i++) { + struct ssb_serial_port *port = &(mcore->serial_ports[i]); + struct uart_port s; + + memset(&s, 0, sizeof(s)); + s.line = i; + s.membase = port->regs; + s.irq = port->irq + 2; + s.uartclk = port->baud_base; + s.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; + s.iotype = SERIAL_IO_MEM; + s.regshift = port->reg_shift; + + early_serial_setup(&s); + } + cfe_printk("Serial init done.\n"); + + _machine_restart = bcm47xx_machine_restart; + _machine_halt = bcm47xx_machine_halt; + pm_power_off = bcm47xx_machine_halt; + board_time_init = bcm47xx_time_init; +} + +static int __init bcm47xx_register_gpiodev(void) +{ + static struct resource res = { + .start = 0xFFFFFFFF, + }; + struct platform_device *pdev; + + pdev = platform_device_register_simple("GPIODEV", 0, &res, 1); + if (!pdev) { + printk(KERN_ERR "bcm47xx: GPIODEV init failed\n"); + return -ENODEV; + } + + return 0; +} +device_initcall(bcm47xx_register_gpiodev); + +EXPORT_SYMBOL(ssb); diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/time.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/time.c new file mode 100644 index 0000000000..62120ebc74 --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/time.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/serial_reg.h> +#include <linux/interrupt.h> +#include <linux/ssb/ssb.h> +#include <asm/addrspace.h> +#include <asm/io.h> +#include <asm/time.h> + +extern struct ssb_bus ssb; + +void __init +bcm47xx_time_init(void) +{ + unsigned long hz; + + /* + * Use deterministic values for initial counter interrupt + * so that calibrate delay avoids encountering a counter wrap. + */ + write_c0_count(0); + write_c0_compare(0xffff); + + hz = ssb_cpu_clock(&ssb.mipscore) / 2; + if (!hz) + hz = 100000000; + + /* Set MIPS counter frequency for fixed_rate_gettimeoffset() */ + mips_hpt_frequency = hz; +} + +void __init +plat_timer_setup(struct irqaction *irq) +{ + /* Enable the timer interrupt */ + setup_irq(7, irq); +} diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/Makefile b/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/Makefile new file mode 100644 index 0000000000..d9f046adf3 --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Broadcom Common Firmware Environment support +# + +obj-y += cfe.o diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/cfe.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/cfe.c new file mode 100644 index 0000000000..6d16111e1c --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/cfe.c @@ -0,0 +1,533 @@ +/* + * Broadcom Common Firmware Environment (CFE) support + * + * Copyright 2000, 2001, 2002 + * Broadcom Corporation. All rights reserved. + * + * Copyright (C) 2006 Michael Buesch + * + * Original Authors: Mitch Lichtenberg, Chris Demetriou + * + * This software is furnished under license and may be used and copied only + * in accordance with the following terms and conditions. Subject to these + * conditions, you may download, copy, install, use, modify and distribute + * modified or unmodified copies of this software in source and/or binary + * form. No title or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce and + * retain this copyright notice and list of conditions as they appear in + * the source file. + * + * 2) No right is granted to use any trade name, trademark, or logo of + * Broadcom Corporation. The "Broadcom Corporation" name may not be + * used to endorse or promote products derived from this software + * without the prior written permission of Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE + * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE + * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/init.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/spinlock.h> +#include <asm/cfe.h> + +#include "cfe_private.h" + + +static cfe_uint_t cfe_handle; +static int (*cfe_trampoline)(long handle, long iocb); + + +#include <linux/kernel.h> + +void __init cfe_setup(unsigned long fwarg0, unsigned long fwarg1, + unsigned long fwarg2, unsigned long fwarg3) +{ + if (fwarg3 == 0x80300000) { + /* WRT54G workaround */ + fwarg3 = CFE_EPTSEAL; + fwarg2 = 0xBFC00500; + } + if (fwarg3 != CFE_EPTSEAL) { + /* We are not booted from CFE */ + return; + } + if (fwarg1 == 0) { + /* We are on the boot CPU */ + cfe_handle = (cfe_uint_t)fwarg0; + cfe_trampoline = CFE_TO_PTR(fwarg2); + } +} + +int cfe_vprintk(const char *fmt, va_list args) +{ + static char buffer[1024]; + static DEFINE_SPINLOCK(lock); + static const char pfx[] = "CFE-console: "; + static const size_t pfx_len = sizeof(pfx) - 1; + unsigned long flags; + int len, cnt, pos; + int handle; + int res; + + if (!cfe_present()) + return -ENODEV; + + spin_lock_irqsave(&lock, flags); + handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); + if (CFE_ISERR(handle)) { + len = -EIO; + goto out; + } + strcpy(buffer, pfx); + len = vscnprintf(buffer + pfx_len, + sizeof(buffer) - pfx_len - 2, + fmt, args); + len += pfx_len; + /* The CFE console requires CR-LF line-ends. + * Add a CR, if we only terminate lines with a LF. + * This does only fix CR-LF at the end of the string. + * So for multiple lines, use multiple cfe_vprintk calls. + */ + if (len > 1 && + buffer[len - 1] == '\n' && buffer[len - 2] != '\r') { + buffer[len - 1] = '\r'; + buffer[len] = '\n'; + len += 1; + } + cnt = len; + pos = 0; + while (cnt > 0) { + res = cfe_write(handle, buffer + pos, len - pos); + if (CFE_ISERR(res)) { + len = -EIO; + goto out; + } + cnt -= res; + pos += res; + } +out: + spin_unlock_irqrestore(&lock, flags); + + return len; +} + +int cfe_printk(const char *fmt, ...) +{ + va_list args; + int res; + + va_start(args, fmt); + res = cfe_vprintk(fmt, args); + va_end(args); + + return res; +} + +static int cfe_iocb_dispatch(struct cfe_iocb *iocb) +{ + if (!cfe_present()) + return CFE_ERR_UNSUPPORTED; + return cfe_trampoline((long)cfe_handle, (long)iocb); +} + +int cfe_present(void) +{ + return (cfe_trampoline != NULL); +} + +int cfe_close(int handle) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_DEV_CLOSE; + iocb.handle = handle; + + err = cfe_iocb_dispatch(&iocb); + + return (CFE_ISERR(err)) ? err : iocb.status; +} + +int cfe_cpu_start(int cpu, void (*fn)(void), long sp, long gp, long a1) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_FW_CPUCTL; + iocb.psize = sizeof(struct cfe_iocb_cpuctl); + iocb.cpuctl.number = cpu; + iocb.cpuctl.command = CFE_CPU_CMD_START; + iocb.cpuctl.gp = gp; + iocb.cpuctl.sp = sp; + iocb.cpuctl.a1 = a1; + iocb.cpuctl.start_addr = (long)fn; + + err = cfe_iocb_dispatch(&iocb); + + return (CFE_ISERR(err)) ? err : iocb.status; +} + +int cfe_cpu_stop(int cpu) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_FW_CPUCTL; + iocb.psize = sizeof(struct cfe_iocb_cpuctl); + iocb.cpuctl.number = cpu; + iocb.cpuctl.command = CFE_CPU_CMD_STOP; + + err = cfe_iocb_dispatch(&iocb); + + return (CFE_ISERR(err)) ? err : iocb.status; +} + +int cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_ENV_ENUM; + iocb.psize = sizeof(struct cfe_iocb_envbuf); + iocb.envbuf.index = idx; + iocb.envbuf.name = PTR_TO_CFE(name); + iocb.envbuf.name_len = namelen; + iocb.envbuf.val = PTR_TO_CFE(val); + iocb.envbuf.val_len = vallen; + + err = cfe_iocb_dispatch(&iocb); + + return (CFE_ISERR(err)) ? err : iocb.status; +} + +int cfe_enumdev(int idx, char *name, int namelen) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + + iocb.fcode = CFE_CMD_DEV_ENUM; + iocb.psize = sizeof(struct cfe_iocb_envbuf); + iocb.envbuf.index = idx; + iocb.envbuf.name = PTR_TO_CFE(name); + iocb.envbuf.name_len = namelen; + + err = cfe_iocb_dispatch(&iocb); + + return (CFE_ISERR(err)) ? err : iocb.status; +} + +int cfe_enummem(int idx, int flags, u64 *start, u64 *length, + u64 *type) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + + iocb.fcode = CFE_CMD_FW_MEMENUM; + iocb.flags = flags; + iocb.psize = sizeof(struct cfe_iocb_meminfo); + iocb.meminfo.index = idx; + + err = cfe_iocb_dispatch(&iocb); + if (CFE_ISERR(err)) + return err; + if (!CFE_ISERR(iocb.status)) { + *start = iocb.meminfo.addr; + *length = iocb.meminfo.size; + *type = iocb.meminfo.type; + } + + return iocb.status; +} + +int cfe_exit(int warm, int status) +{ + struct cfe_iocb iocb; + int err; + +printk("CFE REBOOT\n"); + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_FW_RESTART; + if (warm) + iocb.flags = CFE_FLG_WARMSTART; + iocb.psize = sizeof(struct cfe_iocb_exitstat); + iocb.exitstat.status = status; + +printk("CALL\n"); + err = cfe_iocb_dispatch(&iocb); +printk("DONE\n"); + + return (CFE_ISERR(err)) ? err : iocb.status; +} + +int cfe_flushcache(int flags) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_FW_FLUSHCACHE; + iocb.flags = flags; + + err = cfe_iocb_dispatch(&iocb); + + return (CFE_ISERR(err)) ? err : iocb.status; +} + +int cfe_getdevinfo(char *name) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_DEV_GETINFO; + iocb.psize = sizeof(struct cfe_iocb_buf); + iocb.buffer.ptr = PTR_TO_CFE(name); + iocb.buffer.length = strlen(name); + + err = cfe_iocb_dispatch(&iocb); + if (CFE_ISERR(err)) + return err; + if (CFE_ISERR(iocb.status)) + return iocb.status; + + return iocb.buffer.devflags; +} + +int cfe_getenv(char *name, char *dest, int destlen) +{ + struct cfe_iocb iocb; + int err; + + dest[0] = '\0'; + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_ENV_GET; + iocb.psize = sizeof(struct cfe_iocb_envbuf); + iocb.envbuf.name = PTR_TO_CFE(name); + iocb.envbuf.name_len = strlen(name); + iocb.envbuf.val = PTR_TO_CFE(dest); + iocb.envbuf.val_len = destlen; + + err = cfe_iocb_dispatch(&iocb); + + return (CFE_ISERR(err)) ? err : iocb.status; +} + +int cfe_getfwinfo(struct cfe_fwinfo *info) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_FW_GETINFO; + iocb.psize = sizeof(struct cfe_iocb_fwinfo); + + err = cfe_iocb_dispatch(&iocb); + if (CFE_ISERR(err)) + return err; + if (CFE_ISERR(iocb.status)) + return err; + + info->version = iocb.fwinfo.version; + info->totalmem = iocb.fwinfo.totalmem; + info->flags = iocb.fwinfo.flags; + info->boardid = iocb.fwinfo.boardid; + info->bootarea_va = iocb.fwinfo.bootarea_va; + info->bootarea_pa = iocb.fwinfo.bootarea_pa; + info->bootarea_size = iocb.fwinfo.bootarea_size; + + return iocb.status; +} + +int cfe_getstdhandle(int handletype) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_DEV_GETHANDLE; + iocb.flags = handletype; + + err = cfe_iocb_dispatch(&iocb); + if (CFE_ISERR(err)) + return err; + if (CFE_ISERR(iocb.status)) + return iocb.status; + + return iocb.handle; +} + +int cfe_getticks(s64 *ticks) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_FW_GETTIME; + iocb.psize = sizeof(struct cfe_iocb_time); + + err = cfe_iocb_dispatch(&iocb); + if (CFE_ISERR(err)) + return err; + if (!CFE_ISERR(iocb.status)) + *ticks = iocb.time.ticks; + + return iocb.status; +} + +int cfe_inpstat(int handle) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_DEV_INPSTAT; + iocb.handle = handle; + iocb.psize = sizeof(struct cfe_iocb_inpstat); + + err = cfe_iocb_dispatch(&iocb); + if (CFE_ISERR(err)) + return err; + if (CFE_ISERR(iocb.status)) + return iocb.status; + + return iocb.inpstat.status; +} + +int cfe_ioctl(int handle, unsigned int ioctlnum, + unsigned char *buffer, int length, + int *retlen, u64 offset) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_DEV_IOCTL; + iocb.handle = handle; + iocb.psize = sizeof(struct cfe_iocb_buf); + iocb.buffer.offset = offset; + iocb.buffer.ioctlcmd = ioctlnum; + iocb.buffer.ptr = PTR_TO_CFE(buffer); + iocb.buffer.length = length; + + err = cfe_iocb_dispatch(&iocb); + if (CFE_ISERR(err)) + return err; + if (CFE_ISERR(iocb.status)) + return iocb.status; + if (retlen) + *retlen = iocb.buffer.retlen; + + return iocb.status; +} + +int cfe_open(char *name) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_DEV_OPEN; + iocb.psize = sizeof(struct cfe_iocb_buf); + iocb.buffer.ptr = PTR_TO_CFE(name); + iocb.buffer.length = strlen(name); + + err = cfe_iocb_dispatch(&iocb); + if (CFE_ISERR(err)) + return err; + if (CFE_ISERR(iocb.status)) + return iocb.status; + + return iocb.handle; +} + +int cfe_read(int handle, unsigned char *buffer, int length) +{ + return cfe_readblk(handle, 0, buffer, length); +} + +int cfe_readblk(int handle, s64 offset, unsigned char *buffer, int length) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_DEV_READ; + iocb.handle = handle; + iocb.psize = sizeof(struct cfe_iocb_buf); + iocb.buffer.offset = offset; + iocb.buffer.ptr = PTR_TO_CFE(buffer); + iocb.buffer.length = length; + + err = cfe_iocb_dispatch(&iocb); + if (CFE_ISERR(err)) + return err; + if (CFE_ISERR(iocb.status)) + return iocb.status; + + return iocb.buffer.retlen; +} + +int cfe_setenv(char *name, char *val) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_ENV_SET; + iocb.psize = sizeof(struct cfe_iocb_envbuf); + iocb.envbuf.name = PTR_TO_CFE(name); + iocb.envbuf.name_len = strlen(name); + iocb.envbuf.val = PTR_TO_CFE(val); + iocb.envbuf.val_len = strlen(val); + + err = cfe_iocb_dispatch(&iocb); + + return (CFE_ISERR(err)) ? err : iocb.status; +} + +int cfe_write(int handle, unsigned char *buffer, int length) +{ + return cfe_writeblk(handle, 0, buffer, length); +} + +int cfe_writeblk(int handle, s64 offset, unsigned char *buffer, int length) +{ + struct cfe_iocb iocb; + int err; + + memset(&iocb, 0, sizeof(iocb)); + iocb.fcode = CFE_CMD_DEV_WRITE; + iocb.handle = handle; + iocb.psize = sizeof(struct cfe_iocb_buf); + iocb.buffer.offset = offset; + iocb.buffer.ptr = PTR_TO_CFE(buffer); + iocb.buffer.length = length; + + err = cfe_iocb_dispatch(&iocb); + if (CFE_ISERR(err)) + return err; + if (CFE_ISERR(iocb.status)) + return iocb.status; + + return iocb.buffer.retlen; +} diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/cfe_private.h b/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/cfe_private.h new file mode 100644 index 0000000000..0a604d3bbd --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/cfe_private.h @@ -0,0 +1,176 @@ +/* + * Broadcom Common Firmware Environment (CFE) support + * + * Copyright 2000, 2001, 2002 + * Broadcom Corporation. All rights reserved. + * + * Copyright (C) 2006 Michael Buesch + * + * Original Authors: Mitch Lichtenberg, Chris Demetriou + * + * This software is furnished under license and may be used and copied only + * in accordance with the following terms and conditions. Subject to these + * conditions, you may download, copy, install, use, modify and distribute + * modified or unmodified copies of this software in source and/or binary + * form. No title or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce and + * retain this copyright notice and list of conditions as they appear in + * the source file. + * + * 2) No right is granted to use any trade name, trademark, or logo of + * Broadcom Corporation. The "Broadcom Corporation" name may not be + * used to endorse or promote products derived from this software + * without the prior written permission of Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE + * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE + * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LINUX_CFE_PRIVATE_H_ +#define LINUX_CFE_PRIVATE_H_ + +#ifndef __ASSEMBLY__ + +/* Seal indicating CFE's presence, passed to the kernel. */ +#define CFE_EPTSEAL 0x43464531 + +#define CFE_CMD_FW_GETINFO 0 +#define CFE_CMD_FW_RESTART 1 +#define CFE_CMD_FW_BOOT 2 +#define CFE_CMD_FW_CPUCTL 3 +#define CFE_CMD_FW_GETTIME 4 +#define CFE_CMD_FW_MEMENUM 5 +#define CFE_CMD_FW_FLUSHCACHE 6 + +#define CFE_CMD_DEV_GETHANDLE 9 +#define CFE_CMD_DEV_ENUM 10 +#define CFE_CMD_DEV_OPEN 11 +#define CFE_CMD_DEV_INPSTAT 12 +#define CFE_CMD_DEV_READ 13 +#define CFE_CMD_DEV_WRITE 14 +#define CFE_CMD_DEV_IOCTL 15 +#define CFE_CMD_DEV_CLOSE 16 +#define CFE_CMD_DEV_GETINFO 17 + +#define CFE_CMD_ENV_ENUM 20 +#define CFE_CMD_ENV_GET 22 +#define CFE_CMD_ENV_SET 23 +#define CFE_CMD_ENV_DEL 24 + +#define CFE_CMD_MAX 32 + +#define CFE_CMD_VENDOR_USE 0x8000 /* codes above this are for customer use */ + +typedef u64 cfe_uint_t; +typedef s64 cfe_int_t; +typedef s64 cfe_ptr_t; + +/* Cast a pointer from native to CFE-API pointer and back */ +#define CFE_TO_PTR(p) ((void *)(unsigned long)(p)) +#define PTR_TO_CFE(p) ((cfe_ptr_t)(unsigned long)(p)) + +struct cfe_iocb_buf { + cfe_uint_t offset; /* offset on device (bytes) */ + cfe_ptr_t ptr; /* pointer to a buffer */ + cfe_uint_t length; /* length of this buffer */ + cfe_uint_t retlen; /* returned length (for read ops) */ + union { + cfe_uint_t ioctlcmd; /* IOCTL command (used only for IOCTLs) */ + cfe_uint_t devflags; /* Returned device info flags */ + }; +}; + +struct cfe_iocb_inpstat { + cfe_uint_t status; /* 1 means input available */ +}; + +struct cfe_iocb_envbuf { + cfe_int_t index; /* 0-based enumeration index */ + cfe_ptr_t name; /* name string buffer */ + cfe_int_t name_len; /* size of name buffer */ + cfe_ptr_t val; /* value string buffer */ + cfe_int_t val_len; /* size of value string buffer */ +}; + +struct cfe_iocb_cpuctl { + cfe_uint_t number; /* cpu number to control */ + cfe_uint_t command; /* command to issue to CPU */ + cfe_uint_t start_addr; /* CPU start address */ + cfe_uint_t gp; /* starting GP value */ + cfe_uint_t sp; /* starting SP value */ + cfe_uint_t a1; /* starting A1 value */ +}; + +struct cfe_iocb_time { + cfe_int_t ticks; /* current time in ticks */ +}; + +struct cfe_iocb_exitstat { + cfe_int_t status; +}; + +struct cfe_iocb_meminfo { + cfe_int_t index; /* 0-based enumeration index */ + cfe_int_t type; /* type of memory block */ + cfe_uint_t addr; /* physical start address */ + cfe_uint_t size; /* block size */ +}; + +struct cfe_iocb_fwinfo { + cfe_int_t version; /* major, minor, eco version */ + cfe_int_t totalmem; /* total installed mem */ + cfe_int_t flags; /* various flags */ + cfe_int_t boardid; /* board ID */ + cfe_int_t bootarea_va; /* VA of boot area */ + cfe_int_t bootarea_pa; /* PA of boot area */ + cfe_int_t bootarea_size; /* size of boot area */ + cfe_int_t reserved1; + cfe_int_t reserved2; + cfe_int_t reserved3; +}; + +/* CFE I/O Control Block */ +struct cfe_iocb { + cfe_uint_t fcode; /* IOCB function code */ + cfe_int_t status; /* return status */ + cfe_int_t handle; /* file/device handle */ + cfe_uint_t flags; /* flags for this IOCB */ + cfe_uint_t psize; /* size of parameter list */ + union { + struct cfe_iocb_buf buffer; /* buffer parameters */ + struct cfe_iocb_inpstat inpstat; /* input status parameters */ + struct cfe_iocb_envbuf envbuf; /* environment function parameters */ + struct cfe_iocb_cpuctl cpuctl; /* CPU control parameters */ + struct cfe_iocb_time time; /* timer parameters */ + struct cfe_iocb_meminfo meminfo; /* memory arena info parameters */ + struct cfe_iocb_fwinfo fwinfo; /* firmware information */ + struct cfe_iocb_exitstat exitstat; /* Exit Status */ + }; +}; + + +#include <linux/init.h> + +void __init cfe_setup(unsigned long fwarg0, unsigned long fwarg1, + unsigned long fwarg2, unsigned long fwarg3); + +#else /* __ASSEMBLY__ */ + + .macro cfe_early_init +#ifdef CONFIG_CFE + jal cfe_setup +#endif + .endm + +#endif /* __ASSEMBLY__ */ +#endif /* LINUX_CFE_PRIVATE_H_ */ diff --git a/target/linux/brcm47xx/files-2.6.25/drivers/mtd/maps/bcm47xx-flash.c b/target/linux/brcm47xx/files-2.6.25/drivers/mtd/maps/bcm47xx-flash.c new file mode 100644 index 0000000000..6a82f362c6 --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/drivers/mtd/maps/bcm47xx-flash.c @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> + * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) + * + * original functions for finding root filesystem from Mike Baker + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Copyright 2001-2003, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * Flash mapping for BCM947XX boards + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#ifdef CONFIG_MTD_PARTITIONS +#include <linux/mtd/partitions.h> +#endif +#include <linux/crc32.h> +#ifdef CONFIG_SSB +#include <linux/ssb/ssb.h> +#endif +#include <asm/io.h> + + +#define TRX_MAGIC 0x30524448 /* "HDR0" */ +#define TRX_VERSION 1 +#define TRX_MAX_LEN 0x3A0000 +#define TRX_NO_HEADER 1 /* Do not write TRX header */ +#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ +#define TRX_MAX_OFFSET 3 + +struct trx_header { + u32 magic; /* "HDR0" */ + u32 len; /* Length of file including header */ + u32 crc32; /* 32-bit CRC from flag_version to end of file */ + u32 flag_version; /* 0:15 flags, 16:31 version */ + u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ +}; + +#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) +#define NVRAM_SPACE 0x8000 +#define WINDOW_ADDR 0x1fc00000 +#define WINDOW_SIZE 0x400000 +#define BUSWIDTH 2 + +#ifdef CONFIG_SSB +extern struct ssb_bus ssb; +#endif +static struct mtd_info *bcm947xx_mtd; + +static void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + if (len==1) { + memcpy_fromio(to, map->virt + from, len); + } else { + int i; + u16 *dest = (u16 *) to; + u16 *src = (u16 *) (map->virt + from); + for (i = 0; i < (len / 2); i++) { + dest[i] = src[i]; + } + if (len & 1) + *((u8 *)dest+len-1) = src[i] & 0xff; + } +} + +static struct map_info bcm947xx_map = { + name: "Physically mapped flash", + size: WINDOW_SIZE, + bankwidth: BUSWIDTH, + phys: WINDOW_ADDR, +}; + +#ifdef CONFIG_MTD_PARTITIONS + +static struct mtd_partition bcm947xx_parts[] = { + { name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, }, + { name: "linux", offset: 0, size: 0, }, + { name: "rootfs", offset: 0, size: 0, }, + { name: "nvram", offset: 0, size: 0, }, + { name: NULL, }, +}; + +static int __init +find_cfe_size(struct mtd_info *mtd, size_t size) +{ + struct trx_header *trx; + unsigned char buf[512]; + int off; + size_t len; + int blocksize; + + trx = (struct trx_header *) buf; + + blocksize = mtd->erasesize; + if (blocksize < 0x10000) + blocksize = 0x10000; + + for (off = (128*1024); off < size; off += blocksize) { + 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) { + goto found; + } + } + + printk(KERN_NOTICE + "%s: Couldn't find bootloader size\n", + mtd->name); + return -1; + + found: + printk(KERN_NOTICE "bootloader size: %d\n", off); + return off; + +} + +/* + * Copied from mtdblock.c + * + * Cache stuff... + * + * Since typical flash erasable sectors are much larger than what Linux's + * buffer cache can handle, we must implement read-modify-write on flash + * sectors for each block write requests. To avoid over-erasing flash sectors + * and to speed things up, we locally cache a whole flash sector while it is + * being written to until a different sector is required. + */ + +static void erase_callback(struct erase_info *done) +{ + wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; + wake_up(wait_q); +} + +static int erase_write (struct mtd_info *mtd, unsigned long pos, + int len, const char *buf) +{ + struct erase_info erase; + DECLARE_WAITQUEUE(wait, current); + wait_queue_head_t wait_q; + size_t retlen; + int ret; + + /* + * First, let's erase the flash block. + */ + + init_waitqueue_head(&wait_q); + erase.mtd = mtd; + erase.callback = erase_callback; + erase.addr = pos; + erase.len = len; + erase.priv = (u_long)&wait_q; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&wait_q, &wait); + + ret = mtd->erase(mtd, &erase); + if (ret) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&wait_q, &wait); + printk (KERN_WARNING "erase of region [0x%lx, 0x%x] " + "on \"%s\" failed\n", + pos, len, mtd->name); + return ret; + } + + schedule(); /* Wait for erase to finish. */ + remove_wait_queue(&wait_q, &wait); + + /* + * Next, writhe data to flash. + */ + + ret = mtd->write (mtd, pos, len, &retlen, buf); + if (ret) + return ret; + if (retlen != len) + return -EIO; + return 0; +} + + + + +static int __init +find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part) +{ + struct trx_header trx, *trx2; + unsigned char buf[512], *block; + int off, blocksize; + u32 i, crc = ~0; + size_t len; + struct squashfs_super_block *sb = (struct squashfs_super_block *) buf; + + blocksize = mtd->erasesize; + if (blocksize < 0x10000) + blocksize = 0x10000; + + for (off = (128*1024); off < size; off += blocksize) { + memset(&trx, 0xe5, sizeof(trx)); + + /* + * Read into buffer + */ + if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || + len != sizeof(trx)) + continue; + + /* found a TRX header */ + if (le32_to_cpu(trx.magic) == TRX_MAGIC) { + part->offset = le32_to_cpu(trx.offsets[2]) ? : + le32_to_cpu(trx.offsets[1]); + part->size = le32_to_cpu(trx.len); + + part->size -= part->offset; + part->offset += off; + + goto found; + } + } + + printk(KERN_NOTICE + "%s: Couldn't find root filesystem\n", + mtd->name); + return -1; + + found: + if (part->size == 0) + return 0; + + if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf)) + return 0; + + /* Move the fs outside of the trx */ + part->size = 0; + + if (trx.len != part->offset + part->size - off) { + /* Update the trx offsets and length */ + trx.len = part->offset + part->size - off; + + /* Update the trx crc32 */ + for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) { + if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf)) + return 0; + crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i)); + } + trx.crc32 = crc; + + /* read first eraseblock from the trx */ + block = kmalloc(mtd->erasesize, GFP_KERNEL); + trx2 = (struct trx_header *) block; + if (mtd->read(mtd, off, mtd->erasesize, &len, block) || len != mtd->erasesize) { + printk("Error accessing the first trx eraseblock\n"); + return 0; + } + + printk("Updating TRX offsets and length:\n"); + printk("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32); + printk("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32); + + /* Write updated trx header to the flash */ + memcpy(block, &trx, sizeof(trx)); + if (mtd->unlock) + mtd->unlock(mtd, off, mtd->erasesize); + erase_write(mtd, off, mtd->erasesize, block); + if (mtd->sync) + mtd->sync(mtd); + kfree(block); + printk("Done\n"); + } + + return part->size; +} + +struct mtd_partition * __init +init_mtd_partitions(struct mtd_info *mtd, size_t size) +{ + int cfe_size; + + if ((cfe_size = find_cfe_size(mtd,size)) < 0) + return NULL; + + /* boot loader */ + bcm947xx_parts[0].offset = 0; + bcm947xx_parts[0].size = cfe_size; + + /* nvram */ + if (cfe_size != 384 * 1024) { + bcm947xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize); + bcm947xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); + } else { + /* nvram (old 128kb config partition on netgear wgt634u) */ + bcm947xx_parts[3].offset = bcm947xx_parts[0].size; + bcm947xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize); + } + + /* linux (kernel and rootfs) */ + if (cfe_size != 384 * 1024) { + bcm947xx_parts[1].offset = bcm947xx_parts[0].size; + bcm947xx_parts[1].size = bcm947xx_parts[3].offset - + bcm947xx_parts[1].offset; + } else { + /* do not count the elf loader, which is on one block */ + bcm947xx_parts[1].offset = bcm947xx_parts[0].size + + bcm947xx_parts[3].size + mtd->erasesize; + bcm947xx_parts[1].size = size - + bcm947xx_parts[0].size - + (2*bcm947xx_parts[3].size) - + mtd->erasesize; + } + + /* find and size rootfs */ + find_root(mtd,size,&bcm947xx_parts[2]); + bcm947xx_parts[2].size = size - bcm947xx_parts[2].offset - bcm947xx_parts[3].size; + + return bcm947xx_parts; +} +#endif + +int __init init_bcm947xx_map(void) +{ +#ifdef CONFIG_SSB + struct ssb_mipscore *mcore = &ssb.mipscore; +#endif + size_t size; + int ret = 0; +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *parts; + int i; +#endif + +#ifdef CONFIG_SSB + u32 window = mcore->flash_window; + u32 window_size = mcore->flash_window_size; + + printk("flash init: 0x%08x 0x%08x\n", window, window_size); + bcm947xx_map.phys = window; + bcm947xx_map.size = window_size; + bcm947xx_map.virt = ioremap_nocache(window, window_size); +#else + printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE); + bcm947xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); +#endif + + if (!bcm947xx_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + } + + simple_map_init(&bcm947xx_map); + + if (!(bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map))) { + printk("Failed to do_map_probe\n"); + iounmap((void *)bcm947xx_map.virt); + return -ENXIO; + } + + /* override copy_from routine */ + bcm947xx_map.copy_from = bcm947xx_map_copy_from; + + bcm947xx_mtd->owner = THIS_MODULE; + + size = bcm947xx_mtd->size; + + printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR); + +#ifdef CONFIG_MTD_PARTITIONS + parts = init_mtd_partitions(bcm947xx_mtd, size); + for (i = 0; parts[i].name; i++); + ret = add_mtd_partitions(bcm947xx_mtd, parts, i); + if (ret) { + printk(KERN_ERR "Flash: add_mtd_partitions failed\n"); + goto fail; + } +#endif + return 0; + + fail: + if (bcm947xx_mtd) + map_destroy(bcm947xx_mtd); + if (bcm947xx_map.virt) + iounmap((void *)bcm947xx_map.virt); + bcm947xx_map.virt = 0; + return ret; +} + +void __exit cleanup_bcm947xx_map(void) +{ +#ifdef CONFIG_MTD_PARTITIONS + del_mtd_partitions(bcm947xx_mtd); +#endif + map_destroy(bcm947xx_mtd); + iounmap((void *)bcm947xx_map.virt); +} + +module_init(init_bcm947xx_map); +module_exit(cleanup_bcm947xx_map); diff --git a/target/linux/brcm47xx/files-2.6.25/include/asm-generic/gpio.h b/target/linux/brcm47xx/files-2.6.25/include/asm-generic/gpio.h new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/include/asm-generic/gpio.h diff --git a/target/linux/brcm47xx/files-2.6.25/include/asm-mips/cfe.h b/target/linux/brcm47xx/files-2.6.25/include/asm-mips/cfe.h new file mode 100644 index 0000000000..47c3f5613d --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/include/asm-mips/cfe.h @@ -0,0 +1,189 @@ +/* + * Broadcom Common Firmware Environment (CFE) support + * + * Copyright 2000, 2001, 2002 + * Broadcom Corporation. All rights reserved. + * + * Copyright (C) 2006 Michael Buesch + * + * Original Authors: Mitch Lichtenberg, Chris Demetriou + * + * This software is furnished under license and may be used and copied only + * in accordance with the following terms and conditions. Subject to these + * conditions, you may download, copy, install, use, modify and distribute + * modified or unmodified copies of this software in source and/or binary + * form. No title or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce and + * retain this copyright notice and list of conditions as they appear in + * the source file. + * + * 2) No right is granted to use any trade name, trademark, or logo of + * Broadcom Corporation. The "Broadcom Corporation" name may not be + * used to endorse or promote products derived from this software + * without the prior written permission of Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE + * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE + * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LINUX_CFE_API_H_ +#define LINUX_CFE_API_H_ + +#include <linux/types.h> + + +#define CFE_MI_RESERVED 0 /* memory is reserved, do not use */ +#define CFE_MI_AVAILABLE 1 /* memory is available */ + +#define CFE_FLG_WARMSTART 0x00000001 +#define CFE_FLG_FULL_ARENA 0x00000001 +#define CFE_FLG_ENV_PERMANENT 0x00000001 + +#define CFE_CPU_CMD_START 1 +#define CFE_CPU_CMD_STOP 0 + +#define CFE_STDHANDLE_CONSOLE 0 + +#define CFE_DEV_NETWORK 1 +#define CFE_DEV_DISK 2 +#define CFE_DEV_FLASH 3 +#define CFE_DEV_SERIAL 4 +#define CFE_DEV_CPU 5 +#define CFE_DEV_NVRAM 6 +#define CFE_DEV_CLOCK 7 +#define CFE_DEV_OTHER 8 +#define CFE_DEV_MASK 0x0F + +#define CFE_CACHE_FLUSH_D 1 +#define CFE_CACHE_INVAL_I 2 +#define CFE_CACHE_INVAL_D 4 +#define CFE_CACHE_INVAL_L2 8 + +#define CFE_FWI_64BIT 0x00000001 +#define CFE_FWI_32BIT 0x00000002 +#define CFE_FWI_RELOC 0x00000004 +#define CFE_FWI_UNCACHED 0x00000008 +#define CFE_FWI_MULTICPU 0x00000010 +#define CFE_FWI_FUNCSIM 0x00000020 +#define CFE_FWI_RTLSIM 0x00000040 + +struct cfe_fwinfo { + s64 version; /* major, minor, eco version */ + s64 totalmem; /* total installed mem */ + s64 flags; /* various flags */ + s64 boardid; /* board ID */ + s64 bootarea_va; /* VA of boot area */ + s64 bootarea_pa; /* PA of boot area */ + s64 bootarea_size; /* size of boot area */ +}; + + +/* The public CFE API */ + +int cfe_present(void); /* Check if we booted from CFE. Returns bool */ + +int cfe_getticks(s64 *ticks); +int cfe_close(int handle); +int cfe_cpu_start(int cpu, void (*fn)(void), long sp, long gp, long a1); +int cfe_cpu_stop(int cpu); +int cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen); +int cfe_enumdev(int idx, char *name, int namelen); +int cfe_enummem(int idx, int flags, u64 *start, u64 *length, + u64 *type); +int cfe_exit(int warm, int status); +int cfe_flushcache(int flags); +int cfe_getdevinfo(char *name); +int cfe_getenv(char *name, char *dest, int destlen); +int cfe_getfwinfo(struct cfe_fwinfo *info); +int cfe_getstdhandle(int handletype); +int cfe_inpstat(int handle); +int cfe_ioctl(int handle, unsigned int ioctlnum, unsigned char *buffer, + int length, int *retlen, u64 offset); +int cfe_open(char *name); +int cfe_read(int handle, unsigned char *buffer, int length); +int cfe_readblk(int handle, s64 offset, unsigned char *buffer, int length); +int cfe_setenv(char *name, char *val); +int cfe_write(int handle, unsigned char *buffer, int length); +int cfe_writeblk(int handle, s64 offset, unsigned char *buffer, + int length); + + +/* High level API */ + +/* Print some information to CFE's console (most likely serial line) */ +int cfe_printk(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +int cfe_vprintk(const char *fmt, va_list args); + + + +/* Error codes returned by the low API functions */ + +#define CFE_ISERR(errcode) (errcode < 0) + +#define CFE_OK 0 +#define CFE_ERR -1 /* generic error */ +#define CFE_ERR_INV_COMMAND -2 +#define CFE_ERR_EOF -3 +#define CFE_ERR_IOERR -4 +#define CFE_ERR_NOMEM -5 +#define CFE_ERR_DEVNOTFOUND -6 +#define CFE_ERR_DEVOPEN -7 +#define CFE_ERR_INV_PARAM -8 +#define CFE_ERR_ENVNOTFOUND -9 +#define CFE_ERR_ENVREADONLY -10 + +#define CFE_ERR_NOTELF -11 +#define CFE_ERR_NOT32BIT -12 +#define CFE_ERR_WRONGENDIAN -13 +#define CFE_ERR_BADELFVERS -14 +#define CFE_ERR_NOTMIPS -15 +#define CFE_ERR_BADELFFMT -16 +#define CFE_ERR_BADADDR -17 + +#define CFE_ERR_FILENOTFOUND -18 +#define CFE_ERR_UNSUPPORTED -19 + +#define CFE_ERR_HOSTUNKNOWN -20 + +#define CFE_ERR_TIMEOUT -21 + +#define CFE_ERR_PROTOCOLERR -22 + +#define CFE_ERR_NETDOWN -23 +#define CFE_ERR_NONAMESERVER -24 + +#define CFE_ERR_NOHANDLES -25 +#define CFE_ERR_ALREADYBOUND -26 + +#define CFE_ERR_CANNOTSET -27 +#define CFE_ERR_NOMORE -28 +#define CFE_ERR_BADFILESYS -29 +#define CFE_ERR_FSNOTAVAIL -30 + +#define CFE_ERR_INVBOOTBLOCK -31 +#define CFE_ERR_WRONGDEVTYPE -32 +#define CFE_ERR_BBCHECKSUM -33 +#define CFE_ERR_BOOTPROGCHKSUM -34 + +#define CFE_ERR_LDRNOTAVAIL -35 + +#define CFE_ERR_NOTREADY -36 + +#define CFE_ERR_GETMEM -37 +#define CFE_ERR_SETMEM -38 + +#define CFE_ERR_NOTCONN -39 +#define CFE_ERR_ADDRINUSE -40 + + +#endif /* LINUX_CFE_API_H_ */ diff --git a/target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm947xx/gpio.h b/target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm947xx/gpio.h new file mode 100644 index 0000000000..e7807ce723 --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm947xx/gpio.h @@ -0,0 +1,67 @@ +#ifndef __BCM947XX_GPIO_H +#define __BCM947XX_GPIO_H + +#include <linux/ssb/ssb_embedded.h> + +extern struct ssb_bus ssb; + +static inline int gpio_request(unsigned gpio, const char *label) +{ + return 0; +} + +static inline void gpio_free(unsigned gpio) +{ +} + +static inline int gpio_direction_input(unsigned gpio) +{ + ssb_gpio_outen(&ssb, 1 << gpio, 0); + return 0; +} + +static inline int gpio_direction_output(unsigned gpio, int value) +{ + ssb_gpio_out(&ssb, 1 << gpio, (value ? 1 << gpio : 0)); + ssb_gpio_outen(&ssb, 1 << gpio, 1 << gpio); + return 0; +} + + +static inline int gpio_to_irq(unsigned gpio) +{ + struct ssb_device *dev; + + dev = ssb.chipco.dev; + if (!dev) + dev = ssb.extif.dev; + if (!dev) + return -EINVAL; + + return ssb_mips_irq(dev) + 2; +} + +static inline int irq_to_gpio(unsigned gpio) +{ + return -EINVAL; +} + + +static inline int gpio_get_value(unsigned gpio) +{ + return !!ssb_gpio_in(&ssb, 1 << gpio); +} + +static inline int gpio_set_value(unsigned gpio, int value) +{ + ssb_gpio_out(&ssb, 1 << gpio, (value ? 1 << gpio : 0)); + return 0; +} + + +/* cansleep wrappers */ +#include <asm-generic/gpio.h> + + +#endif /* __BCM947XX_GPIO_H */ + diff --git a/target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm947xx/kernel-entry-init.h b/target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm947xx/kernel-entry-init.h new file mode 100644 index 0000000000..7df0dc2b5a --- /dev/null +++ b/target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm947xx/kernel-entry-init.h @@ -0,0 +1,26 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2005 Embedded Alley Solutions, Inc + * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2006 Michael Buesch + */ +#ifndef __ASM_MACH_GENERIC_KERNEL_ENTRY_H +#define __ASM_MACH_GENERIC_KERNEL_ENTRY_H + +/* Intentionally empty macro, used in head.S. Override in + * arch/mips/mach-xxx/kernel-entry-init.h when necessary. + */ + .macro kernel_entry_setup + .endm + +/* + * Do SMP slave processor setup necessary before we can savely execute C code. + */ + .macro smp_slave_setup + .endm + + +#endif /* __ASM_MACH_GENERIC_KERNEL_ENTRY_H */ diff --git a/target/linux/brcm47xx/patches-2.6.25/001-ssb-fix-gpio-api.patch b/target/linux/brcm47xx/patches-2.6.25/001-ssb-fix-gpio-api.patch new file mode 100644 index 0000000000..f8d454f5a4 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/001-ssb-fix-gpio-api.patch @@ -0,0 +1,160 @@ +Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/driver_chipcommon.c 2008-02-19 14:37:06.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/driver_chipcommon.c 2008-02-19 14:37:08.000000000 +0100 +@@ -39,12 +39,14 @@ static inline void chipco_write32(struct + ssb_write32(cc->dev, offset, value); + } + +-static inline void chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset, +- u32 mask, u32 value) ++static inline u32 chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset, ++ u32 mask, u32 value) + { + value &= mask; + value |= chipco_read32(cc, offset) & ~mask; + chipco_write32(cc, offset, value); ++ ++ return value; + } + + void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, +@@ -355,16 +357,37 @@ u32 ssb_chipco_gpio_in(struct ssb_chipco + { + return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask; + } ++EXPORT_SYMBOL(ssb_chipco_gpio_in); ++ ++u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) ++{ ++ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); ++} ++EXPORT_SYMBOL(ssb_chipco_gpio_out); ++ ++u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) ++{ ++ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); ++} ++EXPORT_SYMBOL(ssb_chipco_gpio_outen); ++ ++u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value) ++{ ++ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); ++} ++EXPORT_SYMBOL(ssb_chipco_gpio_control); + +-void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) ++u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) + { +- chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); ++ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); + } ++EXPORT_SYMBOL(ssb_chipco_gpio_intmask); + +-void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) ++u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value) + { +- chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); ++ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); + } ++EXPORT_SYMBOL(ssb_chipco_gpio_polarity); + + #ifdef CONFIG_SSB_SERIAL + int ssb_chipco_serial_init(struct ssb_chipcommon *cc, +Index: linux-2.6.23.16/drivers/ssb/driver_extif.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/driver_extif.c 2008-02-19 14:37:06.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/driver_extif.c 2008-02-19 14:37:08.000000000 +0100 +@@ -27,12 +27,14 @@ static inline void extif_write32(struct + ssb_write32(extif->dev, offset, value); + } + +-static inline void extif_write32_masked(struct ssb_extif *extif, u16 offset, +- u32 mask, u32 value) ++static inline u32 extif_write32_masked(struct ssb_extif *extif, u16 offset, ++ u32 mask, u32 value) + { + value &= mask; + value |= extif_read32(extif, offset) & ~mask; + extif_write32(extif, offset, value); ++ ++ return value; + } + + #ifdef CONFIG_SSB_SERIAL +@@ -114,16 +116,30 @@ u32 ssb_extif_gpio_in(struct ssb_extif * + { + return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; + } ++EXPORT_SYMBOL(ssb_extif_gpio_in); + +-void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) ++u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) + { + return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), + mask, value); + } ++EXPORT_SYMBOL(ssb_extif_gpio_out); + +-void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) ++u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) + { + return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), + mask, value); + } ++EXPORT_SYMBOL(ssb_extif_gpio_outen); ++ ++u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value) ++{ ++ return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value); ++} ++EXPORT_SYMBOL(ssb_extif_gpio_polarity); + ++u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value) ++{ ++ return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value); ++} ++EXPORT_SYMBOL(ssb_extif_gpio_intmask); +Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h +=================================================================== +--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_chipcommon.h 2008-02-19 14:37:06.000000000 +0100 ++++ linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h 2008-02-19 14:37:08.000000000 +0100 +@@ -382,11 +382,13 @@ extern void ssb_chipco_set_clockmode(str + extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, + u32 ticks); + ++/* Chipcommon GPIO pin access. */ + u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask); +- +-void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value); +- +-void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value); ++u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value); ++u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value); ++u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value); ++u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value); ++u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value); + + #ifdef CONFIG_SSB_SERIAL + extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc, +Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_extif.h +=================================================================== +--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_extif.h 2008-02-19 14:37:06.000000000 +0100 ++++ linux-2.6.23.16/include/linux/ssb/ssb_driver_extif.h 2008-02-19 14:37:08.000000000 +0100 +@@ -171,11 +171,12 @@ extern void ssb_extif_get_clockcontrol(s + extern void ssb_extif_timing_init(struct ssb_extif *extif, + unsigned long ns); + ++/* Extif GPIO pin access */ + u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask); +- +-void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value); +- +-void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value); ++u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value); ++u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value); ++u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value); ++u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value); + + #ifdef CONFIG_SSB_SERIAL + extern int ssb_extif_serial_init(struct ssb_extif *extif, diff --git a/target/linux/brcm47xx/patches-2.6.25/100-board_support.patch b/target/linux/brcm47xx/patches-2.6.25/100-board_support.patch new file mode 100644 index 0000000000..7f28f340fc --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/100-board_support.patch @@ -0,0 +1,212 @@ +Index: linux-2.6.23/arch/mips/Kconfig +=================================================================== +--- linux-2.6.23.orig/arch/mips/Kconfig 2007-10-13 02:23:06.662507926 +0200 ++++ linux-2.6.23/arch/mips/Kconfig 2007-10-13 02:23:41.484492317 +0200 +@@ -4,6 +4,10 @@ + # Horrible source of confusion. Die, die, die ... + select EMBEDDED + ++config CFE ++ bool ++ # Common Firmware Environment ++ + mainmenu "Linux/MIPS Kernel Configuration" + + menu "Machine selection" +@@ -44,6 +48,23 @@ + note that a kernel built with this option selected will not be + able to run on normal units. + ++config BCM947XX ++ bool "Support for BCM947xx based boards" ++ select DMA_NONCOHERENT ++ select HW_HAS_PCI ++ select IRQ_CPU ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SSB ++ select SSB_SERIAL ++ select SSB_DRIVER_PCICORE ++ select SSB_PCICORE_HOSTMODE ++ select CFE ++ select GENERIC_GPIO ++ help ++ Support for BCM947xx based boards ++ + config MIPS_COBALT + bool "Cobalt Server" + select DMA_NONCOHERENT +Index: linux-2.6.23/arch/mips/kernel/cpu-probe.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/kernel/cpu-probe.c 2007-10-13 02:23:06.666508151 +0200 ++++ linux-2.6.23/arch/mips/kernel/cpu-probe.c 2007-10-13 02:23:11.210767122 +0200 +@@ -793,6 +793,28 @@ + } + + ++static inline void cpu_probe_broadcom(struct cpuinfo_mips *c) ++{ ++ decode_config1(c); ++ switch (c->processor_id & 0xff00) { ++ case PRID_IMP_BCM3302: ++ c->cputype = CPU_BCM3302; ++ c->isa_level = MIPS_CPU_ISA_M32R1; ++ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX | ++ MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER; ++ break; ++ case PRID_IMP_BCM4710: ++ c->cputype = CPU_BCM4710; ++ c->isa_level = MIPS_CPU_ISA_M32R1; ++ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX | ++ MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER; ++ break; ++ default: ++ c->cputype = CPU_UNKNOWN; ++ break; ++ } ++} ++ + __init void cpu_probe(void) + { + struct cpuinfo_mips *c = ¤t_cpu_data; +@@ -815,6 +837,9 @@ + case PRID_COMP_SIBYTE: + cpu_probe_sibyte(c); + break; ++ case PRID_COMP_BROADCOM: ++ cpu_probe_broadcom(c); ++ break; + case PRID_COMP_SANDCRAFT: + cpu_probe_sandcraft(c); + break; +Index: linux-2.6.23/arch/mips/kernel/proc.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/kernel/proc.c 2007-10-13 02:23:06.678508839 +0200 ++++ linux-2.6.23/arch/mips/kernel/proc.c 2007-10-13 02:23:11.210767122 +0200 +@@ -82,6 +82,8 @@ + [CPU_VR4181] = "NEC VR4181", + [CPU_VR4181A] = "NEC VR4181A", + [CPU_SR71000] = "Sandcraft SR71000", ++ [CPU_BCM3302] = "Broadcom BCM3302", ++ [CPU_BCM4710] = "Broadcom BCM4710", + [CPU_PR4450] = "Philips PR4450", + [CPU_LOONGSON2] = "ICT Loongson-2", + }; +Index: linux-2.6.23/arch/mips/Makefile +=================================================================== +--- linux-2.6.23.orig/arch/mips/Makefile 2007-10-13 02:23:06.682509066 +0200 ++++ linux-2.6.23/arch/mips/Makefile 2007-10-13 02:23:11.210767122 +0200 +@@ -533,6 +533,18 @@ + load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000 + + # ++# Broadcom BCM47XX boards ++# ++core-$(CONFIG_BCM947XX) += arch/mips/bcm947xx/ ++cflags-$(CONFIG_BCM947XX) += -Iarch/mips/bcm947xx/include -Iinclude/asm-mips/mach-bcm947xx ++load-$(CONFIG_BCM947XX) := 0xffffffff80001000 ++ ++# ++# Common Firmware Environment ++# ++core-$(CONFIG_CFE) += arch/mips/cfe/ ++ ++# + # SNI RM + # + core-$(CONFIG_SNI_RM) += arch/mips/sni/ +Index: linux-2.6.23/arch/mips/mm/tlbex.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/mm/tlbex.c 2007-10-13 02:23:06.694509748 +0200 ++++ linux-2.6.23/arch/mips/mm/tlbex.c 2007-10-13 02:26:00.272401391 +0200 +@@ -895,6 +895,8 @@ + case CPU_AU1550: + case CPU_AU1200: + case CPU_PR4450: ++ case CPU_BCM3302: ++ case CPU_BCM4710: + i_nop(p); + tlbw(p); + break; +Index: linux-2.6.23/drivers/Kconfig +=================================================================== +--- linux-2.6.23.orig/drivers/Kconfig 2007-10-13 02:23:06.702510206 +0200 ++++ linux-2.6.23/drivers/Kconfig 2007-10-13 02:23:11.214767346 +0200 +@@ -58,6 +58,8 @@ + + source "drivers/hwmon/Kconfig" + ++source "drivers/ssb/Kconfig" ++ + source "drivers/mfd/Kconfig" + + source "drivers/media/Kconfig" +Index: linux-2.6.23/include/asm-mips/bootinfo.h +=================================================================== +--- linux-2.6.23.orig/include/asm-mips/bootinfo.h 2007-10-13 02:23:06.718511119 +0200 ++++ linux-2.6.23/include/asm-mips/bootinfo.h 2007-10-13 02:23:11.214767346 +0200 +@@ -208,6 +208,12 @@ + #define MACH_GROUP_WINDRIVER 28 /* Windriver boards */ + #define MACH_WRPPMC 1 + ++/* ++ * Valid machtype for group Broadcom ++ */ ++#define MACH_GROUP_BRCM 23 /* Broadcom */ ++#define MACH_BCM47XX 1 /* Broadcom BCM47xx */ ++ + #define CL_SIZE COMMAND_LINE_SIZE + + const char *get_system_type(void); +Index: linux-2.6.23/include/asm-mips/cpu.h +=================================================================== +--- linux-2.6.23.orig/include/asm-mips/cpu.h 2007-10-13 02:23:06.726511570 +0200 ++++ linux-2.6.23/include/asm-mips/cpu.h 2007-10-13 02:27:43.994312161 +0200 +@@ -106,6 +106,13 @@ + #define PRID_IMP_SR71000 0x0400 + + /* ++ * These are the PRID's for when 23:16 == PRID_COMP_BROADCOM ++ */ ++ ++#define PRID_IMP_BCM4710 0x4000 ++#define PRID_IMP_BCM3302 0x9000 ++ ++/* + * Definitions for 7:0 on legacy processors + */ + +@@ -217,8 +224,10 @@ + #define CPU_R14000 64 + #define CPU_LOONGSON1 65 + #define CPU_LOONGSON2 66 ++#define CPU_BCM3302 67 ++#define CPU_BCM4710 68 + +-#define CPU_LAST 66 ++#define CPU_LAST 68 + + /* + * ISA Level encodings +Index: linux-2.6.23.1/drivers/Makefile +=================================================================== +--- linux-2.6.23.1.orig/drivers/Makefile 2008-01-27 04:34:31.000000000 +0100 ++++ linux-2.6.23.1/drivers/Makefile 2008-01-27 04:39:57.000000000 +0100 +@@ -89,3 +89,4 @@ + obj-$(CONFIG_PPC_PS3) += ps3/ + obj-$(CONFIG_OF) += of/ + obj-$(CONFIG_GPIO_DEVICE) += gpio/ ++obj-$(CONFIG_SSB) += ssb/ +Index: linux-2.6.23.1/include/linux/pci_ids.h +=================================================================== +--- linux-2.6.23.1.orig/include/linux/pci_ids.h 2008-01-27 04:55:18.000000000 +0100 ++++ linux-2.6.23.1/include/linux/pci_ids.h 2008-01-27 04:55:22.000000000 +0100 +@@ -1972,6 +1972,7 @@ + #define PCI_DEVICE_ID_TIGON3_5906M 0x1713 + #define PCI_DEVICE_ID_BCM4401 0x4401 + #define PCI_DEVICE_ID_BCM4401B0 0x4402 ++#define PCI_DEVICE_ID_BCM4713 0x4713 + + #define PCI_VENDOR_ID_TOPIC 0x151f + #define PCI_DEVICE_ID_TOPIC_TP560 0x0000 diff --git a/target/linux/brcm47xx/patches-2.6.25/110-flash_map.patch b/target/linux/brcm47xx/patches-2.6.25/110-flash_map.patch new file mode 100644 index 0000000000..7dc05b6c6a --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/110-flash_map.patch @@ -0,0 +1,29 @@ +Index: linux-2.6.23/drivers/mtd/maps/Kconfig +=================================================================== +--- linux-2.6.23.orig/drivers/mtd/maps/Kconfig 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/drivers/mtd/maps/Kconfig 2007-10-13 02:28:13.644001805 +0200 +@@ -352,6 +352,12 @@ + Mapping for the Flaga digital module. If you don't have one, ignore + this setting. + ++config MTD_BCM47XX ++ tristate "BCM47xx flash device" ++ depends on MIPS && MTD_CFI && BCM947XX ++ help ++ Support for the flash chips on the BCM947xx board. ++ + config MTD_WALNUT + tristate "Flash device mapped on IBM 405GP Walnut" + depends on MTD_JEDECPROBE && WALNUT +Index: linux-2.6.23/drivers/mtd/maps/Makefile +=================================================================== +--- linux-2.6.23.orig/drivers/mtd/maps/Makefile 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/drivers/mtd/maps/Makefile 2007-10-13 02:27:56.727037761 +0200 +@@ -33,6 +33,7 @@ + obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o + obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o + obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o ++obj-$(CONFIG_MTD_BCM47XX) += bcm47xx-flash.o + obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o + obj-$(CONFIG_MTD_IPAQ) += ipaq-flash.o + obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o diff --git a/target/linux/brcm47xx/patches-2.6.25/120-b44_ssb_support.patch b/target/linux/brcm47xx/patches-2.6.25/120-b44_ssb_support.patch new file mode 100644 index 0000000000..29125c6755 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/120-b44_ssb_support.patch @@ -0,0 +1,1544 @@ +Index: linux-2.6.23.16/drivers/net/b44.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/net/b44.c 2008-02-19 01:35:58.000000000 +0100 ++++ linux-2.6.23.16/drivers/net/b44.c 2008-02-19 01:37:04.000000000 +0100 +@@ -1,7 +1,9 @@ +-/* b44.c: Broadcom 4400 device driver. ++/* b44.c: Broadcom 4400/47xx device driver. + * + * Copyright (C) 2002 David S. Miller (davem@redhat.com) +- * Fixed by Pekka Pietikainen (pp@ee.oulu.fi) ++ * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi) ++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) ++ * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org) + * Copyright (C) 2006 Broadcom Corporation. + * + * Distribute under GPL. +@@ -21,11 +23,13 @@ + #include <linux/delay.h> + #include <linux/init.h> + #include <linux/dma-mapping.h> ++#include <linux/ssb/ssb.h> + + #include <asm/uaccess.h> + #include <asm/io.h> + #include <asm/irq.h> + ++ + #include "b44.h" + + #define DRV_MODULE_NAME "b44" +@@ -87,8 +91,8 @@ + static char version[] __devinitdata = + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + +-MODULE_AUTHOR("Florian Schirmer, Pekka Pietikainen, David S. Miller"); +-MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver"); ++MODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller"); ++MODULE_DESCRIPTION("Broadcom 4400/47xx 10/100 PCI ethernet driver"); + MODULE_LICENSE("GPL"); + MODULE_VERSION(DRV_MODULE_VERSION); + +@@ -96,18 +100,11 @@ static int b44_debug = -1; /* -1 == use + module_param(b44_debug, int, 0); + MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value"); + +-static struct pci_device_id b44_pci_tbl[] = { +- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401, +- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, +- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0, +- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, +- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1, +- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, +- { } /* terminate list with empty entry */ ++static struct ssb_device_id b44_ssb_tbl[] = { ++ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV), ++ SSB_DEVTABLE_END + }; + +-MODULE_DEVICE_TABLE(pci, b44_pci_tbl); +- + static void b44_halt(struct b44 *); + static void b44_init_rings(struct b44 *); + +@@ -119,6 +116,7 @@ static void b44_init_hw(struct b44 *, in + + static int dma_desc_align_mask; + static int dma_desc_sync_size; ++static int instance; + + static const char b44_gstrings[][ETH_GSTRING_LEN] = { + #define _B44(x...) # x, +@@ -126,35 +124,24 @@ B44_STAT_REG_DECLARE + #undef _B44 + }; + +-static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev, +- dma_addr_t dma_base, +- unsigned long offset, +- enum dma_data_direction dir) +-{ +- dma_sync_single_range_for_device(&pdev->dev, dma_base, +- offset & dma_desc_align_mask, +- dma_desc_sync_size, dir); +-} +- +-static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev, +- dma_addr_t dma_base, +- unsigned long offset, +- enum dma_data_direction dir) +-{ +- dma_sync_single_range_for_cpu(&pdev->dev, dma_base, +- offset & dma_desc_align_mask, +- dma_desc_sync_size, dir); +-} +- +-static inline unsigned long br32(const struct b44 *bp, unsigned long reg) +-{ +- return readl(bp->regs + reg); +-} +- +-static inline void bw32(const struct b44 *bp, +- unsigned long reg, unsigned long val) +-{ +- writel(val, bp->regs + reg); ++static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev, ++ dma_addr_t dma_base, ++ unsigned long offset, ++ enum dma_data_direction dir) ++{ ++ dma_sync_single_range_for_device(sdev->dev, dma_base, ++ offset & dma_desc_align_mask, ++ dma_desc_sync_size, dir); ++} ++ ++static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev, ++ dma_addr_t dma_base, ++ unsigned long offset, ++ enum dma_data_direction dir) ++{ ++ dma_sync_single_range_for_cpu(sdev->dev, dma_base, ++ offset & dma_desc_align_mask, ++ dma_desc_sync_size, dir); + } + + static int b44_wait_bit(struct b44 *bp, unsigned long reg, +@@ -182,117 +169,29 @@ static int b44_wait_bit(struct b44 *bp, + return 0; + } + +-/* Sonics SiliconBackplane support routines. ROFL, you should see all the +- * buzz words used on this company's website :-) +- * +- * All of these routines must be invoked with bp->lock held and +- * interrupts disabled. +- */ +- +-#define SB_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */ +-#define BCM4400_PCI_CORE_ADDR 0x18002000 /* Address of PCI core on BCM4400 cards */ +- +-static u32 ssb_get_core_rev(struct b44 *bp) +-{ +- return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK); +-} +- +-static u32 ssb_pci_setup(struct b44 *bp, u32 cores) +-{ +- u32 bar_orig, pci_rev, val; +- +- pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig); +- pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, BCM4400_PCI_CORE_ADDR); +- pci_rev = ssb_get_core_rev(bp); +- +- val = br32(bp, B44_SBINTVEC); +- val |= cores; +- bw32(bp, B44_SBINTVEC, val); +- +- val = br32(bp, SSB_PCI_TRANS_2); +- val |= SSB_PCI_PREF | SSB_PCI_BURST; +- bw32(bp, SSB_PCI_TRANS_2, val); +- +- pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig); +- +- return pci_rev; +-} +- +-static void ssb_core_disable(struct b44 *bp) +-{ +- if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET) +- return; +- +- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK)); +- b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0); +- b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1); +- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK | +- SBTMSLOW_REJECT | SBTMSLOW_RESET)); +- br32(bp, B44_SBTMSLOW); +- udelay(1); +- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET)); +- br32(bp, B44_SBTMSLOW); +- udelay(1); +-} +- +-static void ssb_core_reset(struct b44 *bp) ++static inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index) + { + u32 val; + +- ssb_core_disable(bp); +- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC)); +- br32(bp, B44_SBTMSLOW); +- udelay(1); +- +- /* Clear SERR if set, this is a hw bug workaround. */ +- if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR) +- bw32(bp, B44_SBTMSHIGH, 0); +- +- val = br32(bp, B44_SBIMSTATE); +- if (val & (SBIMSTATE_IBE | SBIMSTATE_TO)) +- bw32(bp, B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO)); +- +- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC)); +- br32(bp, B44_SBTMSLOW); +- udelay(1); ++ bw32(bp, B44_CAM_CTRL, (CAM_CTRL_READ | ++ (index << CAM_CTRL_INDEX_SHIFT))); + +- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK)); +- br32(bp, B44_SBTMSLOW); +- udelay(1); +-} ++ b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); + +-static int ssb_core_unit(struct b44 *bp) +-{ +-#if 0 +- u32 val = br32(bp, B44_SBADMATCH0); +- u32 base; ++ val = br32(bp, B44_CAM_DATA_LO); + +- type = val & SBADMATCH0_TYPE_MASK; +- switch (type) { +- case 0: +- base = val & SBADMATCH0_BS0_MASK; +- break; ++ data[2] = (val >> 24) & 0xFF; ++ data[3] = (val >> 16) & 0xFF; ++ data[4] = (val >> 8) & 0xFF; ++ data[5] = (val >> 0) & 0xFF; + +- case 1: +- base = val & SBADMATCH0_BS1_MASK; +- break; ++ val = br32(bp, B44_CAM_DATA_HI); + +- case 2: +- default: +- base = val & SBADMATCH0_BS2_MASK; +- break; +- }; +-#endif +- return 0; ++ data[0] = (val >> 8) & 0xFF; ++ data[1] = (val >> 0) & 0xFF; + } + +-static int ssb_is_core_up(struct b44 *bp) +-{ +- return ((br32(bp, B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK)) +- == SBTMSLOW_CLOCK); +-} +- +-static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) ++static inline void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) + { + u32 val; + +@@ -328,14 +227,14 @@ static void b44_enable_ints(struct b44 * + bw32(bp, B44_IMASK, bp->imask); + } + +-static int b44_readphy(struct b44 *bp, int reg, u32 *val) ++static int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val) + { + int err; + + bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); + bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | + (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) | +- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) | ++ (phy_addr << MDIO_DATA_PMD_SHIFT) | + (reg << MDIO_DATA_RA_SHIFT) | + (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT))); + err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); +@@ -344,18 +243,34 @@ static int b44_readphy(struct b44 *bp, i + return err; + } + +-static int b44_writephy(struct b44 *bp, int reg, u32 val) ++static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val) + { + bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); + bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | + (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) | +- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) | ++ (phy_addr << MDIO_DATA_PMD_SHIFT) | + (reg << MDIO_DATA_RA_SHIFT) | + (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) | + (val & MDIO_DATA_DATA))); + return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); + } + ++static inline int b44_readphy(struct b44 *bp, int reg, u32 *val) ++{ ++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) ++ return 0; ++ ++ return __b44_readphy(bp, bp->phy_addr, reg, val); ++} ++ ++static inline int b44_writephy(struct b44 *bp, int reg, u32 val) ++{ ++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) ++ return 0; ++ ++ return __b44_writephy(bp, bp->phy_addr, reg, val); ++} ++ + /* miilib interface */ + /* FIXME FIXME: phy_id is ignored, bp->phy_addr use is unconditional + * due to code existing before miilib use was added to this driver. +@@ -384,6 +299,8 @@ static int b44_phy_reset(struct b44 *bp) + u32 val; + int err; + ++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) ++ return 0; + err = b44_writephy(bp, MII_BMCR, BMCR_RESET); + if (err) + return err; +@@ -442,11 +359,27 @@ static void b44_set_flow_ctrl(struct b44 + __b44_set_flow_ctrl(bp, pause_enab); + } + ++ ++extern char *nvram_get(char *name); //FIXME: move elsewhere + static int b44_setup_phy(struct b44 *bp) + { + u32 val; + int err; + ++ /* ++ * workaround for bad hardware design in Linksys WAP54G v1.0 ++ * see https://dev.openwrt.org/ticket/146 ++ * check and reset bit "isolate" ++ */ ++ if ((atoi(nvram_get("boardnum")) == 2) && ++ (__b44_readphy(bp, 0, MII_BMCR, &val) == 0) && ++ (val & BMCR_ISOLATE) && ++ (__b44_writephy(bp, 0, MII_BMCR, val & ~BMCR_ISOLATE) != 0)) { ++ printk(KERN_WARNING PFX "PHY: cannot reset MII transceiver isolate bit.\n"); ++ } ++ ++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) ++ return 0; + if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0) + goto out; + if ((err = b44_writephy(bp, B44_MII_ALEDCTRL, +@@ -542,6 +475,19 @@ static void b44_check_phy(struct b44 *bp + { + u32 bmsr, aux; + ++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) { ++ bp->flags |= B44_FLAG_100_BASE_T; ++ bp->flags |= B44_FLAG_FULL_DUPLEX; ++ if (!netif_carrier_ok(bp->dev)) { ++ u32 val = br32(bp, B44_TX_CTRL); ++ val |= TX_CTRL_DUPLEX; ++ bw32(bp, B44_TX_CTRL, val); ++ netif_carrier_on(bp->dev); ++ b44_link_report(bp); ++ } ++ return; ++ } ++ + if (!b44_readphy(bp, MII_BMSR, &bmsr) && + !b44_readphy(bp, B44_MII_AUXCTRL, &aux) && + (bmsr != 0xffff)) { +@@ -617,10 +563,10 @@ static void b44_tx(struct b44 *bp) + + BUG_ON(skb == NULL); + +- pci_unmap_single(bp->pdev, ++ dma_unmap_single(bp->sdev->dev, + pci_unmap_addr(rp, mapping), + skb->len, +- PCI_DMA_TODEVICE); ++ DMA_TO_DEVICE); + rp->skb = NULL; + dev_kfree_skb_irq(skb); + } +@@ -657,9 +603,9 @@ static int b44_alloc_rx_skb(struct b44 * + if (skb == NULL) + return -ENOMEM; + +- mapping = pci_map_single(bp->pdev, skb->data, ++ mapping = dma_map_single(bp->sdev->dev, skb->data, + RX_PKT_BUF_SZ, +- PCI_DMA_FROMDEVICE); ++ DMA_FROM_DEVICE); + + /* Hardware bug work-around, the chip is unable to do PCI DMA + to/from anything above 1GB :-( */ +@@ -667,18 +613,18 @@ static int b44_alloc_rx_skb(struct b44 * + mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { + /* Sigh... */ + if (!dma_mapping_error(mapping)) +- pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); ++ dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA); + if (skb == NULL) + return -ENOMEM; +- mapping = pci_map_single(bp->pdev, skb->data, ++ mapping = dma_map_single(bp->sdev->dev, skb->data, + RX_PKT_BUF_SZ, +- PCI_DMA_FROMDEVICE); ++ DMA_FROM_DEVICE); + if (dma_mapping_error(mapping) || + mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { + if (!dma_mapping_error(mapping)) +- pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); ++ dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + return -ENOMEM; + } +@@ -705,9 +651,9 @@ static int b44_alloc_rx_skb(struct b44 * + dp->addr = cpu_to_le32((u32) mapping + RX_PKT_OFFSET + bp->dma_offset); + + if (bp->flags & B44_FLAG_RX_RING_HACK) +- b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, +- dest_idx * sizeof(dp), +- DMA_BIDIRECTIONAL); ++ b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma, ++ dest_idx * sizeof(dp), ++ DMA_BIDIRECTIONAL); + + return RX_PKT_BUF_SZ; + } +@@ -734,9 +680,9 @@ static void b44_recycle_rx(struct b44 *b + pci_unmap_addr(src_map, mapping)); + + if (bp->flags & B44_FLAG_RX_RING_HACK) +- b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma, +- src_idx * sizeof(src_desc), +- DMA_BIDIRECTIONAL); ++ b44_sync_dma_desc_for_cpu(bp->sdev, bp->rx_ring_dma, ++ src_idx * sizeof(src_desc), ++ DMA_BIDIRECTIONAL); + + ctrl = src_desc->ctrl; + if (dest_idx == (B44_RX_RING_SIZE - 1)) +@@ -750,13 +696,13 @@ static void b44_recycle_rx(struct b44 *b + src_map->skb = NULL; + + if (bp->flags & B44_FLAG_RX_RING_HACK) +- b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, +- dest_idx * sizeof(dest_desc), +- DMA_BIDIRECTIONAL); ++ b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma, ++ dest_idx * sizeof(dest_desc), ++ DMA_BIDIRECTIONAL); + +- pci_dma_sync_single_for_device(bp->pdev, le32_to_cpu(src_desc->addr), ++ dma_sync_single_for_device(bp->sdev->dev, le32_to_cpu(src_desc->addr), + RX_PKT_BUF_SZ, +- PCI_DMA_FROMDEVICE); ++ DMA_FROM_DEVICE); + } + + static int b44_rx(struct b44 *bp, int budget) +@@ -776,9 +722,9 @@ static int b44_rx(struct b44 *bp, int bu + struct rx_header *rh; + u16 len; + +- pci_dma_sync_single_for_cpu(bp->pdev, map, ++ dma_sync_single_for_cpu(bp->sdev->dev, map, + RX_PKT_BUF_SZ, +- PCI_DMA_FROMDEVICE); ++ DMA_FROM_DEVICE); + rh = (struct rx_header *) skb->data; + len = le16_to_cpu(rh->len); + if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) || +@@ -810,8 +756,8 @@ static int b44_rx(struct b44 *bp, int bu + skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod); + if (skb_size < 0) + goto drop_it; +- pci_unmap_single(bp->pdev, map, +- skb_size, PCI_DMA_FROMDEVICE); ++ dma_unmap_single(bp->sdev->dev, map, ++ skb_size, DMA_FROM_DEVICE); + /* Leave out rx_header */ + skb_put(skb, len + RX_PKT_OFFSET); + skb_pull(skb, RX_PKT_OFFSET); +@@ -982,24 +928,24 @@ static int b44_start_xmit(struct sk_buff + goto err_out; + } + +- mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE); ++ mapping = dma_map_single(bp->sdev->dev, skb->data, len, DMA_TO_DEVICE); + if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { + struct sk_buff *bounce_skb; + + /* Chip can't handle DMA to/from >1GB, use bounce buffer */ + if (!dma_mapping_error(mapping)) +- pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE); ++ dma_unmap_single(bp->sdev->dev, mapping, len, DMA_TO_DEVICE); + + bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA); + if (!bounce_skb) + goto err_out; + +- mapping = pci_map_single(bp->pdev, bounce_skb->data, +- len, PCI_DMA_TODEVICE); ++ mapping = dma_map_single(bp->sdev->dev, bounce_skb->data, ++ len, DMA_TO_DEVICE); + if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { + if (!dma_mapping_error(mapping)) +- pci_unmap_single(bp->pdev, mapping, +- len, PCI_DMA_TODEVICE); ++ dma_unmap_single(bp->sdev->dev, mapping, ++ len, DMA_TO_DEVICE); + dev_kfree_skb_any(bounce_skb); + goto err_out; + } +@@ -1022,9 +968,9 @@ static int b44_start_xmit(struct sk_buff + bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset); + + if (bp->flags & B44_FLAG_TX_RING_HACK) +- b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma, +- entry * sizeof(bp->tx_ring[0]), +- DMA_TO_DEVICE); ++ b44_sync_dma_desc_for_device(bp->sdev, bp->tx_ring_dma, ++ entry * sizeof(bp->tx_ring[0]), ++ DMA_TO_DEVICE); + + entry = NEXT_TX(entry); + +@@ -1097,10 +1043,10 @@ static void b44_free_rings(struct b44 *b + + if (rp->skb == NULL) + continue; +- pci_unmap_single(bp->pdev, ++ dma_unmap_single(bp->sdev->dev, + pci_unmap_addr(rp, mapping), + RX_PKT_BUF_SZ, +- PCI_DMA_FROMDEVICE); ++ DMA_FROM_DEVICE); + dev_kfree_skb_any(rp->skb); + rp->skb = NULL; + } +@@ -1111,10 +1057,10 @@ static void b44_free_rings(struct b44 *b + + if (rp->skb == NULL) + continue; +- pci_unmap_single(bp->pdev, ++ dma_unmap_single(bp->sdev->dev, + pci_unmap_addr(rp, mapping), + rp->skb->len, +- PCI_DMA_TODEVICE); ++ DMA_TO_DEVICE); + dev_kfree_skb_any(rp->skb); + rp->skb = NULL; + } +@@ -1136,14 +1082,14 @@ static void b44_init_rings(struct b44 *b + memset(bp->tx_ring, 0, B44_TX_RING_BYTES); + + if (bp->flags & B44_FLAG_RX_RING_HACK) +- dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma, +- DMA_TABLE_BYTES, +- PCI_DMA_BIDIRECTIONAL); ++ dma_sync_single_for_device(bp->sdev->dev, bp->rx_ring_dma, ++ DMA_TABLE_BYTES, ++ DMA_BIDIRECTIONAL); + + if (bp->flags & B44_FLAG_TX_RING_HACK) +- dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma, +- DMA_TABLE_BYTES, +- PCI_DMA_TODEVICE); ++ dma_sync_single_for_device(bp->sdev->dev, bp->tx_ring_dma, ++ DMA_TABLE_BYTES, ++ DMA_TO_DEVICE); + + for (i = 0; i < bp->rx_pending; i++) { + if (b44_alloc_rx_skb(bp, -1, i) < 0) +@@ -1163,24 +1109,24 @@ static void b44_free_consistent(struct b + bp->tx_buffers = NULL; + if (bp->rx_ring) { + if (bp->flags & B44_FLAG_RX_RING_HACK) { +- dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma, +- DMA_TABLE_BYTES, +- DMA_BIDIRECTIONAL); ++ dma_unmap_single(bp->sdev->dev, bp->rx_ring_dma, ++ DMA_TABLE_BYTES, ++ DMA_BIDIRECTIONAL); + kfree(bp->rx_ring); + } else +- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, ++ dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES, + bp->rx_ring, bp->rx_ring_dma); + bp->rx_ring = NULL; + bp->flags &= ~B44_FLAG_RX_RING_HACK; + } + if (bp->tx_ring) { + if (bp->flags & B44_FLAG_TX_RING_HACK) { +- dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma, +- DMA_TABLE_BYTES, +- DMA_TO_DEVICE); ++ dma_unmap_single(bp->sdev->dev, bp->tx_ring_dma, ++ DMA_TABLE_BYTES, ++ DMA_TO_DEVICE); + kfree(bp->tx_ring); + } else +- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, ++ dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES, + bp->tx_ring, bp->tx_ring_dma); + bp->tx_ring = NULL; + bp->flags &= ~B44_FLAG_TX_RING_HACK; +@@ -1206,7 +1152,7 @@ static int b44_alloc_consistent(struct b + goto out_err; + + size = DMA_TABLE_BYTES; +- bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma); ++ bp->rx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->rx_ring_dma, GFP_ATOMIC); + if (!bp->rx_ring) { + /* Allocation may have failed due to pci_alloc_consistent + insisting on use of GFP_DMA, which is more restrictive +@@ -1218,9 +1164,9 @@ static int b44_alloc_consistent(struct b + if (!rx_ring) + goto out_err; + +- rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring, +- DMA_TABLE_BYTES, +- DMA_BIDIRECTIONAL); ++ rx_ring_dma = dma_map_single(bp->sdev->dev, rx_ring, ++ DMA_TABLE_BYTES, ++ DMA_BIDIRECTIONAL); + + if (dma_mapping_error(rx_ring_dma) || + rx_ring_dma + size > DMA_30BIT_MASK) { +@@ -1233,9 +1179,9 @@ static int b44_alloc_consistent(struct b + bp->flags |= B44_FLAG_RX_RING_HACK; + } + +- bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma); ++ bp->tx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->tx_ring_dma, GFP_ATOMIC); + if (!bp->tx_ring) { +- /* Allocation may have failed due to pci_alloc_consistent ++ /* Allocation may have failed due to dma_alloc_coherent + insisting on use of GFP_DMA, which is more restrictive + than necessary... */ + struct dma_desc *tx_ring; +@@ -1245,9 +1191,9 @@ static int b44_alloc_consistent(struct b + if (!tx_ring) + goto out_err; + +- tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring, +- DMA_TABLE_BYTES, +- DMA_TO_DEVICE); ++ tx_ring_dma = dma_map_single(bp->sdev->dev, tx_ring, ++ DMA_TABLE_BYTES, ++ DMA_TO_DEVICE); + + if (dma_mapping_error(tx_ring_dma) || + tx_ring_dma + size > DMA_30BIT_MASK) { +@@ -1282,7 +1228,9 @@ static void b44_clear_stats(struct b44 * + /* bp->lock is held. */ + static void b44_chip_reset(struct b44 *bp) + { +- if (ssb_is_core_up(bp)) { ++ struct ssb_device *sdev = bp->sdev; ++ ++ if (ssb_device_is_enabled(bp->sdev)) { + bw32(bp, B44_RCV_LAZY, 0); + bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE); + b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1); +@@ -1294,19 +1242,24 @@ static void b44_chip_reset(struct b44 *b + } + bw32(bp, B44_DMARX_CTRL, 0); + bp->rx_prod = bp->rx_cons = 0; +- } else { +- ssb_pci_setup(bp, (bp->core_unit == 0 ? +- SBINTVEC_ENET0 : +- SBINTVEC_ENET1)); + } + +- ssb_core_reset(bp); +- ++ ssb_device_enable(bp->sdev, 0); + b44_clear_stats(bp); + +- /* Make PHY accessible. */ +- bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | ++ switch (sdev->bus->bustype) { ++ case SSB_BUSTYPE_SSB: ++ bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | ++ (((ssb_clockspeed(sdev->bus) + (B44_MDC_RATIO / 2)) / B44_MDC_RATIO) ++ & MDIO_CTRL_MAXF_MASK))); ++ break; ++ case SSB_BUSTYPE_PCI: ++ case SSB_BUSTYPE_PCMCIA: ++ bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | + (0x0d & MDIO_CTRL_MAXF_MASK))); ++ break; ++ } ++ + br32(bp, B44_MDIO_CTRL); + + if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) { +@@ -1349,6 +1302,7 @@ static int b44_set_mac_addr(struct net_d + { + struct b44 *bp = netdev_priv(dev); + struct sockaddr *addr = p; ++ u32 val; + + if (netif_running(dev)) + return -EBUSY; +@@ -1359,7 +1313,11 @@ static int b44_set_mac_addr(struct net_d + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + spin_lock_irq(&bp->lock); +- __b44_set_mac_addr(bp); ++ ++ val = br32(bp, B44_RXCONFIG); ++ if (!(val & RXCONFIG_CAM_ABSENT)) ++ __b44_set_mac_addr(bp); ++ + spin_unlock_irq(&bp->lock); + + return 0; +@@ -1445,18 +1403,6 @@ out: + return err; + } + +-#if 0 +-/*static*/ void b44_dump_state(struct b44 *bp) +-{ +- u32 val32, val32_2, val32_3, val32_4, val32_5; +- u16 val16; +- +- pci_read_config_word(bp->pdev, PCI_STATUS, &val16); +- printk("DEBUG: PCI status [%04x] \n", val16); +- +-} +-#endif +- + #ifdef CONFIG_NET_POLL_CONTROLLER + /* + * Polling receive - used by netconsole and other diagnostic tools +@@ -1570,7 +1516,6 @@ static void b44_setup_pseudo_magicp(stru + static void b44_setup_wol(struct b44 *bp) + { + u32 val; +- u16 pmval; + + bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI); + +@@ -1594,13 +1539,6 @@ static void b44_setup_wol(struct b44 *bp + } else { + b44_setup_pseudo_magicp(bp); + } +- +- val = br32(bp, B44_SBTMSLOW); +- bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE); +- +- pci_read_config_word(bp->pdev, SSB_PMCSR, &pmval); +- pci_write_config_word(bp->pdev, SSB_PMCSR, pmval | SSB_PE); +- + } + + static int b44_close(struct net_device *dev) +@@ -1700,7 +1638,7 @@ static void __b44_set_rx_mode(struct net + + val = br32(bp, B44_RXCONFIG); + val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI); +- if (dev->flags & IFF_PROMISC) { ++ if ((dev->flags & IFF_PROMISC) || (val & RXCONFIG_CAM_ABSENT)) { + val |= RXCONFIG_PROMISC; + bw32(bp, B44_RXCONFIG, val); + } else { +@@ -1747,12 +1685,8 @@ static void b44_set_msglevel(struct net_ + + static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) + { +- struct b44 *bp = netdev_priv(dev); +- struct pci_dev *pci_dev = bp->pdev; +- + strcpy (info->driver, DRV_MODULE_NAME); + strcpy (info->version, DRV_MODULE_VERSION); +- strcpy (info->bus_info, pci_name(pci_dev)); + } + + static int b44_nway_reset(struct net_device *dev) +@@ -2035,6 +1969,245 @@ static const struct ethtool_ops b44_etht + .get_ethtool_stats = b44_get_ethtool_stats, + }; + ++static int b44_ethtool_ioctl (struct net_device *dev, void __user *useraddr) ++{ ++ struct b44 *bp = dev->priv; ++ u32 ethcmd; ++ ++ if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd))) ++ return -EFAULT; ++ ++ switch (ethcmd) { ++ case ETHTOOL_GDRVINFO: { ++ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; ++ strcpy (info.driver, DRV_MODULE_NAME); ++ strcpy (info.version, DRV_MODULE_VERSION); ++ memset(&info.fw_version, 0, sizeof(info.fw_version)); ++ info.eedump_len = 0; ++ info.regdump_len = 0; ++ if (copy_to_user (useraddr, &info, sizeof (info))) ++ return -EFAULT; ++ return 0; ++ } ++ ++ case ETHTOOL_GSET: { ++ struct ethtool_cmd cmd = { ETHTOOL_GSET }; ++ ++ if (!(bp->flags & B44_FLAG_INIT_COMPLETE)) ++ return -EAGAIN; ++ cmd.supported = (SUPPORTED_Autoneg); ++ cmd.supported |= (SUPPORTED_100baseT_Half | ++ SUPPORTED_100baseT_Full | ++ SUPPORTED_10baseT_Half | ++ SUPPORTED_10baseT_Full | ++ SUPPORTED_MII); ++ ++ cmd.advertising = 0; ++ if (bp->flags & B44_FLAG_ADV_10HALF) ++ cmd.advertising |= ADVERTISE_10HALF; ++ if (bp->flags & B44_FLAG_ADV_10FULL) ++ cmd.advertising |= ADVERTISE_10FULL; ++ if (bp->flags & B44_FLAG_ADV_100HALF) ++ cmd.advertising |= ADVERTISE_100HALF; ++ if (bp->flags & B44_FLAG_ADV_100FULL) ++ cmd.advertising |= ADVERTISE_100FULL; ++ cmd.advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; ++ cmd.speed = (bp->flags & B44_FLAG_100_BASE_T) ? ++ SPEED_100 : SPEED_10; ++ cmd.duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ? ++ DUPLEX_FULL : DUPLEX_HALF; ++ cmd.port = 0; ++ cmd.phy_address = bp->phy_addr; ++ cmd.transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ? ++ XCVR_INTERNAL : XCVR_EXTERNAL; ++ cmd.autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ? ++ AUTONEG_DISABLE : AUTONEG_ENABLE; ++ cmd.maxtxpkt = 0; ++ cmd.maxrxpkt = 0; ++ if (copy_to_user(useraddr, &cmd, sizeof(cmd))) ++ return -EFAULT; ++ return 0; ++ } ++ case ETHTOOL_SSET: { ++ struct ethtool_cmd cmd; ++ ++ if (!(bp->flags & B44_FLAG_INIT_COMPLETE)) ++ return -EAGAIN; ++ ++ if (copy_from_user(&cmd, useraddr, sizeof(cmd))) ++ return -EFAULT; ++ ++ /* We do not support gigabit. */ ++ if (cmd.autoneg == AUTONEG_ENABLE) { ++ if (cmd.advertising & ++ (ADVERTISED_1000baseT_Half | ++ ADVERTISED_1000baseT_Full)) ++ return -EINVAL; ++ } else if ((cmd.speed != SPEED_100 && ++ cmd.speed != SPEED_10) || ++ (cmd.duplex != DUPLEX_HALF && ++ cmd.duplex != DUPLEX_FULL)) { ++ return -EINVAL; ++ } ++ ++ spin_lock_irq(&bp->lock); ++ ++ if (cmd.autoneg == AUTONEG_ENABLE) { ++ bp->flags &= ~B44_FLAG_FORCE_LINK; ++ bp->flags &= ~(B44_FLAG_ADV_10HALF | ++ B44_FLAG_ADV_10FULL | ++ B44_FLAG_ADV_100HALF | ++ B44_FLAG_ADV_100FULL); ++ if (cmd.advertising & ADVERTISE_10HALF) ++ bp->flags |= B44_FLAG_ADV_10HALF; ++ if (cmd.advertising & ADVERTISE_10FULL) ++ bp->flags |= B44_FLAG_ADV_10FULL; ++ if (cmd.advertising & ADVERTISE_100HALF) ++ bp->flags |= B44_FLAG_ADV_100HALF; ++ if (cmd.advertising & ADVERTISE_100FULL) ++ bp->flags |= B44_FLAG_ADV_100FULL; ++ } else { ++ bp->flags |= B44_FLAG_FORCE_LINK; ++ if (cmd.speed == SPEED_100) ++ bp->flags |= B44_FLAG_100_BASE_T; ++ if (cmd.duplex == DUPLEX_FULL) ++ bp->flags |= B44_FLAG_FULL_DUPLEX; ++ } ++ ++ b44_setup_phy(bp); ++ ++ spin_unlock_irq(&bp->lock); ++ ++ return 0; ++ } ++ ++ case ETHTOOL_GMSGLVL: { ++ struct ethtool_value edata = { ETHTOOL_GMSGLVL }; ++ edata.data = bp->msg_enable; ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++ } ++ case ETHTOOL_SMSGLVL: { ++ struct ethtool_value edata; ++ if (copy_from_user(&edata, useraddr, sizeof(edata))) ++ return -EFAULT; ++ bp->msg_enable = edata.data; ++ return 0; ++ } ++ case ETHTOOL_NWAY_RST: { ++ u32 bmcr; ++ int r; ++ ++ spin_lock_irq(&bp->lock); ++ b44_readphy(bp, MII_BMCR, &bmcr); ++ b44_readphy(bp, MII_BMCR, &bmcr); ++ r = -EINVAL; ++ if (bmcr & BMCR_ANENABLE) { ++ b44_writephy(bp, MII_BMCR, ++ bmcr | BMCR_ANRESTART); ++ r = 0; ++ } ++ spin_unlock_irq(&bp->lock); ++ ++ return r; ++ } ++ case ETHTOOL_GLINK: { ++ struct ethtool_value edata = { ETHTOOL_GLINK }; ++ edata.data = netif_carrier_ok(bp->dev) ? 1 : 0; ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++ } ++ case ETHTOOL_GRINGPARAM: { ++ struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM }; ++ ++ ering.rx_max_pending = B44_RX_RING_SIZE - 1; ++ ering.rx_pending = bp->rx_pending; ++ ++ /* XXX ethtool lacks a tx_max_pending, oops... */ ++ ++ if (copy_to_user(useraddr, &ering, sizeof(ering))) ++ return -EFAULT; ++ return 0; ++ } ++ case ETHTOOL_SRINGPARAM: { ++ struct ethtool_ringparam ering; ++ ++ if (copy_from_user(&ering, useraddr, sizeof(ering))) ++ return -EFAULT; ++ ++ if ((ering.rx_pending > B44_RX_RING_SIZE - 1) || ++ (ering.rx_mini_pending != 0) || ++ (ering.rx_jumbo_pending != 0) || ++ (ering.tx_pending > B44_TX_RING_SIZE - 1)) ++ return -EINVAL; ++ ++ spin_lock_irq(&bp->lock); ++ ++ bp->rx_pending = ering.rx_pending; ++ bp->tx_pending = ering.tx_pending; ++ ++ b44_halt(bp); ++ b44_init_rings(bp); ++ b44_init_hw(bp, 1); ++ netif_wake_queue(bp->dev); ++ spin_unlock_irq(&bp->lock); ++ ++ b44_enable_ints(bp); ++ ++ return 0; ++ } ++ case ETHTOOL_GPAUSEPARAM: { ++ struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM }; ++ ++ epause.autoneg = ++ (bp->flags & B44_FLAG_PAUSE_AUTO) != 0; ++ epause.rx_pause = ++ (bp->flags & B44_FLAG_RX_PAUSE) != 0; ++ epause.tx_pause = ++ (bp->flags & B44_FLAG_TX_PAUSE) != 0; ++ if (copy_to_user(useraddr, &epause, sizeof(epause))) ++ return -EFAULT; ++ return 0; ++ } ++ case ETHTOOL_SPAUSEPARAM: { ++ struct ethtool_pauseparam epause; ++ ++ if (copy_from_user(&epause, useraddr, sizeof(epause))) ++ return -EFAULT; ++ ++ spin_lock_irq(&bp->lock); ++ if (epause.autoneg) ++ bp->flags |= B44_FLAG_PAUSE_AUTO; ++ else ++ bp->flags &= ~B44_FLAG_PAUSE_AUTO; ++ if (epause.rx_pause) ++ bp->flags |= B44_FLAG_RX_PAUSE; ++ else ++ bp->flags &= ~B44_FLAG_RX_PAUSE; ++ if (epause.tx_pause) ++ bp->flags |= B44_FLAG_TX_PAUSE; ++ else ++ bp->flags &= ~B44_FLAG_TX_PAUSE; ++ if (bp->flags & B44_FLAG_PAUSE_AUTO) { ++ b44_halt(bp); ++ b44_init_rings(bp); ++ b44_init_hw(bp, 1); ++ } else { ++ __b44_set_flow_ctrl(bp, bp->flags); ++ } ++ spin_unlock_irq(&bp->lock); ++ ++ b44_enable_ints(bp); ++ ++ return 0; ++ } ++ }; ++ ++ return -EOPNOTSUPP; ++} ++ + static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) + { + struct mii_ioctl_data *data = if_mii(ifr); +@@ -2044,40 +2217,64 @@ static int b44_ioctl(struct net_device * + if (!netif_running(dev)) + goto out; + +- spin_lock_irq(&bp->lock); +- err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL); +- spin_unlock_irq(&bp->lock); +-out: +- return err; +-} ++ switch (cmd) { ++ case SIOCETHTOOL: ++ return b44_ethtool_ioctl(dev, (void __user*) ifr->ifr_data); + +-/* Read 128-bytes of EEPROM. */ +-static int b44_read_eeprom(struct b44 *bp, u8 *data) +-{ +- long i; +- __le16 *ptr = (__le16 *) data; ++ case SIOCGMIIPHY: ++ data->phy_id = bp->phy_addr; + +- for (i = 0; i < 128; i += 2) +- ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i)); ++ /* fallthru */ ++ case SIOCGMIIREG: { ++ u32 mii_regval; ++ spin_lock_irq(&bp->lock); ++ err = __b44_readphy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, &mii_regval); ++ spin_unlock_irq(&bp->lock); + +- return 0; ++ data->val_out = mii_regval; ++ ++ return err; ++ } ++ ++ case SIOCSMIIREG: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ spin_lock_irq(&bp->lock); ++ err = __b44_writephy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); ++ spin_unlock_irq(&bp->lock); ++ ++ return err; ++ ++ default: ++ break; ++ }; ++ return -EOPNOTSUPP; ++ ++out: ++ return err; + } + + static int __devinit b44_get_invariants(struct b44 *bp) + { +- u8 eeprom[128]; +- int err; ++ struct ssb_device *sdev = bp->sdev; ++ int err = 0; ++ u8 *addr; + +- err = b44_read_eeprom(bp, &eeprom[0]); +- if (err) +- goto out; ++ bp->dma_offset = ssb_dma_translation(sdev); + +- bp->dev->dev_addr[0] = eeprom[79]; +- bp->dev->dev_addr[1] = eeprom[78]; +- bp->dev->dev_addr[2] = eeprom[81]; +- bp->dev->dev_addr[3] = eeprom[80]; +- bp->dev->dev_addr[4] = eeprom[83]; +- bp->dev->dev_addr[5] = eeprom[82]; ++ switch (instance) { ++ case 1: ++ addr = sdev->bus->sprom.et0mac; ++ bp->phy_addr = sdev->bus->sprom.et0phyaddr; ++ break; ++ default: ++ addr = sdev->bus->sprom.et1mac; ++ bp->phy_addr = sdev->bus->sprom.et1phyaddr; ++ break; ++ } ++ ++ memcpy(bp->dev->dev_addr, addr, 6); + + if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){ + printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n"); +@@ -2086,103 +2283,52 @@ static int __devinit b44_get_invariants( + + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len); + +- bp->phy_addr = eeprom[90] & 0x1f; +- + bp->imask = IMASK_DEF; + +- bp->core_unit = ssb_core_unit(bp); +- bp->dma_offset = SB_PCI_DMA; +- + /* XXX - really required? + bp->flags |= B44_FLAG_BUGGY_TXPTR; + */ + +- if (ssb_get_core_rev(bp) >= 7) ++ if (bp->sdev->id.revision >= 7) + bp->flags |= B44_FLAG_B0_ANDLATER; + +-out: + return err; + } + +-static int __devinit b44_init_one(struct pci_dev *pdev, +- const struct pci_device_id *ent) ++static int __devinit b44_init_one(struct ssb_device *sdev, ++ const struct ssb_device_id *ent) + { + static int b44_version_printed = 0; +- unsigned long b44reg_base, b44reg_len; + struct net_device *dev; + struct b44 *bp; + int err, i; + ++ instance++; ++ + if (b44_version_printed++ == 0) + printk(KERN_INFO "%s", version); + +- err = pci_enable_device(pdev); +- if (err) { +- dev_err(&pdev->dev, "Cannot enable PCI device, " +- "aborting.\n"); +- return err; +- } +- +- if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { +- dev_err(&pdev->dev, +- "Cannot find proper PCI device " +- "base address, aborting.\n"); +- err = -ENODEV; +- goto err_out_disable_pdev; +- } +- +- err = pci_request_regions(pdev, DRV_MODULE_NAME); +- if (err) { +- dev_err(&pdev->dev, +- "Cannot obtain PCI resources, aborting.\n"); +- goto err_out_disable_pdev; +- } +- +- pci_set_master(pdev); +- +- err = pci_set_dma_mask(pdev, (u64) DMA_30BIT_MASK); +- if (err) { +- dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n"); +- goto err_out_free_res; +- } +- +- err = pci_set_consistent_dma_mask(pdev, (u64) DMA_30BIT_MASK); +- if (err) { +- dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n"); +- goto err_out_free_res; +- } +- +- b44reg_base = pci_resource_start(pdev, 0); +- b44reg_len = pci_resource_len(pdev, 0); +- + dev = alloc_etherdev(sizeof(*bp)); + if (!dev) { +- dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n"); ++ dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n"); + err = -ENOMEM; +- goto err_out_free_res; ++ goto out; + } + + SET_MODULE_OWNER(dev); +- SET_NETDEV_DEV(dev,&pdev->dev); ++ SET_NETDEV_DEV(dev,sdev->dev); + + /* No interesting netdevice features in this card... */ + dev->features |= 0; + + bp = netdev_priv(dev); +- bp->pdev = pdev; ++ bp->sdev = sdev; + bp->dev = dev; + + bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE); + + spin_lock_init(&bp->lock); + +- bp->regs = ioremap(b44reg_base, b44reg_len); +- if (bp->regs == 0UL) { +- dev_err(&pdev->dev, "Cannot map device registers, aborting.\n"); +- err = -ENOMEM; +- goto err_out_free_dev; +- } +- + bp->rx_pending = B44_DEF_RX_RING_PENDING; + bp->tx_pending = B44_DEF_TX_RING_PENDING; + +@@ -2201,16 +2347,16 @@ static int __devinit b44_init_one(struct + dev->poll_controller = b44_poll_controller; + #endif + dev->change_mtu = b44_change_mtu; +- dev->irq = pdev->irq; ++ dev->irq = sdev->irq; + SET_ETHTOOL_OPS(dev, &b44_ethtool_ops); + + netif_carrier_off(dev); + + err = b44_get_invariants(bp); + if (err) { +- dev_err(&pdev->dev, ++ dev_err(sdev->dev, + "Problem fetching invariants of chip, aborting.\n"); +- goto err_out_iounmap; ++ goto err_out_free_dev; + } + + bp->mii_if.dev = dev; +@@ -2229,61 +2375,52 @@ static int __devinit b44_init_one(struct + + err = register_netdev(dev); + if (err) { +- dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); +- goto err_out_iounmap; ++ dev_err(sdev->dev, "Cannot register net device, aborting.\n"); ++ goto out; + } + +- pci_set_drvdata(pdev, dev); +- +- pci_save_state(bp->pdev); ++ ssb_set_drvdata(sdev, dev); + + /* Chip reset provides power to the b44 MAC & PCI cores, which + * is necessary for MAC register access. + */ + b44_chip_reset(bp); + +- printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name); ++ printk(KERN_INFO "%s: Broadcom 10/100BaseT Ethernet ", dev->name); + for (i = 0; i < 6; i++) + printk("%2.2x%c", dev->dev_addr[i], + i == 5 ? '\n' : ':'); + +- return 0; ++ /* Initialize phy */ ++ spin_lock_irq(&bp->lock); ++ b44_chip_reset(bp); ++ spin_unlock_irq(&bp->lock); + +-err_out_iounmap: +- iounmap(bp->regs); ++ return 0; + + err_out_free_dev: + free_netdev(dev); + +-err_out_free_res: +- pci_release_regions(pdev); +- +-err_out_disable_pdev: +- pci_disable_device(pdev); +- pci_set_drvdata(pdev, NULL); ++out: + return err; + } + +-static void __devexit b44_remove_one(struct pci_dev *pdev) ++static void __devexit b44_remove_one(struct ssb_device *pdev) + { +- struct net_device *dev = pci_get_drvdata(pdev); +- struct b44 *bp = netdev_priv(dev); ++ struct net_device *dev = ssb_get_drvdata(pdev); + + unregister_netdev(dev); +- iounmap(bp->regs); + free_netdev(dev); +- pci_release_regions(pdev); +- pci_disable_device(pdev); +- pci_set_drvdata(pdev, NULL); ++ ssb_set_drvdata(pdev, NULL); + } + +-static int b44_suspend(struct pci_dev *pdev, pm_message_t state) ++static int b44_suspend(struct ssb_device *pdev, pm_message_t state) + { +- struct net_device *dev = pci_get_drvdata(pdev); ++ struct net_device *dev = ssb_get_drvdata(pdev); + struct b44 *bp = netdev_priv(dev); + + if (!netif_running(dev)) +- return 0; ++ return 0; + + del_timer_sync(&bp->timer); + +@@ -2301,33 +2438,22 @@ static int b44_suspend(struct pci_dev *p + b44_init_hw(bp, B44_PARTIAL_RESET); + b44_setup_wol(bp); + } +- pci_disable_device(pdev); ++ + return 0; + } + +-static int b44_resume(struct pci_dev *pdev) ++static int b44_resume(struct ssb_device *pdev) + { +- struct net_device *dev = pci_get_drvdata(pdev); ++ struct net_device *dev = ssb_get_drvdata(pdev); + struct b44 *bp = netdev_priv(dev); + int rc = 0; + +- pci_restore_state(pdev); +- rc = pci_enable_device(pdev); +- if (rc) { +- printk(KERN_ERR PFX "%s: pci_enable_device failed\n", +- dev->name); +- return rc; +- } +- +- pci_set_master(pdev); +- + if (!netif_running(dev)) + return 0; + + rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev); + if (rc) { + printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name); +- pci_disable_device(pdev); + return rc; + } + +@@ -2346,29 +2472,31 @@ static int b44_resume(struct pci_dev *pd + return 0; + } + +-static struct pci_driver b44_driver = { ++static struct ssb_driver b44_driver = { + .name = DRV_MODULE_NAME, +- .id_table = b44_pci_tbl, ++ .id_table = b44_ssb_tbl, + .probe = b44_init_one, + .remove = __devexit_p(b44_remove_one), +- .suspend = b44_suspend, +- .resume = b44_resume, ++ .suspend = b44_suspend, ++ .resume = b44_resume, + }; + + static int __init b44_init(void) + { + unsigned int dma_desc_align_size = dma_get_cache_alignment(); + ++ instance = 0; ++ + /* Setup paramaters for syncing RX/TX DMA descriptors */ + dma_desc_align_mask = ~(dma_desc_align_size - 1); + dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc)); + +- return pci_register_driver(&b44_driver); ++ return ssb_driver_register(&b44_driver); + } + + static void __exit b44_cleanup(void) + { +- pci_unregister_driver(&b44_driver); ++ ssb_driver_unregister(&b44_driver); + } + + module_init(b44_init); +Index: linux-2.6.23.16/drivers/net/b44.h +=================================================================== +--- linux-2.6.23.16.orig/drivers/net/b44.h 2008-02-19 01:35:58.000000000 +0100 ++++ linux-2.6.23.16/drivers/net/b44.h 2008-02-19 01:36:00.000000000 +0100 +@@ -129,6 +129,7 @@ + #define RXCONFIG_FLOW 0x00000020 /* Flow Control Enable */ + #define RXCONFIG_FLOW_ACCEPT 0x00000040 /* Accept Unicast Flow Control Frame */ + #define RXCONFIG_RFILT 0x00000080 /* Reject Filter */ ++#define RXCONFIG_CAM_ABSENT 0x00000100 /* CAM Absent */ + #define B44_RXMAXLEN 0x0404UL /* EMAC RX Max Packet Length */ + #define B44_TXMAXLEN 0x0408UL /* EMAC TX Max Packet Length */ + #define B44_MDIO_CTRL 0x0410UL /* EMAC MDIO Control */ +@@ -227,75 +228,9 @@ + #define B44_RX_PAUSE 0x05D4UL /* MIB RX Pause Packets */ + #define B44_RX_NPAUSE 0x05D8UL /* MIB RX Non-Pause Packets */ + +-/* Silicon backplane register definitions */ +-#define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */ +-#define SBIMSTATE_PC 0x0000000f /* Pipe Count */ +-#define SBIMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */ +-#define SBIMSTATE_AP_BOTH 0x00000000 /* Use both timeslices and token */ +-#define SBIMSTATE_AP_TS 0x00000010 /* Use timeslices only */ +-#define SBIMSTATE_AP_TK 0x00000020 /* Use token only */ +-#define SBIMSTATE_AP_RSV 0x00000030 /* Reserved */ +-#define SBIMSTATE_IBE 0x00020000 /* In Band Error */ +-#define SBIMSTATE_TO 0x00040000 /* Timeout */ +-#define B44_SBINTVEC 0x0F94UL /* SB Interrupt Mask */ +-#define SBINTVEC_PCI 0x00000001 /* Enable interrupts for PCI */ +-#define SBINTVEC_ENET0 0x00000002 /* Enable interrupts for enet 0 */ +-#define SBINTVEC_ILINE20 0x00000004 /* Enable interrupts for iline20 */ +-#define SBINTVEC_CODEC 0x00000008 /* Enable interrupts for v90 codec */ +-#define SBINTVEC_USB 0x00000010 /* Enable interrupts for usb */ +-#define SBINTVEC_EXTIF 0x00000020 /* Enable interrupts for external i/f */ +-#define SBINTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */ +-#define B44_SBTMSLOW 0x0F98UL /* SB Target State Low */ +-#define SBTMSLOW_RESET 0x00000001 /* Reset */ +-#define SBTMSLOW_REJECT 0x00000002 /* Reject */ +-#define SBTMSLOW_CLOCK 0x00010000 /* Clock Enable */ +-#define SBTMSLOW_FGC 0x00020000 /* Force Gated Clocks On */ +-#define SBTMSLOW_PE 0x40000000 /* Power Management Enable */ +-#define SBTMSLOW_BE 0x80000000 /* BIST Enable */ +-#define B44_SBTMSHIGH 0x0F9CUL /* SB Target State High */ +-#define SBTMSHIGH_SERR 0x00000001 /* S-error */ +-#define SBTMSHIGH_INT 0x00000002 /* Interrupt */ +-#define SBTMSHIGH_BUSY 0x00000004 /* Busy */ +-#define SBTMSHIGH_GCR 0x20000000 /* Gated Clock Request */ +-#define SBTMSHIGH_BISTF 0x40000000 /* BIST Failed */ +-#define SBTMSHIGH_BISTD 0x80000000 /* BIST Done */ +-#define B44_SBIDHIGH 0x0FFCUL /* SB Identification High */ +-#define SBIDHIGH_RC_MASK 0x0000000f /* Revision Code */ +-#define SBIDHIGH_CC_MASK 0x0000fff0 /* Core Code */ +-#define SBIDHIGH_CC_SHIFT 4 +-#define SBIDHIGH_VC_MASK 0xffff0000 /* Vendor Code */ +-#define SBIDHIGH_VC_SHIFT 16 +- +-/* SSB PCI config space registers. */ +-#define SSB_PMCSR 0x44 +-#define SSB_PE 0x100 +-#define SSB_BAR0_WIN 0x80 +-#define SSB_BAR1_WIN 0x84 +-#define SSB_SPROM_CONTROL 0x88 +-#define SSB_BAR1_CONTROL 0x8c +- +-/* SSB core and host control registers. */ +-#define SSB_CONTROL 0x0000UL +-#define SSB_ARBCONTROL 0x0010UL +-#define SSB_ISTAT 0x0020UL +-#define SSB_IMASK 0x0024UL +-#define SSB_MBOX 0x0028UL +-#define SSB_BCAST_ADDR 0x0050UL +-#define SSB_BCAST_DATA 0x0054UL +-#define SSB_PCI_TRANS_0 0x0100UL +-#define SSB_PCI_TRANS_1 0x0104UL +-#define SSB_PCI_TRANS_2 0x0108UL +-#define SSB_SPROM 0x0800UL +- +-#define SSB_PCI_MEM 0x00000000 +-#define SSB_PCI_IO 0x00000001 +-#define SSB_PCI_CFG0 0x00000002 +-#define SSB_PCI_CFG1 0x00000003 +-#define SSB_PCI_PREF 0x00000004 +-#define SSB_PCI_BURST 0x00000008 +-#define SSB_PCI_MASK0 0xfc000000 +-#define SSB_PCI_MASK1 0xfc000000 +-#define SSB_PCI_MASK2 0xc0000000 ++#define br32(bp, REG) ssb_read32((bp)->sdev, (REG)) ++#define bw32(bp, REG, VAL) ssb_write32((bp)->sdev, (REG), (VAL)) ++#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0) + + /* 4400 PHY registers */ + #define B44_MII_AUXCTRL 24 /* Auxiliary Control */ +@@ -346,10 +281,12 @@ struct rx_header { + + struct ring_info { + struct sk_buff *skb; +- DECLARE_PCI_UNMAP_ADDR(mapping); ++ dma_addr_t mapping; + }; + + #define B44_MCAST_TABLE_SIZE 32 ++#define B44_PHY_ADDR_NO_PHY 30 ++#define B44_MDC_RATIO 5000000 + + #define B44_STAT_REG_DECLARE \ + _B44(tx_good_octets) \ +@@ -425,9 +362,10 @@ struct b44 { + + u32 dma_offset; + u32 flags; +-#define B44_FLAG_B0_ANDLATER 0x00000001 ++#define B44_FLAG_INIT_COMPLETE 0x00000001 + #define B44_FLAG_BUGGY_TXPTR 0x00000002 + #define B44_FLAG_REORDER_BUG 0x00000004 ++#define B44_FLAG_B0_ANDLATER 0x00000008 + #define B44_FLAG_PAUSE_AUTO 0x00008000 + #define B44_FLAG_FULL_DUPLEX 0x00010000 + #define B44_FLAG_100_BASE_T 0x00020000 +@@ -450,8 +388,7 @@ struct b44 { + struct net_device_stats stats; + struct b44_hw_stats hw_stats; + +- void __iomem *regs; +- struct pci_dev *pdev; ++ struct ssb_device *sdev; + struct net_device *dev; + + dma_addr_t rx_ring_dma, tx_ring_dma; +Index: linux-2.6.23.16/drivers/net/Kconfig +=================================================================== +--- linux-2.6.23.16.orig/drivers/net/Kconfig 2008-02-19 01:35:58.000000000 +0100 ++++ linux-2.6.23.16/drivers/net/Kconfig 2008-02-19 01:36:00.000000000 +0100 +@@ -1577,7 +1577,7 @@ config APRICOT + + config B44 + tristate "Broadcom 4400 ethernet support" +- depends on NET_PCI && PCI ++ depends on SSB && EXPERIMENTAL + select MII + help + If you have a network (Ethernet) controller of this type, say Y and diff --git a/target/linux/brcm47xx/patches-2.6.25/121-fix_b44_phyaddr.patch b/target/linux/brcm47xx/patches-2.6.25/121-fix_b44_phyaddr.patch new file mode 100644 index 0000000000..c93d517923 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/121-fix_b44_phyaddr.patch @@ -0,0 +1,15 @@ +Index: linux-2.6.23.16/drivers/net/b44.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/net/b44.c 2008-03-22 19:52:40.000000000 -0700 ++++ linux-2.6.23.16/drivers/net/b44.c 2008-03-22 19:52:41.000000000 -0700 +@@ -2273,6 +2273,10 @@ + bp->phy_addr = sdev->bus->sprom.et1phyaddr; + break; + } ++ /* Some ROMs have buggy PHY addresses with the high ++ * bits set (sign extension?). Truncate them to a ++ * valid PHY address. */ ++ bp->phy_addr &= 0x1F; + + memcpy(bp->dev->dev_addr, addr, 6); + diff --git a/target/linux/brcm47xx/patches-2.6.25/130-remove_scache.patch b/target/linux/brcm47xx/patches-2.6.25/130-remove_scache.patch new file mode 100644 index 0000000000..eea4e26026 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/130-remove_scache.patch @@ -0,0 +1,97 @@ +Index: linux-2.6.23/arch/mips/Kconfig +=================================================================== +--- linux-2.6.23.orig/arch/mips/Kconfig 2007-10-13 02:23:41.484492317 +0200 ++++ linux-2.6.23/arch/mips/Kconfig 2007-10-13 02:47:02.784347843 +0200 +@@ -192,7 +192,6 @@ + select I8259 + select MIPS_BOARDS_GEN + select MIPS_BONITO64 +- select MIPS_CPU_SCACHE + select PCI_GT64XXX_PCI0 + select MIPS_MSC + select SWAP_IO_SPACE +@@ -1281,13 +1280,6 @@ + bool + select BOARD_SCACHE + +-# +-# Support for a MIPS32 / MIPS64 style S-caches +-# +-config MIPS_CPU_SCACHE +- bool +- select BOARD_SCACHE +- + config R5000_CPU_SCACHE + bool + select BOARD_SCACHE +Index: linux-2.6.23/arch/mips/kernel/cpu-probe.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/kernel/cpu-probe.c 2007-10-13 02:23:11.210767122 +0200 ++++ linux-2.6.23/arch/mips/kernel/cpu-probe.c 2007-10-13 02:47:02.788348072 +0200 +@@ -701,6 +701,8 @@ + break; + case PRID_IMP_25KF: + c->cputype = CPU_25KF; ++ /* Probe for L2 cache */ ++ c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; + break; + case PRID_IMP_34K: + c->cputype = CPU_34K; +Index: linux-2.6.23/arch/mips/mm/c-r4k.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/mm/c-r4k.c 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/arch/mips/mm/c-r4k.c 2007-10-13 02:47:02.792348301 +0200 +@@ -1086,7 +1086,6 @@ + + extern int r5k_sc_init(void); + extern int rm7k_sc_init(void); +-extern int mips_sc_init(void); + + static void __init setup_scache(void) + { +@@ -1140,29 +1139,17 @@ + #endif + + default: +- if (c->isa_level == MIPS_CPU_ISA_M32R1 || +- c->isa_level == MIPS_CPU_ISA_M32R2 || +- c->isa_level == MIPS_CPU_ISA_M64R1 || +- c->isa_level == MIPS_CPU_ISA_M64R2) { +-#ifdef CONFIG_MIPS_CPU_SCACHE +- if (mips_sc_init ()) { +- scache_size = c->scache.ways * c->scache.sets * c->scache.linesz; +- printk("MIPS secondary cache %ldkB, %s, linesize %d bytes.\n", +- scache_size >> 10, +- way_string[c->scache.ways], c->scache.linesz); +- } +-#else +- if (!(c->scache.flags & MIPS_CACHE_NOT_PRESENT)) +- panic("Dunno how to handle MIPS32 / MIPS64 second level cache"); +-#endif +- return; +- } + sc_present = 0; + } + + if (!sc_present) + return; + ++ if ((c->isa_level == MIPS_CPU_ISA_M32R1 || ++ c->isa_level == MIPS_CPU_ISA_M64R1) && ++ !(c->scache.flags & MIPS_CACHE_NOT_PRESENT)) ++ panic("Dunno how to handle MIPS32 / MIPS64 second level cache"); ++ + /* compute a couple of other cache variables */ + c->scache.waysize = scache_size / c->scache.ways; + +Index: linux-2.6.23/arch/mips/mm/Makefile +=================================================================== +--- linux-2.6.23.orig/arch/mips/mm/Makefile 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/arch/mips/mm/Makefile 2007-10-13 02:47:23.393522295 +0200 +@@ -31,6 +31,5 @@ + obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o + obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o + obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o +-obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o + + EXTRA_CFLAGS += -Werror diff --git a/target/linux/brcm47xx/patches-2.6.25/150-cpu_fixes.patch b/target/linux/brcm47xx/patches-2.6.25/150-cpu_fixes.patch new file mode 100644 index 0000000000..d19ba81fad --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/150-cpu_fixes.patch @@ -0,0 +1,361 @@ +Index: linux-2.6.23/arch/mips/kernel/genex.S +=================================================================== +--- linux-2.6.23.orig/arch/mips/kernel/genex.S 2007-10-13 11:29:46.219648163 +0200 ++++ linux-2.6.23/arch/mips/kernel/genex.S 2007-10-13 11:29:49.619841933 +0200 +@@ -51,6 +51,10 @@ + NESTED(except_vec3_generic, 0, sp) + .set push + .set noat ++#ifdef CONFIG_BCM947XX ++ nop ++ nop ++#endif + #if R5432_CP0_INTERRUPT_WAR + mfc0 k0, CP0_INDEX + #endif +Index: linux-2.6.23/arch/mips/mm/c-r4k.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/mm/c-r4k.c 2007-10-13 11:29:46.227648623 +0200 ++++ linux-2.6.23/arch/mips/mm/c-r4k.c 2007-10-13 11:29:49.619841933 +0200 +@@ -30,6 +30,9 @@ + #include <asm/cacheflush.h> /* for run_uncached() */ + + ++/* For enabling BCM4710 cache workarounds */ ++int bcm4710 = 0; ++ + /* + * Special Variant of smp_call_function for use by cache functions: + * +@@ -94,6 +97,9 @@ + { + unsigned long dc_lsize = cpu_dcache_line_size(); + ++ if (bcm4710) ++ r4k_blast_dcache_page = blast_dcache_page; ++ else + if (dc_lsize == 0) + r4k_blast_dcache_page = (void *)cache_noop; + else if (dc_lsize == 16) +@@ -108,6 +114,9 @@ + { + unsigned long dc_lsize = cpu_dcache_line_size(); + ++ if (bcm4710) ++ r4k_blast_dcache_page_indexed = blast_dcache_page_indexed; ++ else + if (dc_lsize == 0) + r4k_blast_dcache_page_indexed = (void *)cache_noop; + else if (dc_lsize == 16) +@@ -122,6 +131,9 @@ + { + unsigned long dc_lsize = cpu_dcache_line_size(); + ++ if (bcm4710) ++ r4k_blast_dcache = blast_dcache; ++ else + if (dc_lsize == 0) + r4k_blast_dcache = (void *)cache_noop; + else if (dc_lsize == 16) +@@ -623,6 +635,8 @@ + unsigned long addr = (unsigned long) arg; + + R4600_HIT_CACHEOP_WAR_IMPL; ++ BCM4710_PROTECTED_FILL_TLB(addr); ++ BCM4710_PROTECTED_FILL_TLB(addr + 4); + if (dc_lsize) + protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); + if (!cpu_icache_snoops_remote_store && scache_size) +@@ -1198,6 +1212,17 @@ + * silly idea of putting something else there ... + */ + switch (current_cpu_data.cputype) { ++ case CPU_BCM3302: ++ { ++ u32 cm; ++ cm = read_c0_diag(); ++ /* Enable icache */ ++ cm |= (1 << 31); ++ /* Enable dcache */ ++ cm |= (1 << 30); ++ write_c0_diag(cm); ++ } ++ break; + case CPU_R4000PC: + case CPU_R4000SC: + case CPU_R4000MC: +@@ -1228,6 +1253,15 @@ + /* Default cache error handler for R4000 and R5000 family */ + set_uncached_handler (0x100, &except_vec2_generic, 0x80); + ++ /* Check if special workarounds are required */ ++#ifdef CONFIG_BCM947XX ++ if (current_cpu_data.cputype == CPU_BCM4710 && (current_cpu_data.processor_id & 0xff) == 0) { ++ printk("Enabling BCM4710A0 cache workarounds.\n"); ++ bcm4710 = 1; ++ } else ++#endif ++ bcm4710 = 0; ++ + probe_pcache(); + setup_scache(); + +@@ -1273,5 +1307,13 @@ + build_clear_page(); + build_copy_page(); + local_r4k___flush_cache_all(NULL); ++#ifdef CONFIG_BCM947XX ++ { ++ static void (*_coherency_setup)(void); ++ _coherency_setup = (void (*)(void)) KSEG1ADDR(coherency_setup); ++ _coherency_setup(); ++ } ++#else + coherency_setup(); ++#endif + } +Index: linux-2.6.23/arch/mips/mm/tlbex.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/mm/tlbex.c 2007-10-13 11:29:46.235649074 +0200 ++++ linux-2.6.23/arch/mips/mm/tlbex.c 2007-10-13 11:35:46.076155216 +0200 +@@ -1273,6 +1273,9 @@ + /* No need for i_nop */ + } + ++#ifdef CONFIG_BCM947XX ++ i_nop(&p); ++#endif + #ifdef CONFIG_64BIT + build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */ + #else +@@ -1708,6 +1711,9 @@ + struct reloc **r, unsigned int pte, + unsigned int ptr) + { ++#ifdef CONFIG_BCM947XX ++ i_nop(p); ++#endif + #ifdef CONFIG_64BIT + build_get_pmde64(p, l, r, pte, ptr); /* get pmd in ptr */ + #else +Index: linux-2.6.23/include/asm-mips/r4kcache.h +=================================================================== +--- linux-2.6.23.orig/include/asm-mips/r4kcache.h 2007-10-13 11:29:46.255650214 +0200 ++++ linux-2.6.23/include/asm-mips/r4kcache.h 2007-10-13 11:29:49.631842613 +0200 +@@ -17,6 +17,20 @@ + #include <asm/cpu-features.h> + #include <asm/mipsmtregs.h> + ++#ifdef CONFIG_BCM947XX ++#include <asm/paccess.h> ++#include <linux/ssb/ssb.h> ++#define BCM4710_DUMMY_RREG() ((void) *((u8 *) KSEG1ADDR(SSB_ENUM_BASE + SSB_IMSTATE))) ++ ++#define BCM4710_FILL_TLB(addr) (*(volatile unsigned long *)(addr)) ++#define BCM4710_PROTECTED_FILL_TLB(addr) ({ unsigned long x; get_dbe(x, (volatile unsigned long *)(addr)); }) ++#else ++#define BCM4710_DUMMY_RREG() ++ ++#define BCM4710_FILL_TLB(addr) ++#define BCM4710_PROTECTED_FILL_TLB(addr) ++#endif ++ + /* + * This macro return a properly sign-extended address suitable as base address + * for indexed cache operations. Two issues here: +@@ -150,6 +164,7 @@ + static inline void flush_dcache_line_indexed(unsigned long addr) + { + __dflush_prologue ++ BCM4710_DUMMY_RREG(); + cache_op(Index_Writeback_Inv_D, addr); + __dflush_epilogue + } +@@ -169,6 +184,7 @@ + static inline void flush_dcache_line(unsigned long addr) + { + __dflush_prologue ++ BCM4710_DUMMY_RREG(); + cache_op(Hit_Writeback_Inv_D, addr); + __dflush_epilogue + } +@@ -176,6 +192,7 @@ + static inline void invalidate_dcache_line(unsigned long addr) + { + __dflush_prologue ++ BCM4710_DUMMY_RREG(); + cache_op(Hit_Invalidate_D, addr); + __dflush_epilogue + } +@@ -208,6 +225,7 @@ + */ + static inline void protected_flush_icache_line(unsigned long addr) + { ++ BCM4710_DUMMY_RREG(); + protected_cache_op(Hit_Invalidate_I, addr); + } + +@@ -219,6 +237,7 @@ + */ + static inline void protected_writeback_dcache_line(unsigned long addr) + { ++ BCM4710_DUMMY_RREG(); + protected_cache_op(Hit_Writeback_Inv_D, addr); + } + +@@ -339,8 +358,52 @@ + : "r" (base), \ + "i" (op)); + ++static inline void blast_dcache(void) ++{ ++ unsigned long start = KSEG0; ++ unsigned long dcache_size = current_cpu_data.dcache.waysize * current_cpu_data.dcache.ways; ++ unsigned long end = (start + dcache_size); ++ ++ do { ++ BCM4710_DUMMY_RREG(); ++ cache_op(Index_Writeback_Inv_D, start); ++ start += current_cpu_data.dcache.linesz; ++ } while(start < end); ++} ++ ++static inline void blast_dcache_page(unsigned long page) ++{ ++ unsigned long start = page; ++ unsigned long end = start + PAGE_SIZE; ++ ++ BCM4710_FILL_TLB(start); ++ do { ++ BCM4710_DUMMY_RREG(); ++ cache_op(Hit_Writeback_Inv_D, start); ++ start += current_cpu_data.dcache.linesz; ++ } while(start < end); ++} ++ ++static inline void blast_dcache_page_indexed(unsigned long page) ++{ ++ unsigned long start = page; ++ unsigned long end = start + PAGE_SIZE; ++ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit; ++ unsigned long ws_end = current_cpu_data.dcache.ways << ++ current_cpu_data.dcache.waybit; ++ unsigned long ws, addr; ++ for (ws = 0; ws < ws_end; ws += ws_inc) { ++ start = page + ws; ++ for (addr = start; addr < end; addr += current_cpu_data.dcache.linesz) { ++ BCM4710_DUMMY_RREG(); ++ cache_op(Index_Writeback_Inv_D, addr); ++ } ++ } ++} ++ ++ + /* build blast_xxx, blast_xxx_page, blast_xxx_page_indexed */ +-#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize) \ ++#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize, war) \ + static inline void blast_##pfx##cache##lsize(void) \ + { \ + unsigned long start = INDEX_BASE; \ +@@ -352,6 +415,7 @@ + \ + __##pfx##flush_prologue \ + \ ++ war \ + for (ws = 0; ws < ws_end; ws += ws_inc) \ + for (addr = start; addr < end; addr += lsize * 32) \ + cache##lsize##_unroll32(addr|ws,indexop); \ +@@ -366,6 +430,7 @@ + \ + __##pfx##flush_prologue \ + \ ++ war \ + do { \ + cache##lsize##_unroll32(start,hitop); \ + start += lsize * 32; \ +@@ -384,6 +449,8 @@ + current_cpu_data.desc.waybit; \ + unsigned long ws, addr; \ + \ ++ war \ ++ \ + __##pfx##flush_prologue \ + \ + for (ws = 0; ws < ws_end; ws += ws_inc) \ +@@ -393,28 +460,30 @@ + __##pfx##flush_epilogue \ + } + +-__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16) +-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16) +-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16) +-__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32) +-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32) +-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32) +-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64) +-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64) +-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128) ++__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16, ) ++__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16, BCM4710_FILL_TLB(start);) ++__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16, ) ++__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32, ) ++__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32, BCM4710_FILL_TLB(start);) ++__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32, ) ++__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, BCM4710_FILL_TLB(start);) ++__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64, ) ++__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128, ) + + /* build blast_xxx_range, protected_blast_xxx_range */ +-#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \ ++#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot, war, war2) \ + static inline void prot##blast_##pfx##cache##_range(unsigned long start, \ + unsigned long end) \ + { \ + unsigned long lsize = cpu_##desc##_line_size(); \ + unsigned long addr = start & ~(lsize - 1); \ + unsigned long aend = (end - 1) & ~(lsize - 1); \ ++ war \ + \ + __##pfx##flush_prologue \ + \ + while (1) { \ ++ war2 \ + prot##cache_op(hitop, addr); \ + if (addr == aend) \ + break; \ +@@ -424,13 +493,13 @@ + __##pfx##flush_epilogue \ + } + +-__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_) +-__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_) +-__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_) +-__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, ) +-__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, ) ++__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_, BCM4710_PROTECTED_FILL_TLB(addr); BCM4710_PROTECTED_FILL_TLB(aend);, BCM4710_DUMMY_RREG();) ++__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_,, ) ++__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_,, ) ++__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D,, BCM4710_FILL_TLB(addr); BCM4710_FILL_TLB(aend);, BCM4710_DUMMY_RREG();) ++__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD,,, ) + /* blast_inv_dcache_range */ +-__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, ) +-__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, ) ++__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D,,,BCM4710_DUMMY_RREG();) ++__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD,,, ) + + #endif /* _ASM_R4KCACHE_H */ +Index: linux-2.6.23/include/asm-mips/stackframe.h +=================================================================== +--- linux-2.6.23.orig/include/asm-mips/stackframe.h 2007-10-13 11:29:46.263650671 +0200 ++++ linux-2.6.23/include/asm-mips/stackframe.h 2007-10-13 11:33:38.504885346 +0200 +@@ -350,6 +350,10 @@ + .macro RESTORE_SP_AND_RET + LONG_L sp, PT_R29(sp) + .set mips3 ++#ifdef CONFIG_BCM947XX ++ nop ++ nop ++#endif + eret + .set mips0 + .endm diff --git a/target/linux/brcm47xx/patches-2.6.25/160-kmap_coherent.patch b/target/linux/brcm47xx/patches-2.6.25/160-kmap_coherent.patch new file mode 100644 index 0000000000..8a3bd0ec74 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/160-kmap_coherent.patch @@ -0,0 +1,63 @@ +Index: linux-2.6.23/arch/mips/mm/init.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/mm/init.c 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/arch/mips/mm/init.c 2007-10-13 02:57:18.483434538 +0200 +@@ -211,7 +211,7 @@ + void *vfrom, *vto; + + vto = kmap_atomic(to, KM_USER1); +- if (cpu_has_dc_aliases && !Page_dcache_dirty(from)) { ++ if (cpu_has_dc_aliases && cpu_use_kmap_coherent && !Page_dcache_dirty(from)) { + vfrom = kmap_coherent(from, vaddr); + copy_page(vto, vfrom); + kunmap_coherent(); +@@ -234,7 +234,7 @@ + struct page *page, unsigned long vaddr, void *dst, const void *src, + unsigned long len) + { +- if (cpu_has_dc_aliases) { ++ if (cpu_has_dc_aliases && cpu_use_kmap_coherent) { + void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(vto, src, len); + kunmap_coherent(); +@@ -250,7 +250,7 @@ + struct page *page, unsigned long vaddr, void *dst, const void *src, + unsigned long len) + { +- if (cpu_has_dc_aliases) { ++ if (cpu_has_dc_aliases && cpu_use_kmap_coherent) { + void *vfrom = + kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(dst, vfrom, len); +Index: linux-2.6.23/include/asm-mips/mach-bcm947xx/cpu-feature-overrides.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.23/include/asm-mips/mach-bcm947xx/cpu-feature-overrides.h 2007-10-13 02:56:22.020216880 +0200 +@@ -0,0 +1,13 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) ++ */ ++#ifndef __ASM_MACH_BCM947XX_CPU_FEATURE_OVERRIDES_H ++#define __ASM_MACH_BCM947XX_CPU_FEATURE_OVERRIDES_H ++ ++#define cpu_use_kmap_coherent 0 ++ ++#endif /* __ASM_MACH_BCM947XX_CPU_FEATURE_OVERRIDES_H */ +Index: linux-2.6.23/include/asm-mips/cpu-features.h +=================================================================== +--- linux-2.6.23.orig/include/asm-mips/cpu-features.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/include/asm-mips/cpu-features.h 2007-10-13 02:56:22.028217337 +0200 +@@ -101,6 +101,9 @@ + #ifndef cpu_has_pindexed_dcache + #define cpu_has_pindexed_dcache (cpu_data[0].dcache.flags & MIPS_CACHE_PINDEX) + #endif ++#ifndef cpu_use_kmap_coherent ++#define cpu_use_kmap_coherent 1 ++#endif + + /* + * I-Cache snoops remote store. This only matters on SMP. Some multiprocessors diff --git a/target/linux/brcm47xx/patches-2.6.25/170-cpu_wait.patch b/target/linux/brcm47xx/patches-2.6.25/170-cpu_wait.patch new file mode 100644 index 0000000000..62b3b12b8f --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/170-cpu_wait.patch @@ -0,0 +1,12 @@ +Index: linux-2.6.23/arch/mips/kernel/cpu-probe.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/kernel/cpu-probe.c 2007-10-13 02:47:02.788348072 +0200 ++++ linux-2.6.23/arch/mips/kernel/cpu-probe.c 2007-10-13 02:57:46.293019312 +0200 +@@ -159,6 +159,7 @@ + case CPU_5KC: + case CPU_25KF: + case CPU_PR4450: ++ case CPU_BCM3302: + cpu_wait = r4k_wait; + break; + diff --git a/target/linux/brcm47xx/patches-2.6.25/220-bcm5354.patch b/target/linux/brcm47xx/patches-2.6.25/220-bcm5354.patch new file mode 100644 index 0000000000..53818aba6d --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/220-bcm5354.patch @@ -0,0 +1,48 @@ +Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/driver_chipcommon.c 2008-02-19 13:46:08.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/driver_chipcommon.c 2008-02-19 13:46:17.000000000 +0100 +@@ -270,6 +270,8 @@ void ssb_chipco_resume(struct ssb_chipco + void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m) + { ++ if ((chipco_read32(cc, SSB_CHIPCO_CHIPID) & SSB_CHIPCO_IDMASK) == 0x5354) ++ return; + *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); + *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); + switch (*plltype) { +@@ -293,6 +295,8 @@ void ssb_chipco_get_clockcpu(struct ssb_ + void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m) + { ++ if ((chipco_read32(cc, SSB_CHIPCO_CHIPID) & SSB_CHIPCO_IDMASK) == 0x5354) ++ return; + *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); + *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); + switch (*plltype) { +Index: linux-2.6.23.16/drivers/ssb/driver_mipscore.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/driver_mipscore.c 2008-02-19 13:46:08.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/driver_mipscore.c 2008-02-19 13:46:17.000000000 +0100 +@@ -160,6 +160,8 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m + + if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) { + rate = 200000000; ++ } else if (bus->chip_id == 0x5354) { ++ rate = 240000000; + } else { + rate = ssb_calc_clock_rate(pll_type, n, m); + } +Index: linux-2.6.23.16/drivers/ssb/main.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-02-19 13:46:08.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-19 13:46:17.000000000 +0100 +@@ -862,6 +862,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus) + + if (bus->chip_id == 0x5365) { + rate = 100000000; ++ } else if (bus->chip_id == 0x5354) { ++ rate = 120000000; + } else { + rate = ssb_calc_clock_rate(plltype, clkctl_n, clkctl_m); + if (plltype == SSB_PLLTYPE_3) /* 25Mhz, 2 dividers */ diff --git a/target/linux/brcm47xx/patches-2.6.25/230-ohci-ssb.patch b/target/linux/brcm47xx/patches-2.6.25/230-ohci-ssb.patch new file mode 100644 index 0000000000..5be1a66c58 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/230-ohci-ssb.patch @@ -0,0 +1,345 @@ +From: Michael Buesch <mb@bu3sch.de> +Date: Wed, 10 Oct 2007 06:47:17 +0000 (-0700) +Subject: USB: ohci SSB bus glue +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fralf%2Flinux.git;a=commitdiff_plain;h=c604e851486eabcbeb73e984279d436ce121fd5d + +USB: ohci SSB bus glue + +This adds SSB bus glue for the USB OHCI HCD. + +Signed-off-by: Michael Buesch <mb@bu3sch.de> +Signed-off-by: John W. Linville <linville@tuxdriver.com> +Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + +Index: linux-2.6.23.16/drivers/usb/host/Kconfig +=================================================================== +--- linux-2.6.23.16.orig/drivers/usb/host/Kconfig 2008-02-19 00:47:29.000000000 +0100 ++++ linux-2.6.23.16/drivers/usb/host/Kconfig 2008-02-19 00:47:51.000000000 +0100 +@@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI + Enables support for PCI-bus plug-in USB controller cards. + If unsure, say Y. + ++config USB_OHCI_HCD_SSB ++ bool "OHCI support for Broadcom SSB OHCI core" ++ depends on USB_OHCI_HCD && SSB && EXPERIMENTAL ++ default n ++ ---help--- ++ Support for the Sonics Silicon Backplane (SSB) attached ++ Broadcom USB OHCI core. ++ ++ This device is present in some embedded devices with ++ Broadcom based SSB bus. ++ ++ If unsure, say N. ++ + config USB_OHCI_BIG_ENDIAN_DESC + bool + depends on USB_OHCI_HCD +Index: linux-2.6.23.16/drivers/usb/host/ohci-hcd.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/usb/host/ohci-hcd.c 2008-02-19 00:47:29.000000000 +0100 ++++ linux-2.6.23.16/drivers/usb/host/ohci-hcd.c 2008-02-19 00:47:51.000000000 +0100 +@@ -926,11 +926,17 @@ MODULE_LICENSE ("GPL"); + #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver + #endif + ++#ifdef CONFIG_USB_OHCI_HCD_SSB ++#include "ohci-ssb.c" ++#define SSB_OHCI_DRIVER ssb_ohci_driver ++#endif ++ + #if !defined(PCI_DRIVER) && \ + !defined(PLATFORM_DRIVER) && \ + !defined(OF_PLATFORM_DRIVER) && \ + !defined(SA1111_DRIVER) && \ +- !defined(PS3_SYSTEM_BUS_DRIVER) ++ !defined(PS3_SYSTEM_BUS_DRIVER) && \ ++ !defined(SSB_OHCI_DRIVER) + #error "missing bus glue for ohci-hcd" + #endif + +@@ -975,10 +981,20 @@ static int __init ohci_hcd_mod_init(void + goto error_pci; + #endif + ++#ifdef SSB_OHCI_DRIVER ++ retval = ssb_driver_register(&SSB_OHCI_DRIVER); ++ if (retval) ++ goto error_ssb; ++#endif ++ + return retval; + + /* Error path */ ++#ifdef SSB_OHCI_DRIVER ++ error_ssb: ++#endif + #ifdef PCI_DRIVER ++ pci_unregister_driver(&PCI_DRIVER); + error_pci: + #endif + #ifdef SA1111_DRIVER +@@ -1003,6 +1019,9 @@ module_init(ohci_hcd_mod_init); + + static void __exit ohci_hcd_mod_exit(void) + { ++#ifdef SSB_OHCI_DRIVER ++ ssb_driver_unregister(&SSB_OHCI_DRIVER); ++#endif + #ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); + #endif +Index: linux-2.6.23.16/drivers/usb/host/ohci-ssb.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.23.16/drivers/usb/host/ohci-ssb.c 2008-02-19 00:47:51.000000000 +0100 +@@ -0,0 +1,247 @@ ++/* ++ * Sonics Silicon Backplane ++ * Broadcom USB-core OHCI driver ++ * ++ * Copyright 2007 Michael Buesch <mb@bu3sch.de> ++ * ++ * Derived from the OHCI-PCI driver ++ * Copyright 1999 Roman Weissgaerber ++ * Copyright 2000-2002 David Brownell ++ * Copyright 1999 Linus Torvalds ++ * Copyright 1999 Gregory P. Smith ++ * ++ * Derived from the USBcore related parts of Broadcom-SB ++ * Copyright 2005 Broadcom Corporation ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++#include <linux/ssb/ssb.h> ++ ++ ++#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) ++ ++struct ssb_ohci_device { ++ struct ohci_hcd ohci; /* _must_ be at the beginning. */ ++ ++ u32 enable_flags; ++}; ++ ++static inline ++struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd) ++{ ++ return (struct ssb_ohci_device *)(hcd->hcd_priv); ++} ++ ++ ++static int ssb_ohci_reset(struct usb_hcd *hcd) ++{ ++ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); ++ struct ohci_hcd *ohci = &ohcidev->ohci; ++ int err; ++ ++ ohci_hcd_init(ohci); ++ err = ohci_init(ohci); ++ ++ return err; ++} ++ ++static int ssb_ohci_start(struct usb_hcd *hcd) ++{ ++ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); ++ struct ohci_hcd *ohci = &ohcidev->ohci; ++ int err; ++ ++ err = ohci_run(ohci); ++ if (err < 0) { ++ ohci_err(ohci, "can't start\n"); ++ ohci_stop(hcd); ++ } ++ ++ return err; ++} ++ ++#ifdef CONFIG_PM ++static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message) ++{ ++ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); ++ struct ohci_hcd *ohci = &ohcidev->ohci; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ohci->lock, flags); ++ ++ ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); ++ ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */ ++ ++ /* make sure snapshot being resumed re-enumerates everything */ ++ if (message.event == PM_EVENT_PRETHAW) ++ ohci_usb_reset(ohci); ++ ++ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); ++ ++ spin_unlock_irqrestore(&ohci->lock, flags); ++ return 0; ++} ++ ++static int ssb_ohci_hcd_resume(struct usb_hcd *hcd) ++{ ++ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); ++ usb_hcd_resume_root_hub(hcd); ++ return 0; ++} ++#endif /* CONFIG_PM */ ++ ++static const struct hc_driver ssb_ohci_hc_driver = { ++ .description = "ssb-usb-ohci", ++ .product_desc = "SSB OHCI Controller", ++ .hcd_priv_size = sizeof(struct ssb_ohci_device), ++ ++ .irq = ohci_irq, ++ .flags = HCD_MEMORY | HCD_USB11, ++ ++ .reset = ssb_ohci_reset, ++ .start = ssb_ohci_start, ++ .stop = ohci_stop, ++ .shutdown = ohci_shutdown, ++ ++#ifdef CONFIG_PM ++ .suspend = ssb_ohci_hcd_suspend, ++ .resume = ssb_ohci_hcd_resume, ++#endif ++ ++ .urb_enqueue = ohci_urb_enqueue, ++ .urb_dequeue = ohci_urb_dequeue, ++ .endpoint_disable = ohci_endpoint_disable, ++ ++ .get_frame_number = ohci_get_frame, ++ ++ .hub_status_data = ohci_hub_status_data, ++ .hub_control = ohci_hub_control, ++ .hub_irq_enable = ohci_rhsc_enable, ++ .bus_suspend = ohci_bus_suspend, ++ .bus_resume = ohci_bus_resume, ++ ++ .start_port_reset = ohci_start_port_reset, ++}; ++ ++static void ssb_ohci_detach(struct ssb_device *dev) ++{ ++ struct usb_hcd *hcd = ssb_get_drvdata(dev); ++ ++ usb_remove_hcd(hcd); ++ iounmap(hcd->regs); ++ usb_put_hcd(hcd); ++ ssb_device_disable(dev, 0); ++} ++ ++static int ssb_ohci_attach(struct ssb_device *dev) ++{ ++ struct ssb_ohci_device *ohcidev; ++ struct usb_hcd *hcd; ++ int err = -ENOMEM; ++ u32 tmp, flags = 0; ++ ++ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) ++ flags |= SSB_OHCI_TMSLOW_HOSTMODE; ++ ++ ssb_device_enable(dev, flags); ++ ++ hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev, ++ dev->dev->bus_id); ++ if (!hcd) ++ goto err_dev_disable; ++ ohcidev = hcd_to_ssb_ohci(hcd); ++ ohcidev->enable_flags = flags; ++ ++ tmp = ssb_read32(dev, SSB_ADMATCH0); ++ hcd->rsrc_start = ssb_admatch_base(tmp); ++ hcd->rsrc_len = ssb_admatch_size(tmp); ++ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); ++ if (!hcd->regs) ++ goto err_put_hcd; ++ err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED); ++ if (err) ++ goto err_iounmap; ++ ++ ssb_set_drvdata(dev, hcd); ++ ++ return err; ++ ++err_iounmap: ++ iounmap(hcd->regs); ++err_put_hcd: ++ usb_put_hcd(hcd); ++err_dev_disable: ++ ssb_device_disable(dev, flags); ++ return err; ++} ++ ++static int ssb_ohci_probe(struct ssb_device *dev, ++ const struct ssb_device_id *id) ++{ ++ int err; ++ u16 chipid_top; ++ ++ /* USBcores are only connected on embedded devices. */ ++ chipid_top = (dev->bus->chip_id & 0xFF00); ++ if (chipid_top != 0x4700 && chipid_top != 0x5300) ++ return -ENODEV; ++ ++ /* TODO: Probably need checks here; is the core connected? */ ++ ++ if (usb_disabled()) ++ return -ENODEV; ++ ++ /* We currently always attach SSB_DEV_USB11_HOSTDEV ++ * as HOST OHCI. If we want to attach it as Client device, ++ * we must branch here and call into the (yet to ++ * be written) Client mode driver. Same for remove(). */ ++ ++ err = ssb_ohci_attach(dev); ++ ++ return err; ++} ++ ++static void ssb_ohci_remove(struct ssb_device *dev) ++{ ++ ssb_ohci_detach(dev); ++} ++ ++#ifdef CONFIG_PM ++ ++static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state) ++{ ++ ssb_device_disable(dev, 0); ++ ++ return 0; ++} ++ ++static int ssb_ohci_resume(struct ssb_device *dev) ++{ ++ struct usb_hcd *hcd = ssb_get_drvdata(dev); ++ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); ++ ++ ssb_device_enable(dev, ohcidev->enable_flags); ++ ++ return 0; ++} ++ ++#else /* !CONFIG_PM */ ++#define ssb_ohci_suspend NULL ++#define ssb_ohci_resume NULL ++#endif /* CONFIG_PM */ ++ ++static const struct ssb_device_id ssb_ohci_table[] = { ++ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), ++ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), ++ SSB_DEVTABLE_END ++}; ++MODULE_DEVICE_TABLE(ssb, ssb_ohci_table); ++ ++static struct ssb_driver ssb_ohci_driver = { ++ .name = KBUILD_MODNAME, ++ .id_table = ssb_ohci_table, ++ .probe = ssb_ohci_probe, ++ .remove = ssb_ohci_remove, ++ .suspend = ssb_ohci_suspend, ++ .resume = ssb_ohci_resume, ++}; diff --git a/target/linux/brcm47xx/patches-2.6.25/240-ohci-ssb-pm.patch b/target/linux/brcm47xx/patches-2.6.25/240-ohci-ssb-pm.patch new file mode 100644 index 0000000000..81ba45bee8 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/240-ohci-ssb-pm.patch @@ -0,0 +1,30 @@ +From: Al Viro <viro@ftp.linux.org.uk> +Date: Sat, 13 Oct 2007 21:29:47 +0000 (+0100) +Subject: Fix ohci-ssb with !CONFIG_PM +X-Git-Tag: linux-2.6.24-rc1~57^2~38 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fralf%2Flinux.git;a=commitdiff_plain;h=4735b37cf434175c2b7b36b3b68f1e60e8ec8527;hp=d773b33972a663cfaf066e966f87922a74088a1e + +Fix ohci-ssb with !CONFIG_PM + +ohci_bus_{suspend,resume} exists only if we have CONFIG_PM; do the same +thing as other subdrivers... + +Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c +index bc3e785..fe70e72 100644 +--- a/drivers/usb/host/ohci-ssb.c ++++ b/drivers/usb/host/ohci-ssb.c +@@ -117,8 +117,10 @@ static const struct hc_driver ssb_ohci_hc_driver = { + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, ++#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, ++#endif + + .start_port_reset = ohci_start_port_reset, + }; diff --git a/target/linux/brcm47xx/patches-2.6.25/250-ohci-ssb-usb2.patch b/target/linux/brcm47xx/patches-2.6.25/250-ohci-ssb-usb2.patch new file mode 100644 index 0000000000..45493958b2 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/250-ohci-ssb-usb2.patch @@ -0,0 +1,72 @@ +--- a/drivers/usb/host/ohci-ssb.c 2007-11-05 07:56:56.000000000 -0800 ++++ b/drivers/usb/host/ohci-ssb.c 2007-11-05 08:26:15.000000000 -0800 +@@ -142,10 +142,59 @@ + int err = -ENOMEM; + u32 tmp, flags = 0; + +- if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) ++ /* ++ * THE FOLLOWING COMMENTS PRESERVED FROM GPL SOURCE RELEASE ++ * ++ * 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 (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) { + flags |= SSB_OHCI_TMSLOW_HOSTMODE; ++ ssb_device_enable(dev, flags); ++ } ++ ++ /* ++ * USB 2.0 special considerations: ++ * ++ * 1. Since the core supports both OHCI and EHCI functions, it must ++ * only be reset once. ++ * ++ * 2. In addition to the standard SB reset sequence, the Host Control ++ * Register must be programmed to bring the USB core and various ++ * phy components out of reset. ++ */ ++ ++ else if (dev->id.coreid == SSB_DEV_USB20_HOST) { ++#warning FIX ME need test for core being up & exit ++ ssb_device_enable(dev, 0); ++ ssb_write32(dev, 0x200, 0x7ff); ++ udelay(1); ++ if (dev->id.revision == 1) { // bug in rev 1 ++ ++ /* Change Flush control reg */ ++ tmp = ssb_read32(dev, 0x400); ++ tmp &= ~8; ++ ssb_write32(dev, 0x400, tmp); ++ tmp = ssb_read32(dev, 0x400); ++ printk("USB20H fcr: 0x%0x\n", tmp); ++ ++ /* Change Shim control reg */ ++ tmp = ssb_read32(dev, 0x304); ++ tmp &= ~0x100; ++ ssb_write32(dev, 0x304, tmp); ++ tmp = ssb_read32(dev, 0x304); ++ printk("USB20H shim: 0x%0x\n", tmp); ++ } ++ } ++ else ++ ssb_device_enable(dev, 0); + +- ssb_device_enable(dev, flags); + + hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev, + dev->dev->bus_id); +@@ -235,6 +284,7 @@ + static const struct ssb_device_id ssb_ohci_table[] = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), ++ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV), + SSB_DEVTABLE_END + }; + MODULE_DEVICE_TABLE(ssb, ssb_ohci_table); diff --git a/target/linux/brcm47xx/patches-2.6.25/260-ohci-set-dma-mask.patch b/target/linux/brcm47xx/patches-2.6.25/260-ohci-set-dma-mask.patch new file mode 100644 index 0000000000..5c2d5223e9 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/260-ohci-set-dma-mask.patch @@ -0,0 +1,14 @@ +--- linux-2.6.23.1/drivers/usb/host/ohci-ssb.c 2007-11-26 14:01:22.000000000 -0500 ++++ linux-2.6.23.1.new/drivers/usb/host/ohci-ssb.c 2007-11-26 14:16:08.000000000 -0500 +@@ -195,6 +195,11 @@ + else + ssb_device_enable(dev, 0); + ++ /* ++ * Set dma mask - 32 bit mask is just an assumption ++ */ ++ if (ssb_dma_set_mask(dev, DMA_32BIT_MASK)) ++ return -EOPNOTSUPP; + + hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev, + dev->dev->bus_id); diff --git a/target/linux/brcm47xx/patches-2.6.25/300-fork_cacheflush.patch b/target/linux/brcm47xx/patches-2.6.25/300-fork_cacheflush.patch new file mode 100644 index 0000000000..1620bf48ad --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/300-fork_cacheflush.patch @@ -0,0 +1,13 @@ +Index: linux-2.6.23/include/asm-mips/cacheflush.h +=================================================================== +--- linux-2.6.23.orig/include/asm-mips/cacheflush.h 2007-10-13 11:01:52.780284289 +0200 ++++ linux-2.6.23/include/asm-mips/cacheflush.h 2007-10-13 11:02:16.289624011 +0200 +@@ -32,7 +32,7 @@ + extern void (*flush_cache_all)(void); + extern void (*__flush_cache_all)(void); + extern void (*flush_cache_mm)(struct mm_struct *mm); +-#define flush_cache_dup_mm(mm) do { (void) (mm); } while (0) ++#define flush_cache_dup_mm(mm) flush_cache_mm(mm) + extern void (*flush_cache_range)(struct vm_area_struct *vma, + unsigned long start, unsigned long end); + extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn); diff --git a/target/linux/brcm47xx/patches-2.6.25/310-no_highpage.patch b/target/linux/brcm47xx/patches-2.6.25/310-no_highpage.patch new file mode 100644 index 0000000000..16e7e3f36c --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/310-no_highpage.patch @@ -0,0 +1,71 @@ +Index: linux-2.6.23/arch/mips/mm/init.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/mm/init.c 2007-10-13 11:46:58.762489429 +0200 ++++ linux-2.6.23/arch/mips/mm/init.c 2007-10-13 11:47:36.092616749 +0200 +@@ -205,31 +205,6 @@ + preempt_check_resched(); + } + +-void copy_user_highpage(struct page *to, struct page *from, +- unsigned long vaddr, struct vm_area_struct *vma) +-{ +- void *vfrom, *vto; +- +- vto = kmap_atomic(to, KM_USER1); +- if (cpu_has_dc_aliases && cpu_use_kmap_coherent && !Page_dcache_dirty(from)) { +- vfrom = kmap_coherent(from, vaddr); +- copy_page(vto, vfrom); +- kunmap_coherent(); +- } else { +- vfrom = kmap_atomic(from, KM_USER0); +- copy_page(vto, vfrom); +- kunmap_atomic(vfrom, KM_USER0); +- } +- if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) || +- pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) +- flush_data_cache_page((unsigned long)vto); +- kunmap_atomic(vto, KM_USER1); +- /* Make sure this page is cleared on other CPU's too before using it */ +- smp_wmb(); +-} +- +-EXPORT_SYMBOL(copy_user_highpage); +- + void copy_to_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, void *dst, const void *src, + unsigned long len) +Index: linux-2.6.23/include/asm-mips/page.h +=================================================================== +--- linux-2.6.23.orig/include/asm-mips/page.h 2007-10-13 11:45:50.518600430 +0200 ++++ linux-2.6.23/include/asm-mips/page.h 2007-10-13 11:47:26.472068504 +0200 +@@ -35,6 +35,7 @@ + #ifndef __ASSEMBLY__ + + #include <linux/pfn.h> ++#include <asm/cpu-features.h> + #include <asm/io.h> + + /* +@@ -67,13 +68,16 @@ + flush_data_cache_page((unsigned long)addr); + } + +-extern void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, +- struct page *to); +-struct vm_area_struct; +-extern void copy_user_highpage(struct page *to, struct page *from, +- unsigned long vaddr, struct vm_area_struct *vma); ++static inline void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, ++ struct page *to) ++{ ++ extern void (*flush_data_cache_page)(unsigned long addr); + +-#define __HAVE_ARCH_COPY_USER_HIGHPAGE ++ copy_page(vto, vfrom); ++ if (!cpu_has_ic_fills_f_dc || ++ pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) ++ flush_data_cache_page((unsigned long)vto); ++} + + /* + * These are used to make use of C type-checking.. diff --git a/target/linux/brcm47xx/patches-2.6.25/410-aec62xx_pci_enable.patch b/target/linux/brcm47xx/patches-2.6.25/410-aec62xx_pci_enable.patch new file mode 100644 index 0000000000..ae2be766f9 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/410-aec62xx_pci_enable.patch @@ -0,0 +1,32 @@ +diff -Naur a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c +--- a/drivers/ide/pci/aec62xx.c 2007-10-12 18:43:44.000000000 +0200 ++++ b/drivers/ide/pci/aec62xx.c 2007-11-14 14:12:51.000000000 +0100 +@@ -248,7 +248,14 @@ + + static int __devinit init_setup_aec6x80(struct pci_dev *dev, ide_pci_device_t *d) + { +- unsigned long dma_base = pci_resource_start(dev, 4); ++ unsigned long dma_base; ++ int err; ++ ++ err = pci_enable_device(dev); ++ if (err) ++ return err; ++ ++ dma_base = pci_resource_start(dev, 4); + + if (inb(dma_base + 2) & 0x10) { + d->name = (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R) ? +@@ -256,7 +263,11 @@ + d->udma_mask = 0x7f; /* udma0-6 */ + } + +- return ide_setup_pci_device(dev, d); ++ err = ide_setup_pci_device(dev, d); ++ if(err) ++ pci_disable_device(dev); ++ ++ return err; + } + + static ide_pci_device_t aec62xx_chipsets[] __devinitdata = { diff --git a/target/linux/brcm47xx/patches-2.6.25/500-lzma_initramfs.patch b/target/linux/brcm47xx/patches-2.6.25/500-lzma_initramfs.patch new file mode 100644 index 0000000000..b545bba264 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/500-lzma_initramfs.patch @@ -0,0 +1,121 @@ +Index: linux-2.6.23.1/scripts/gen_initramfs_list.sh +=================================================================== +--- linux-2.6.23.1.orig/scripts/gen_initramfs_list.sh 2007-11-16 02:26:47.821227881 +0100 ++++ linux-2.6.23.1/scripts/gen_initramfs_list.sh 2007-11-16 02:45:42.753904007 +0100 +@@ -287,7 +287,7 @@ + if [ "${is_cpio_compressed}" = "compressed" ]; then + cat ${cpio_tfile} > ${output_file} + else +- cat ${cpio_tfile} | gzip -f -9 - > ${output_file} ++ lzma e -lc1 -lp2 -pb2 ${cpio_tfile} ${output_file} + fi + [ -z ${cpio_file} ] && rm ${cpio_tfile} + fi +Index: linux-2.6.23.1/init/initramfs.c +=================================================================== +--- linux-2.6.23.1.orig/init/initramfs.c 2007-11-16 02:26:47.829228332 +0100 ++++ linux-2.6.23.1/init/initramfs.c 2007-11-16 03:03:09.661563882 +0100 +@@ -441,6 +441,69 @@ + outcnt = 0; + } + ++#include <linux/LzmaDecode.h> ++static int __init lzma_unzip(void) ++{ ++ unsigned int i; /* temp value */ ++ unsigned int lc; /* literal context bits */ ++ unsigned int lp; /* literal pos state bits */ ++ unsigned int pb; /* pos state bits */ ++ unsigned int osize; /* uncompressed size */ ++ unsigned char *workspace; ++ unsigned char* outputbuffer; ++ unsigned int outsizeProcessed = 0; ++ int workspace_size; ++ int res; ++ ++ // lzma args ++ i = get_byte(); ++ lc = i % 9, i = i / 9; ++ lp = i % 5, pb = i / 5; ++ ++ // skip dictionary size ++ for (i = 0; i < 4; i++) ++ get_byte(); ++ ++ /* read the lower half of uncompressed size in the header */ ++ osize = ((unsigned int)get_byte()) + ++ ((unsigned int)get_byte() << 8) + ++ ((unsigned int)get_byte() << 16) + ++ ((unsigned int)get_byte() << 24); ++ ++ /* skip rest of the header (upper half of uncompressed size) */ ++ for (i = 0; i < 4; i++) ++ get_byte(); ++ ++ workspace_size = ((LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp))) * sizeof(CProb)) + 100; ++ printk( KERN_NOTICE "initramfs: LZMA lc=%d,lp=%d,pb=%d,origSize=%d\n", ++ lc,lp,pb,osize); ++ outputbuffer = kmalloc(osize, GFP_KERNEL); ++ if (outputbuffer == 0) { ++ printk(KERN_ERR "initramfs: Couldn't allocate lzma output buffer\n"); ++ return -1; ++ } ++ ++ workspace = kmalloc(workspace_size, GFP_KERNEL); ++ if (workspace == NULL) { ++ printk(KERN_ERR "initramfs: Couldn't allocate lzma workspace\n"); ++ return -1; ++ } ++ ++ res = LzmaDecode(workspace, workspace_size, lc, lp, pb, inbuf + inptr, insize - inptr, outputbuffer, osize, &outsizeProcessed); ++ if( res != 0 ) { ++ panic( KERN_ERR "initramfs: Lzma decode failure\n"); ++ return -1; ++ } ++ ++ flush_buffer(outputbuffer, outsizeProcessed); ++ inptr = insize; ++ ++ kfree(outputbuffer); ++ kfree(workspace); ++ state = Reset; ++ return 0; ++} ++ + static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only) + { + int written; +@@ -475,12 +538,28 @@ + inptr = 0; + outcnt = 0; /* bytes in output buffer */ + bytes_out = 0; +- crc = (ulg)0xffffffffL; /* shift register contents */ +- makecrc(); +- gunzip(); +- if (state != Reset) ++ if( inbuf[0] == 037 && ((inbuf[1] == 0213) || (inbuf[1] == 0236))) ++ { ++ printk( KERN_NOTICE "detected gzip initramfs\n"); ++ crc = (ulg)0xffffffffL; /* shift register contents */ ++ makecrc(); ++ gunzip(); ++ if (state != Reset) + error("junk in gzipped archive"); +- this_header = saved_offset + inptr; ++ } ++ else if(!memcmp(inbuf+1, "\x00\x00\x80\x00", 4)) /* FIXME: hardcoded dictionary size */ ++ { ++ printk( KERN_NOTICE "detected lzma initramfs\n"); ++ lzma_unzip(); ++ } ++ else ++ { ++ // skip forward ? ++ crc = (ulg)0xffffffffL; /* shift register contents */ ++ makecrc(); ++ gunzip(); ++ } ++ this_header = saved_offset + inptr; + buf += inptr; + len -= inptr; + } diff --git a/target/linux/brcm47xx/patches-2.6.25/600-ssb-fix-pcidevices.patch b/target/linux/brcm47xx/patches-2.6.25/600-ssb-fix-pcidevices.patch new file mode 100644 index 0000000000..01bd9ffea2 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/600-ssb-fix-pcidevices.patch @@ -0,0 +1,65 @@ +Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/driver_pcicore.c 2008-02-16 17:55:20.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/driver_pcicore.c 2008-02-16 17:55:35.000000000 +0100 +@@ -66,6 +66,7 @@ int pcibios_plat_dev_init(struct pci_dev + base = &ssb_pcicore_pcibus_iobase; + else + base = &ssb_pcicore_pcibus_membase; ++ res->flags |= IORESOURCE_PCI_FIXED; + if (res->end) { + size = res->end - res->start + 1; + if (*base & (size - 1)) +@@ -88,10 +89,12 @@ int pcibios_plat_dev_init(struct pci_dev + + static void __init ssb_fixup_pcibridge(struct pci_dev *dev) + { ++ u8 lat; ++ + if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) + return; + +- ssb_printk(KERN_INFO "PCI: fixing up bridge\n"); ++ ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev)); + + /* Enable PCI bridge bus mastering and memory space */ + pci_set_master(dev); +@@ -101,7 +104,10 @@ static void __init ssb_fixup_pcibridge(s + pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); + + /* Make sure our latency is high enough to handle the devices behind us */ +- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8); ++ lat = 168; ++ ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n", ++ pci_name(dev), lat); ++ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); + } + DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); + +@@ -279,14 +285,14 @@ static struct resource ssb_pcicore_mem_r + .name = "SSB PCIcore external memory", + .start = SSB_PCI_DMA, + .end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1, +- .flags = IORESOURCE_MEM, ++ .flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED, + }; + + static struct resource ssb_pcicore_io_resource = { + .name = "SSB PCIcore external I/O", + .start = 0x100, + .end = 0x7FF, +- .flags = IORESOURCE_IO, ++ .flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED, + }; + + static struct pci_controller ssb_pcicore_controller = { +@@ -344,7 +350,8 @@ static void ssb_pcicore_init_hostmode(st + /* Ok, ready to run, register it to the system. + * The following needs change, if we want to port hostmode + * to non-MIPS platform. */ +- set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000)); ++ ssb_pcicore_controller.io_map_base = (unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000); ++ set_io_port_base(ssb_pcicore_controller.io_map_base); + /* Give some time to the PCI controller to configure itself with the new + * values. Not waiting at this point causes crashes of the machine. */ + mdelay(10); diff --git a/target/linux/brcm47xx/patches-2.6.25/601-mips-remove-pci-collision-check.patch b/target/linux/brcm47xx/patches-2.6.25/601-mips-remove-pci-collision-check.patch new file mode 100644 index 0000000000..8ab28a75e2 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/601-mips-remove-pci-collision-check.patch @@ -0,0 +1,21 @@ +The SSB pcicore driver does create some MMIO resource collisions. +However, the pcicore PCI-fixup routine fixes these collisions afterwards. +Remove this sanity check for now until we find a better solution. +--mb +Index: linux-2.6.23.16/arch/mips/pci/pci.c +=================================================================== +--- linux-2.6.23.16.orig/arch/mips/pci/pci.c 2008-02-16 17:55:20.000000000 +0100 ++++ linux-2.6.23.16/arch/mips/pci/pci.c 2008-02-16 17:57:39.000000000 +0100 +@@ -177,10 +177,8 @@ static int pcibios_enable_resources(stru + continue; + + r = &dev->resource[idx]; +- if (!r->start && r->end) { +- printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev)); +- return -EINVAL; +- } ++ if (!r->start && r->end) ++ printk(KERN_WARNING "PCI: Device %s resource collisions detected. Ignoring...\n", pci_name(dev)); + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) diff --git a/target/linux/brcm47xx/patches-2.6.25/602-ssb-fix-serial-on-new-devices.patch b/target/linux/brcm47xx/patches-2.6.25/602-ssb-fix-serial-on-new-devices.patch new file mode 100644 index 0000000000..d80b86e78a --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/602-ssb-fix-serial-on-new-devices.patch @@ -0,0 +1,90 @@ +Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/driver_chipcommon.c 2008-02-19 14:37:26.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/driver_chipcommon.c 2008-02-19 14:37:27.000000000 +0100 +@@ -403,6 +403,7 @@ int ssb_chipco_serial_init(struct ssb_ch + unsigned int irq; + u32 baud_base, div; + u32 i, n; ++ unsigned int ccrev = cc->dev->id.revision; + + plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); + irq = ssb_mips_irq(cc->dev); +@@ -414,14 +415,39 @@ int ssb_chipco_serial_init(struct ssb_ch + chipco_read32(cc, SSB_CHIPCO_CLOCK_M2)); + div = 1; + } else { +- if (cc->dev->id.revision >= 11) { ++ if (ccrev == 20) { ++ /* BCM5354 uses constant 25MHz clock */ ++ baud_base = 25000000; ++ div = 48; ++ /* Set the override bit so we don't divide it */ ++ chipco_write32(cc, SSB_CHIPCO_CORECTL, ++ chipco_read32(cc, SSB_CHIPCO_CORECTL) ++ | SSB_CHIPCO_CORECTL_UARTCLK0); ++ } else if ((ccrev >= 11) && (ccrev != 15)) { + /* Fixed ALP clock */ + baud_base = 20000000; ++ if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { ++ /* FIXME: baud_base is different for devices with a PMU */ ++ SSB_WARN_ON(1); ++ } + div = 1; ++ if (ccrev >= 21) { ++ /* Turn off UART clock before switching clocksource. */ ++ chipco_write32(cc, SSB_CHIPCO_CORECTL, ++ chipco_read32(cc, SSB_CHIPCO_CORECTL) ++ & ~SSB_CHIPCO_CORECTL_UARTCLKEN); ++ } + /* Set the override bit so we don't divide it */ + chipco_write32(cc, SSB_CHIPCO_CORECTL, +- SSB_CHIPCO_CORECTL_UARTCLK0); +- } else if (cc->dev->id.revision >= 3) { ++ chipco_read32(cc, SSB_CHIPCO_CORECTL) ++ | SSB_CHIPCO_CORECTL_UARTCLK0); ++ if (ccrev >= 21) { ++ /* Re-enable the UART clock. */ ++ chipco_write32(cc, SSB_CHIPCO_CORECTL, ++ chipco_read32(cc, SSB_CHIPCO_CORECTL) ++ | SSB_CHIPCO_CORECTL_UARTCLKEN); ++ } ++ } else if (ccrev >= 3) { + /* Internal backplane clock */ + baud_base = ssb_clockspeed(bus); + div = chipco_read32(cc, SSB_CHIPCO_CLKDIV) +@@ -433,7 +459,7 @@ int ssb_chipco_serial_init(struct ssb_ch + } + + /* Clock source depends on strapping if UartClkOverride is unset */ +- if ((cc->dev->id.revision > 0) && ++ if ((ccrev > 0) && + !(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) { + if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) == + SSB_CHIPCO_CAP_UARTCLK_INT) { +@@ -455,7 +481,7 @@ int ssb_chipco_serial_init(struct ssb_ch + cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE); + uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA; + /* Offset changed at after rev 0 */ +- if (cc->dev->id.revision == 0) ++ if (ccrev == 0) + uart_regs += (i * 8); + else + uart_regs += (i * 256); +Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h +=================================================================== +--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_chipcommon.h 2008-02-19 14:37:26.000000000 +0100 ++++ linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h 2008-02-19 14:37:27.000000000 +0100 +@@ -51,9 +51,12 @@ + #define SSB_CHIPCO_CAP_JTAGM 0x00400000 /* JTAG master present */ + #define SSB_CHIPCO_CAP_BROM 0x00800000 /* Internal boot ROM active */ + #define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */ ++#define SSB_CHIPCO_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */ ++#define SSB_CHIPCO_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */ + #define SSB_CHIPCO_CORECTL 0x0008 + #define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */ + #define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ ++#define SSB_CHIPCO_CORECTL_UARTCLKEN 0x00000008 /* UART clock enable (rev >= 21) */ + #define SSB_CHIPCO_BIST 0x000C + #define SSB_CHIPCO_OTPS 0x0010 /* OTP status */ + #define SSB_CHIPCO_OTPS_PROGFAIL 0x80000000 diff --git a/target/linux/brcm47xx/patches-2.6.25/610-ssb-watchdog-fix.patch b/target/linux/brcm47xx/patches-2.6.25/610-ssb-watchdog-fix.patch new file mode 100644 index 0000000000..fecb8b50d0 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/610-ssb-watchdog-fix.patch @@ -0,0 +1,133 @@ +Index: linux-2.6.23.16/drivers/ssb/Kconfig +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/Kconfig 2008-02-19 13:46:05.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/Kconfig 2008-02-19 13:46:33.000000000 +0100 +@@ -105,6 +105,12 @@ config SSB_DRIVER_MIPS + + If unsure, say N + ++# Assumption: We are on embedded, if we compile the MIPS core. ++config SSB_EMBEDDED ++ bool ++ depends on SSB_DRIVER_MIPS ++ default y ++ + config SSB_DRIVER_EXTIF + bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)" + depends on SSB_DRIVER_MIPS && EXPERIMENTAL +Index: linux-2.6.23.16/drivers/ssb/Makefile +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/Makefile 2008-02-19 13:46:05.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/Makefile 2008-02-19 13:46:33.000000000 +0100 +@@ -1,5 +1,6 @@ + # core + ssb-y += main.o scan.o ++ssb-$(CONFIG_SSB_EMBEDDED) += embedded.o + + # host support + ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o +Index: linux-2.6.23.16/drivers/ssb/driver_extif.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/driver_extif.c 2008-02-19 13:46:05.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/driver_extif.c 2008-02-19 13:46:33.000000000 +0100 +@@ -37,6 +37,12 @@ static inline u32 extif_write32_masked(s + return value; + } + ++void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, ++ u32 ticks) ++{ ++ extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks); ++} ++ + #ifdef CONFIG_SSB_SERIAL + static bool serial_exists(u8 *regs) + { +Index: linux-2.6.23.16/drivers/ssb/embedded.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.23.16/drivers/ssb/embedded.c 2008-02-19 13:46:33.000000000 +0100 +@@ -0,0 +1,26 @@ ++/* ++ * Sonics Silicon Backplane ++ * Embedded systems support code ++ * ++ * Copyright 2005-2008, Broadcom Corporation ++ * Copyright 2006-2008, Michael Buesch <mb@bu3sch.de> ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include <linux/ssb/ssb.h> ++#include <linux/ssb/ssb_embedded.h> ++ ++ ++int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks) ++{ ++ if (ssb_chipco_available(&bus->chipco)) { ++ ssb_chipco_watchdog_timer_set(&bus->chipco, ticks); ++ return 0; ++ } ++ if (ssb_extif_available(&bus->extif)) { ++ ssb_extif_watchdog_timer_set(&bus->extif, ticks); ++ return 0; ++ } ++ return -ENODEV; ++} +Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h +=================================================================== +--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_chipcommon.h 2008-02-19 13:46:29.000000000 +0100 ++++ linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h 2008-02-19 13:46:33.000000000 +0100 +@@ -360,6 +360,11 @@ struct ssb_chipcommon { + u16 fast_pwrup_delay; + }; + ++static inline bool ssb_chipco_available(struct ssb_chipcommon *cc) ++{ ++ return (cc->dev != NULL); ++} ++ + extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); + + #include <linux/pm.h> +Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_extif.h +=================================================================== +--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_extif.h 2008-02-19 13:46:05.000000000 +0100 ++++ linux-2.6.23.16/include/linux/ssb/ssb_driver_extif.h 2008-02-19 13:46:33.000000000 +0100 +@@ -178,6 +178,9 @@ u32 ssb_extif_gpio_outen(struct ssb_exti + u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value); + u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value); + ++extern void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, ++ u32 ticks); ++ + #ifdef CONFIG_SSB_SERIAL + extern int ssb_extif_serial_init(struct ssb_extif *extif, + struct ssb_serial_port *ports); +@@ -201,5 +204,11 @@ void ssb_extif_get_clockcontrol(struct s + { + } + ++static inline ++void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, ++ u32 ticks) ++{ ++} ++ + #endif /* CONFIG_SSB_DRIVER_EXTIF */ + #endif /* LINUX_SSB_EXTIFCORE_H_ */ +Index: linux-2.6.23.16/include/linux/ssb/ssb_embedded.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.23.16/include/linux/ssb/ssb_embedded.h 2008-02-19 13:46:33.000000000 +0100 +@@ -0,0 +1,10 @@ ++#ifndef LINUX_SSB_EMBEDDED_H_ ++#define LINUX_SSB_EMBEDDED_H_ ++ ++#include <linux/types.h> ++#include <linux/ssb/ssb.h> ++ ++ ++extern int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks); ++ ++#endif /* LINUX_SSB_EMBEDDED_H_ */ diff --git a/target/linux/brcm47xx/patches-2.6.25/620-ssb-modinit-fix.patch b/target/linux/brcm47xx/patches-2.6.25/620-ssb-modinit-fix.patch new file mode 100644 index 0000000000..a36c046018 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/620-ssb-modinit-fix.patch @@ -0,0 +1,15 @@ +Index: linux-2.6.23.16/drivers/ssb/main.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-02-19 12:38:34.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-19 12:48:25.000000000 +0100 +@@ -1163,7 +1163,9 @@ static int __init ssb_modinit(void) + /* ssb must be initialized after PCI but before the ssb drivers. + * That means we must use some initcall between subsys_initcall + * and device_initcall. */ +-fs_initcall(ssb_modinit); ++//FIXME on embedded we need to be early to make sure we can register ++// a new PCI bus, if needed. ++subsys_initcall(ssb_modinit); + + static void __exit ssb_modexit(void) + { diff --git a/target/linux/brcm47xx/patches-2.6.25/621-ssb-common-gpio-api.patch b/target/linux/brcm47xx/patches-2.6.25/621-ssb-common-gpio-api.patch new file mode 100644 index 0000000000..d1debcfe3a --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/621-ssb-common-gpio-api.patch @@ -0,0 +1,245 @@ +Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/driver_chipcommon.c 2008-02-19 15:50:42.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/driver_chipcommon.c 2008-02-19 15:50:44.000000000 +0100 +@@ -361,37 +361,31 @@ u32 ssb_chipco_gpio_in(struct ssb_chipco + { + return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask; + } +-EXPORT_SYMBOL(ssb_chipco_gpio_in); + + u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) + { + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); + } +-EXPORT_SYMBOL(ssb_chipco_gpio_out); + + u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) + { + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); + } +-EXPORT_SYMBOL(ssb_chipco_gpio_outen); + + u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value) + { + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); + } +-EXPORT_SYMBOL(ssb_chipco_gpio_control); + + u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) + { + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); + } +-EXPORT_SYMBOL(ssb_chipco_gpio_intmask); + + u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value) + { + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); + } +-EXPORT_SYMBOL(ssb_chipco_gpio_polarity); + + #ifdef CONFIG_SSB_SERIAL + int ssb_chipco_serial_init(struct ssb_chipcommon *cc, +Index: linux-2.6.23.16/drivers/ssb/driver_extif.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/driver_extif.c 2008-02-19 15:50:42.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/driver_extif.c 2008-02-19 15:50:44.000000000 +0100 +@@ -122,30 +122,25 @@ u32 ssb_extif_gpio_in(struct ssb_extif * + { + return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; + } +-EXPORT_SYMBOL(ssb_extif_gpio_in); + + u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) + { + return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), + mask, value); + } +-EXPORT_SYMBOL(ssb_extif_gpio_out); + + u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) + { + return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), + mask, value); + } +-EXPORT_SYMBOL(ssb_extif_gpio_outen); + + u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value) + { + return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value); + } +-EXPORT_SYMBOL(ssb_extif_gpio_polarity); + + u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value) + { + return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value); + } +-EXPORT_SYMBOL(ssb_extif_gpio_intmask); +Index: linux-2.6.23.16/drivers/ssb/embedded.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/embedded.c 2008-02-19 15:50:42.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/embedded.c 2008-02-19 15:51:01.000000000 +0100 +@@ -11,6 +11,8 @@ + #include <linux/ssb/ssb.h> + #include <linux/ssb/ssb_embedded.h> + ++#include "ssb_private.h" ++ + + int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks) + { +@@ -24,3 +26,107 @@ int ssb_watchdog_timer_set(struct ssb_bu + } + return -ENODEV; + } ++ ++u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask) ++{ ++ unsigned long flags; ++ u32 res = 0; ++ ++ spin_lock_irqsave(&bus->gpio_lock, flags); ++ if (ssb_chipco_available(&bus->chipco)) ++ res = ssb_chipco_gpio_in(&bus->chipco, mask); ++ else if (ssb_extif_available(&bus->extif)) ++ res = ssb_extif_gpio_in(&bus->extif, mask); ++ else ++ SSB_WARN_ON(1); ++ spin_unlock_irqrestore(&bus->gpio_lock, flags); ++ ++ return res; ++} ++EXPORT_SYMBOL(ssb_gpio_in); ++ ++u32 ssb_gpio_out(struct ssb_bus *bus, u32 mask, u32 value) ++{ ++ unsigned long flags; ++ u32 res = 0; ++ ++ spin_lock_irqsave(&bus->gpio_lock, flags); ++ if (ssb_chipco_available(&bus->chipco)) ++ res = ssb_chipco_gpio_out(&bus->chipco, mask, value); ++ else if (ssb_extif_available(&bus->extif)) ++ res = ssb_extif_gpio_out(&bus->extif, mask, value); ++ else ++ SSB_WARN_ON(1); ++ spin_unlock_irqrestore(&bus->gpio_lock, flags); ++ ++ return res; ++} ++EXPORT_SYMBOL(ssb_gpio_out); ++ ++u32 ssb_gpio_outen(struct ssb_bus *bus, u32 mask, u32 value) ++{ ++ unsigned long flags; ++ u32 res = 0; ++ ++ spin_lock_irqsave(&bus->gpio_lock, flags); ++ if (ssb_chipco_available(&bus->chipco)) ++ res = ssb_chipco_gpio_outen(&bus->chipco, mask, value); ++ else if (ssb_extif_available(&bus->extif)) ++ res = ssb_extif_gpio_outen(&bus->extif, mask, value); ++ else ++ SSB_WARN_ON(1); ++ spin_unlock_irqrestore(&bus->gpio_lock, flags); ++ ++ return res; ++} ++EXPORT_SYMBOL(ssb_gpio_outen); ++ ++u32 ssb_gpio_control(struct ssb_bus *bus, u32 mask, u32 value) ++{ ++ unsigned long flags; ++ u32 res = 0; ++ ++ spin_lock_irqsave(&bus->gpio_lock, flags); ++ if (ssb_chipco_available(&bus->chipco)) ++ res = ssb_chipco_gpio_control(&bus->chipco, mask, value); ++ spin_unlock_irqrestore(&bus->gpio_lock, flags); ++ ++ return res; ++} ++EXPORT_SYMBOL(ssb_gpio_control); ++ ++u32 ssb_gpio_intmask(struct ssb_bus *bus, u32 mask, u32 value) ++{ ++ unsigned long flags; ++ u32 res = 0; ++ ++ spin_lock_irqsave(&bus->gpio_lock, flags); ++ if (ssb_chipco_available(&bus->chipco)) ++ res = ssb_chipco_gpio_intmask(&bus->chipco, mask, value); ++ else if (ssb_extif_available(&bus->extif)) ++ res = ssb_extif_gpio_intmask(&bus->extif, mask, value); ++ else ++ SSB_WARN_ON(1); ++ spin_unlock_irqrestore(&bus->gpio_lock, flags); ++ ++ return res; ++} ++EXPORT_SYMBOL(ssb_gpio_intmask); ++ ++u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value) ++{ ++ unsigned long flags; ++ u32 res = 0; ++ ++ spin_lock_irqsave(&bus->gpio_lock, flags); ++ if (ssb_chipco_available(&bus->chipco)) ++ res = ssb_chipco_gpio_polarity(&bus->chipco, mask, value); ++ else if (ssb_extif_available(&bus->extif)) ++ res = ssb_extif_gpio_polarity(&bus->extif, mask, value); ++ else ++ SSB_WARN_ON(1); ++ spin_unlock_irqrestore(&bus->gpio_lock, flags); ++ ++ return res; ++} ++EXPORT_SYMBOL(ssb_gpio_polarity); +Index: linux-2.6.23.16/include/linux/ssb/ssb.h +=================================================================== +--- linux-2.6.23.16.orig/include/linux/ssb/ssb.h 2008-02-19 15:50:42.000000000 +0100 ++++ linux-2.6.23.16/include/linux/ssb/ssb.h 2008-02-19 15:50:44.000000000 +0100 +@@ -283,6 +283,11 @@ struct ssb_bus { + /* Contents of the SPROM. */ + struct ssb_sprom sprom; + ++#ifdef CONFIG_SSB_EMBEDDED ++ /* Lock for GPIO register access. */ ++ spinlock_t gpio_lock; ++#endif /* EMBEDDED */ ++ + /* Internal-only stuff follows. Do not touch. */ + struct list_head list; + #ifdef CONFIG_SSB_DEBUG +Index: linux-2.6.23.16/include/linux/ssb/ssb_embedded.h +=================================================================== +--- linux-2.6.23.16.orig/include/linux/ssb/ssb_embedded.h 2008-02-19 15:50:42.000000000 +0100 ++++ linux-2.6.23.16/include/linux/ssb/ssb_embedded.h 2008-02-19 15:50:44.000000000 +0100 +@@ -7,4 +7,12 @@ + + extern int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks); + ++/* Generic GPIO API */ ++u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask); ++u32 ssb_gpio_out(struct ssb_bus *bus, u32 mask, u32 value); ++u32 ssb_gpio_outen(struct ssb_bus *bus, u32 mask, u32 value); ++u32 ssb_gpio_control(struct ssb_bus *bus, u32 mask, u32 value); ++u32 ssb_gpio_intmask(struct ssb_bus *bus, u32 mask, u32 value); ++u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value); ++ + #endif /* LINUX_SSB_EMBEDDED_H_ */ +Index: linux-2.6.23.16/drivers/ssb/main.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-02-19 15:50:42.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-19 15:50:44.000000000 +0100 +@@ -571,6 +571,9 @@ static int ssb_bus_register(struct ssb_b + + spin_lock_init(&bus->bar_lock); + INIT_LIST_HEAD(&bus->list); ++#ifdef CONFIG_SSB_EMBEDDED ++ spin_lock_init(&bus->gpio_lock); ++#endif + + /* Powerup the bus */ + err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); diff --git a/target/linux/brcm47xx/patches-2.6.25/622-ssb-cardbus-fixes.patch b/target/linux/brcm47xx/patches-2.6.25/622-ssb-cardbus-fixes.patch new file mode 100644 index 0000000000..1d2779ed74 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/622-ssb-cardbus-fixes.patch @@ -0,0 +1,116 @@ +Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/driver_pcicore.c 2008-02-19 16:37:14.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/driver_pcicore.c 2008-02-19 17:25:26.000000000 +0100 +@@ -11,6 +11,7 @@ + #include <linux/ssb/ssb.h> + #include <linux/pci.h> + #include <linux/delay.h> ++#include <linux/ssb/ssb_embedded.h> + + #include "ssb_private.h" + +@@ -27,6 +28,18 @@ void pcicore_write32(struct ssb_pcicore + ssb_write32(pc->dev, offset, value); + } + ++static inline ++u16 pcicore_read16(struct ssb_pcicore *pc, u16 offset) ++{ ++ return ssb_read16(pc->dev, offset); ++} ++ ++static inline ++void pcicore_write16(struct ssb_pcicore *pc, u16 offset, u16 value) ++{ ++ ssb_write16(pc->dev, offset, value); ++} ++ + /************************************************** + * Code for hostmode operation. + **************************************************/ +@@ -123,8 +136,10 @@ static u32 get_cfgspace_addr(struct ssb_ + u32 addr = 0; + u32 tmp; + +- if (unlikely(pc->cardbusmode && dev > 1)) ++ /* We do only have one cardbus device behind the bridge. */ ++ if (pc->cardbusmode && (dev >= 1)) + goto out; ++ + if (bus == 0) { + /* Type 0 transaction */ + if (unlikely(dev >= SSB_PCI_SLOT_MAX)) +@@ -324,7 +339,16 @@ static void ssb_pcicore_init_hostmode(st + pcicore_write32(pc, SSB_PCICORE_ARBCTL, val); + udelay(1); /* Assertion time demanded by the PCI standard */ + +- /*TODO cardbus mode */ ++ if (pc->dev->bus->has_cardbus_slot) { ++ ssb_dprintk(KERN_INFO PFX "CardBus slot detected\n"); ++ pc->cardbusmode = 1; ++ /* GPIO 1 resets the bridge */ ++ ssb_gpio_out(pc->dev->bus, 1, 1); ++ ssb_gpio_outen(pc->dev->bus, 1, 1); ++ pcicore_write16(pc, SSB_PCICORE_SPROM(0), ++ pcicore_read16(pc, SSB_PCICORE_SPROM(0)) ++ | 0x0400); ++ } + + /* 64MB I/O window */ + pcicore_write32(pc, SSB_PCICORE_SBTOPCI0, +Index: linux-2.6.23.16/drivers/ssb/main.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-02-19 15:50:44.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-19 16:38:31.000000000 +0100 +@@ -559,6 +559,7 @@ static int ssb_fetch_invariants(struct s + goto out; + memcpy(&bus->boardinfo, &iv.boardinfo, sizeof(iv.boardinfo)); + memcpy(&bus->sprom, &iv.sprom, sizeof(iv.sprom)); ++ bus->has_cardbus_slot = iv.has_cardbus_slot; + out: + return err; + } +Index: linux-2.6.23.16/include/linux/ssb/ssb.h +=================================================================== +--- linux-2.6.23.16.orig/include/linux/ssb/ssb.h 2008-02-19 15:50:44.000000000 +0100 ++++ linux-2.6.23.16/include/linux/ssb/ssb.h 2008-02-19 16:38:31.000000000 +0100 +@@ -282,6 +282,8 @@ struct ssb_bus { + struct ssb_boardinfo boardinfo; + /* Contents of the SPROM. */ + struct ssb_sprom sprom; ++ /* If the board has a cardbus slot, this is set to true. */ ++ bool has_cardbus_slot; + + #ifdef CONFIG_SSB_EMBEDDED + /* Lock for GPIO register access. */ +@@ -299,8 +301,13 @@ struct ssb_bus { + + /* The initialization-invariants. */ + struct ssb_init_invariants { ++ /* Versioning information about the PCB. */ + struct ssb_boardinfo boardinfo; ++ /* The SPROM information. That's either stored in an ++ * EEPROM or NVRAM on the board. */ + struct ssb_sprom sprom; ++ /* If the board has a cardbus slot, this is set to true. */ ++ bool has_cardbus_slot; + }; + /* Type of function to fetch the invariants. */ + typedef int (*ssb_invariants_func_t)(struct ssb_bus *bus, +Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h +=================================================================== +--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_pci.h 2008-02-13 20:27:17.000000000 +0100 ++++ linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h 2008-02-19 17:31:47.000000000 +0100 +@@ -51,6 +51,11 @@ + #define SSB_PCICORE_SBTOPCI1_MASK 0xFC000000 + #define SSB_PCICORE_SBTOPCI2 0x0108 /* Backplane to PCI translation 2 (sbtopci2) */ + #define SSB_PCICORE_SBTOPCI2_MASK 0xC0000000 ++#define SSB_PCICORE_PCICFG0 0x0400 /* PCI config space 0 (rev >= 8) */ ++#define SSB_PCICORE_PCICFG1 0x0500 /* PCI config space 1 (rev >= 8) */ ++#define SSB_PCICORE_PCICFG2 0x0600 /* PCI config space 2 (rev >= 8) */ ++#define SSB_PCICORE_PCICFG3 0x0700 /* PCI config space 3 (rev >= 8) */ ++#define SSB_PCICORE_SPROM(wordoffset) (0x0800 + ((wordoffset) * 2)) /* SPROM shadow area (72 bytes) */ + + /* SBtoPCIx */ + #define SSB_PCICORE_SBTOPCI_MEM 0x00000000 diff --git a/target/linux/brcm47xx/patches-2.6.25/680-ssb-support-8bit-writes.patch b/target/linux/brcm47xx/patches-2.6.25/680-ssb-support-8bit-writes.patch new file mode 100644 index 0000000000..82b64a37b6 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/680-ssb-support-8bit-writes.patch @@ -0,0 +1,197 @@ +Add support for 8bit reads/writes to SSB. +Index: linux-2.6.23.16/drivers/ssb/main.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-02-20 14:10:07.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-20 18:34:48.000000000 +0100 +@@ -507,6 +507,14 @@ error: + return err; + } + ++static u8 ssb_ssb_read8(struct ssb_device *dev, u16 offset) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ return readb(bus->mmio + offset); ++} ++ + static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset) + { + struct ssb_bus *bus = dev->bus; +@@ -523,6 +531,14 @@ static u32 ssb_ssb_read32(struct ssb_dev + return readl(bus->mmio + offset); + } + ++static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ writeb(value, bus->mmio + offset); ++} ++ + static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value) + { + struct ssb_bus *bus = dev->bus; +@@ -541,8 +557,10 @@ static void ssb_ssb_write32(struct ssb_d + + /* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ + static const struct ssb_bus_ops ssb_ssb_ops = { ++ .read8 = ssb_ssb_read8, + .read16 = ssb_ssb_read16, + .read32 = ssb_ssb_read32, ++ .write8 = ssb_ssb_write8, + .write16 = ssb_ssb_write16, + .write32 = ssb_ssb_write32, + }; +Index: linux-2.6.23.16/drivers/ssb/pci.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/pci.c 2008-02-20 14:10:03.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/pci.c 2008-02-20 14:10:07.000000000 +0100 +@@ -572,6 +572,19 @@ static inline int ssb_pci_assert_buspowe + } + #endif /* DEBUG */ + ++static u8 ssb_pci_read8(struct ssb_device *dev, u16 offset) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ if (unlikely(ssb_pci_assert_buspower(bus))) ++ return 0xFF; ++ if (unlikely(bus->mapped_device != dev)) { ++ if (unlikely(ssb_pci_switch_core(bus, dev))) ++ return 0xFF; ++ } ++ return ioread8(bus->mmio + offset); ++} ++ + static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset) + { + struct ssb_bus *bus = dev->bus; +@@ -598,6 +611,19 @@ static u32 ssb_pci_read32(struct ssb_dev + return ioread32(bus->mmio + offset); + } + ++static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ if (unlikely(ssb_pci_assert_buspower(bus))) ++ return; ++ if (unlikely(bus->mapped_device != dev)) { ++ if (unlikely(ssb_pci_switch_core(bus, dev))) ++ return; ++ } ++ iowrite8(value, bus->mmio + offset); ++} ++ + static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value) + { + struct ssb_bus *bus = dev->bus; +@@ -626,8 +652,10 @@ static void ssb_pci_write32(struct ssb_d + + /* Not "static", as it's used in main.c */ + const struct ssb_bus_ops ssb_pci_ops = { ++ .read8 = ssb_pci_read8, + .read16 = ssb_pci_read16, + .read32 = ssb_pci_read32, ++ .write8 = ssb_pci_write8, + .write16 = ssb_pci_write16, + .write32 = ssb_pci_write32, + }; +Index: linux-2.6.23.16/drivers/ssb/pcmcia.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/pcmcia.c 2008-02-20 14:10:03.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/pcmcia.c 2008-02-20 14:10:07.000000000 +0100 +@@ -172,6 +172,22 @@ static int select_core_and_segment(struc + return 0; + } + ++static u8 ssb_pcmcia_read8(struct ssb_device *dev, u16 offset) ++{ ++ struct ssb_bus *bus = dev->bus; ++ unsigned long flags; ++ int err; ++ u8 value = 0xFF; ++ ++ spin_lock_irqsave(&bus->bar_lock, flags); ++ err = select_core_and_segment(dev, &offset); ++ if (likely(!err)) ++ value = readb(bus->mmio + offset); ++ spin_unlock_irqrestore(&bus->bar_lock, flags); ++ ++ return value; ++} ++ + static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset) + { + struct ssb_bus *bus = dev->bus; +@@ -206,6 +222,20 @@ static u32 ssb_pcmcia_read32(struct ssb_ + return (lo | (hi << 16)); + } + ++static void ssb_pcmcia_write8(struct ssb_device *dev, u16 offset, u8 value) ++{ ++ struct ssb_bus *bus = dev->bus; ++ unsigned long flags; ++ int err; ++ ++ spin_lock_irqsave(&bus->bar_lock, flags); ++ err = select_core_and_segment(dev, &offset); ++ if (likely(!err)) ++ writeb(value, bus->mmio + offset); ++ mmiowb(); ++ spin_unlock_irqrestore(&bus->bar_lock, flags); ++} ++ + static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value) + { + struct ssb_bus *bus = dev->bus; +@@ -238,8 +268,10 @@ static void ssb_pcmcia_write32(struct ss + + /* Not "static", as it's used in main.c */ + const struct ssb_bus_ops ssb_pcmcia_ops = { ++ .read8 = ssb_pcmcia_read8, + .read16 = ssb_pcmcia_read16, + .read32 = ssb_pcmcia_read32, ++ .write8 = ssb_pcmcia_write8, + .write16 = ssb_pcmcia_write16, + .write32 = ssb_pcmcia_write32, + }; +Index: linux-2.6.23.16/include/linux/ssb/ssb.h +=================================================================== +--- linux-2.6.23.16.orig/include/linux/ssb/ssb.h 2008-02-20 14:10:07.000000000 +0100 ++++ linux-2.6.23.16/include/linux/ssb/ssb.h 2008-02-20 18:33:21.000000000 +0100 +@@ -72,8 +72,10 @@ struct ssb_device; + /* Lowlevel read/write operations on the device MMIO. + * Internal, don't use that outside of ssb. */ + struct ssb_bus_ops { ++ u8 (*read8)(struct ssb_device *dev, u16 offset); + u16 (*read16)(struct ssb_device *dev, u16 offset); + u32 (*read32)(struct ssb_device *dev, u16 offset); ++ void (*write8)(struct ssb_device *dev, u16 offset, u8 value); + void (*write16)(struct ssb_device *dev, u16 offset, u16 value); + void (*write32)(struct ssb_device *dev, u16 offset, u32 value); + }; +@@ -344,6 +346,10 @@ void ssb_device_disable(struct ssb_devic + + + /* Device MMIO register read/write functions. */ ++static inline u8 ssb_read8(struct ssb_device *dev, u16 offset) ++{ ++ return dev->ops->read8(dev, offset); ++} + static inline u16 ssb_read16(struct ssb_device *dev, u16 offset) + { + return dev->ops->read16(dev, offset); +@@ -352,6 +358,10 @@ static inline u32 ssb_read32(struct ssb_ + { + return dev->ops->read32(dev, offset); + } ++static inline void ssb_write8(struct ssb_device *dev, u16 offset, u8 value) ++{ ++ dev->ops->write8(dev, offset, value); ++} + static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value) + { + dev->ops->write16(dev, offset, value); diff --git a/target/linux/brcm47xx/patches-2.6.25/690-mips-allow-pciregister-after-boot.patch b/target/linux/brcm47xx/patches-2.6.25/690-mips-allow-pciregister-after-boot.patch new file mode 100644 index 0000000000..132b41dc5d --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/690-mips-allow-pciregister-after-boot.patch @@ -0,0 +1,163 @@ +Allow registering PCI devices after early boot. + +This is an ugly hack and needs to be rewritten before going upstream. +Index: linux-2.6.23.16/arch/mips/pci/pci.c +=================================================================== +--- linux-2.6.23.16.orig/arch/mips/pci/pci.c 2008-02-20 16:06:36.000000000 +0100 ++++ linux-2.6.23.16/arch/mips/pci/pci.c 2008-02-20 16:09:33.000000000 +0100 +@@ -21,6 +21,17 @@ + */ + int pci_probe_only; + ++/* ++ * Indicate whether PCI-bios init was already done. ++ */ ++static int pcibios_init_done; ++ ++/* ++ * The currently used busnumber. ++ */ ++static int next_busno; ++static int need_domain_info; ++ + #define PCI_ASSIGN_ALL_BUSSES 1 + + unsigned int pci_probe = PCI_ASSIGN_ALL_BUSSES; +@@ -75,8 +86,32 @@ pcibios_align_resource(void *data, struc + res->start = start; + } + +-void __devinit register_pci_controller(struct pci_controller *hose) ++/* Most MIPS systems have straight-forward swizzling needs. */ ++ ++static inline u8 bridge_swizzle(u8 pin, u8 slot) ++{ ++ return (((pin - 1) + slot) % 4) + 1; ++} ++ ++static u8 common_swizzle(struct pci_dev *dev, u8 *pinp) + { ++ u8 pin = *pinp; ++ ++ while (dev->bus->parent) { ++ pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); ++ /* Move up the chain of bridges. */ ++ dev = dev->bus->self; ++ } ++ *pinp = pin; ++ ++ /* The slot is the slot of the last bridge. */ ++ return PCI_SLOT(dev->devfn); ++} ++ ++void register_pci_controller(struct pci_controller *hose) ++{ ++ struct pci_bus *bus; ++ + if (request_resource(&iomem_resource, hose->mem_resource) < 0) + goto out; + if (request_resource(&ioport_resource, hose->io_resource) < 0) { +@@ -84,9 +119,6 @@ void __devinit register_pci_controller(s + goto out; + } + +- *hose_tail = hose; +- hose_tail = &hose->next; +- + /* + * Do not panic here but later - this might hapen before console init. + */ +@@ -94,41 +126,47 @@ void __devinit register_pci_controller(s + printk(KERN_WARNING + "registering PCI controller with io_map_base unset\n"); + } +- return; + +-out: +- printk(KERN_WARNING +- "Skipping PCI bus scan due to resource conflict\n"); +-} ++ if (pcibios_init_done) { ++ //TODO + +-/* Most MIPS systems have straight-forward swizzling needs. */ ++ printk(KERN_INFO "Registering a PCI bus after boot\n"); + +-static inline u8 bridge_swizzle(u8 pin, u8 slot) +-{ +- return (((pin - 1) + slot) % 4) + 1; +-} ++ if (!hose->iommu) ++ PCI_DMA_BUS_IS_PHYS = 1; + +-static u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp) +-{ +- u8 pin = *pinp; ++ bus = pci_scan_bus(next_busno, hose->pci_ops, hose); ++ hose->bus = bus; ++ need_domain_info = need_domain_info || hose->index; ++ hose->need_domain_info = need_domain_info; ++ if (bus) { ++ next_busno = bus->subordinate + 1; ++ /* Don't allow 8-bit bus number overflow inside the hose - ++ reserve some space for bridges. */ ++ if (next_busno > 224) { ++ next_busno = 0; ++ need_domain_info = 1; ++ } ++ } ++ if (!pci_probe_only) ++ pci_assign_unassigned_resources(); ++ pci_fixup_irqs(common_swizzle, pcibios_map_irq); ++ } else { ++ *hose_tail = hose; ++ hose_tail = &hose->next; ++ } + +- while (dev->bus->parent) { +- pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); +- /* Move up the chain of bridges. */ +- dev = dev->bus->self; +- } +- *pinp = pin; ++ return; + +- /* The slot is the slot of the last bridge. */ +- return PCI_SLOT(dev->devfn); ++out: ++ printk(KERN_WARNING ++ "Skipping PCI bus scan due to resource conflict\n"); + } + + static int __init pcibios_init(void) + { + struct pci_controller *hose; + struct pci_bus *bus; +- int next_busno; +- int need_domain_info = 0; + + /* Scan all of the recorded PCI controllers. */ + for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { +@@ -157,6 +195,7 @@ static int __init pcibios_init(void) + if (!pci_probe_only) + pci_assign_unassigned_resources(); + pci_fixup_irqs(common_swizzle, pcibios_map_irq); ++ pcibios_init_done = 1; + + return 0; + } +Index: linux-2.6.23.16/drivers/ssb/main.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-02-20 16:06:36.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-20 18:33:21.000000000 +0100 +@@ -1185,9 +1185,7 @@ static int __init ssb_modinit(void) + /* ssb must be initialized after PCI but before the ssb drivers. + * That means we must use some initcall between subsys_initcall + * and device_initcall. */ +-//FIXME on embedded we need to be early to make sure we can register +-// a new PCI bus, if needed. +-subsys_initcall(ssb_modinit); ++fs_initcall(ssb_modinit); + + static void __exit ssb_modexit(void) + { diff --git a/target/linux/brcm47xx/patches-2.6.25/700-ssb-gigabit-ethernet-driver.patch b/target/linux/brcm47xx/patches-2.6.25/700-ssb-gigabit-ethernet-driver.patch new file mode 100644 index 0000000000..1b97d126c9 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.25/700-ssb-gigabit-ethernet-driver.patch @@ -0,0 +1,1252 @@ +Index: linux-2.6.23.16/drivers/ssb/Kconfig +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/Kconfig 2008-03-19 11:16:18.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/Kconfig 2008-03-19 11:16:18.000000000 +0100 +@@ -120,4 +120,13 @@ config SSB_DRIVER_EXTIF + + If unsure, say N + ++config SSB_DRIVER_GIGE ++ bool "SSB Broadcom Gigabit Ethernet driver" ++ depends on SSB_PCIHOST_POSSIBLE && SSB_EMBEDDED && MIPS ++ help ++ Driver for the Sonics Silicon Backplane attached ++ Broadcom Gigabit Ethernet. ++ ++ If unsure, say N ++ + endmenu +Index: linux-2.6.23.16/drivers/ssb/Makefile +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/Makefile 2008-03-19 11:16:18.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/Makefile 2008-03-19 11:16:18.000000000 +0100 +@@ -11,6 +11,7 @@ ssb-y += driver_chipcommon.o + ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o + ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o + ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o ++ssb-$(CONFIG_SSB_DRIVER_GIGE) += driver_gige.o + + # b43 pci-ssb-bridge driver + # Not strictly a part of SSB, but kept here for convenience +Index: linux-2.6.23.16/drivers/ssb/driver_gige.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.23.16/drivers/ssb/driver_gige.c 2008-03-19 11:16:18.000000000 +0100 +@@ -0,0 +1,294 @@ ++/* ++ * Sonics Silicon Backplane ++ * Broadcom Gigabit Ethernet core driver ++ * ++ * Copyright 2008, Broadcom Corporation ++ * Copyright 2008, Michael Buesch <mb@bu3sch.de> ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include <linux/ssb/ssb.h> ++#include <linux/ssb/ssb_driver_gige.h> ++#include <linux/pci.h> ++#include <linux/pci_regs.h> ++ ++ ++/* ++MODULE_DESCRIPTION("SSB Broadcom Gigabit Ethernet driver"); ++MODULE_AUTHOR("Michael Buesch"); ++MODULE_LICENSE("GPL"); ++*/ ++ ++static const struct ssb_device_id ssb_gige_tbl[] = { ++ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET_GBIT, SSB_ANY_REV), ++ SSB_DEVTABLE_END ++}; ++/* MODULE_DEVICE_TABLE(ssb, ssb_gige_tbl); */ ++ ++ ++static inline u8 gige_read8(struct ssb_gige *dev, u16 offset) ++{ ++ return ssb_read8(dev->dev, offset); ++} ++ ++static inline u16 gige_read16(struct ssb_gige *dev, u16 offset) ++{ ++ return ssb_read16(dev->dev, offset); ++} ++ ++static inline u32 gige_read32(struct ssb_gige *dev, u16 offset) ++{ ++ return ssb_read32(dev->dev, offset); ++} ++ ++static inline void gige_write8(struct ssb_gige *dev, ++ u16 offset, u8 value) ++{ ++ ssb_write8(dev->dev, offset, value); ++} ++ ++static inline void gige_write16(struct ssb_gige *dev, ++ u16 offset, u16 value) ++{ ++ ssb_write16(dev->dev, offset, value); ++} ++ ++static inline void gige_write32(struct ssb_gige *dev, ++ u16 offset, u32 value) ++{ ++ ssb_write32(dev->dev, offset, value); ++} ++ ++static inline ++u8 gige_pcicfg_read8(struct ssb_gige *dev, unsigned int offset) ++{ ++ BUG_ON(offset >= 256); ++ return gige_read8(dev, SSB_GIGE_PCICFG + offset); ++} ++ ++static inline ++u16 gige_pcicfg_read16(struct ssb_gige *dev, unsigned int offset) ++{ ++ BUG_ON(offset >= 256); ++ return gige_read16(dev, SSB_GIGE_PCICFG + offset); ++} ++ ++static inline ++u32 gige_pcicfg_read32(struct ssb_gige *dev, unsigned int offset) ++{ ++ BUG_ON(offset >= 256); ++ return gige_read32(dev, SSB_GIGE_PCICFG + offset); ++} ++ ++static inline ++void gige_pcicfg_write8(struct ssb_gige *dev, ++ unsigned int offset, u8 value) ++{ ++ BUG_ON(offset >= 256); ++ gige_write8(dev, SSB_GIGE_PCICFG + offset, value); ++} ++ ++static inline ++void gige_pcicfg_write16(struct ssb_gige *dev, ++ unsigned int offset, u16 value) ++{ ++ BUG_ON(offset >= 256); ++ gige_write16(dev, SSB_GIGE_PCICFG + offset, value); ++} ++ ++static inline ++void gige_pcicfg_write32(struct ssb_gige *dev, ++ unsigned int offset, u32 value) ++{ ++ BUG_ON(offset >= 256); ++ gige_write32(dev, SSB_GIGE_PCICFG + offset, value); ++} ++ ++static int ssb_gige_pci_read_config(struct pci_bus *bus, unsigned int devfn, ++ int reg, int size, u32 *val) ++{ ++ struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops); ++ unsigned long flags; ++ ++ if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ if (reg >= 256) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ switch (size) { ++ case 1: ++ *val = gige_pcicfg_read8(dev, reg); ++ break; ++ case 2: ++ *val = gige_pcicfg_read16(dev, reg); ++ break; ++ case 4: ++ *val = gige_pcicfg_read32(dev, reg); ++ break; ++ default: ++ WARN_ON(1); ++ } ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int ssb_gige_pci_write_config(struct pci_bus *bus, unsigned int devfn, ++ int reg, int size, u32 val) ++{ ++ struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops); ++ unsigned long flags; ++ ++ if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ if (reg >= 256) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ switch (size) { ++ case 1: ++ gige_pcicfg_write8(dev, reg, val); ++ break; ++ case 2: ++ gige_pcicfg_write16(dev, reg, val); ++ break; ++ case 4: ++ gige_pcicfg_write32(dev, reg, val); ++ break; ++ default: ++ WARN_ON(1); ++ } ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int ssb_gige_probe(struct ssb_device *sdev, const struct ssb_device_id *id) ++{ ++ struct ssb_gige *dev; ++ u32 base, tmslow, tmshigh; ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ dev->dev = sdev; ++ ++ spin_lock_init(&dev->lock); ++ dev->pci_controller.pci_ops = &dev->pci_ops; ++ dev->pci_controller.io_resource = &dev->io_resource; ++ dev->pci_controller.mem_resource = &dev->mem_resource; ++ dev->pci_controller.io_map_base = 0x800; ++ dev->pci_ops.read = ssb_gige_pci_read_config; ++ dev->pci_ops.write = ssb_gige_pci_write_config; ++ ++ dev->io_resource.name = SSB_GIGE_IO_RES_NAME; ++ dev->io_resource.start = 0x800; ++ dev->io_resource.end = 0x8FF; ++ dev->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED; ++ ++ if (!ssb_device_is_enabled(sdev)) ++ ssb_device_enable(sdev, 0); ++ ++ /* Setup BAR0. This is a 64k MMIO region. */ ++ base = ssb_admatch_base(ssb_read32(sdev, SSB_ADMATCH1)); ++ gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_0, base); ++ gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_1, 0); ++ ++ dev->mem_resource.name = SSB_GIGE_MEM_RES_NAME; ++ dev->mem_resource.start = base; ++ dev->mem_resource.end = base + 0x10000 - 1; ++ dev->mem_resource.flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED; ++ ++ /* Enable the memory region. */ ++ gige_pcicfg_write16(dev, PCI_COMMAND, ++ gige_pcicfg_read16(dev, PCI_COMMAND) ++ | PCI_COMMAND_MEMORY); ++ ++ /* Write flushing is controlled by the Flush Status Control register. ++ * We want to flush every register write with a timeout and we want ++ * to disable the IRQ mask while flushing to avoid concurrency. ++ * Note that automatic write flushing does _not_ work from ++ * an IRQ handler. The driver must flush manually by reading a register. ++ */ ++ gige_write32(dev, SSB_GIGE_SHIM_FLUSHSTAT, 0x00000068); ++ ++ /* Check if we have an RGMII or GMII PHY-bus. ++ * On RGMII do not bypass the DLLs */ ++ tmslow = ssb_read32(sdev, SSB_TMSLOW); ++ tmshigh = ssb_read32(sdev, SSB_TMSHIGH); ++ if (tmshigh & SSB_GIGE_TMSHIGH_RGMII) { ++ tmslow &= ~SSB_GIGE_TMSLOW_TXBYPASS; ++ tmslow &= ~SSB_GIGE_TMSLOW_RXBYPASS; ++ dev->has_rgmii = 1; ++ } else { ++ tmslow |= SSB_GIGE_TMSLOW_TXBYPASS; ++ tmslow |= SSB_GIGE_TMSLOW_RXBYPASS; ++ dev->has_rgmii = 0; ++ } ++ tmslow |= SSB_GIGE_TMSLOW_DLLEN; ++ ssb_write32(sdev, SSB_TMSLOW, tmslow); ++ ++ ssb_set_drvdata(sdev, dev); ++ register_pci_controller(&dev->pci_controller); ++ ++ return 0; ++} ++ ++bool pdev_is_ssb_gige_core(struct pci_dev *pdev) ++{ ++ if (!pdev->resource[0].name) ++ return 0; ++ return (strcmp(pdev->resource[0].name, SSB_GIGE_MEM_RES_NAME) == 0); ++} ++EXPORT_SYMBOL(pdev_is_ssb_gige_core); ++ ++int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, ++ struct pci_dev *pdev) ++{ ++ struct ssb_gige *dev = ssb_get_drvdata(sdev); ++ struct resource *res; ++ ++ if (pdev->bus->ops != &dev->pci_ops) { ++ /* The PCI device is not on this SSB GigE bridge device. */ ++ return -ENODEV; ++ } ++ ++ /* Fixup the PCI resources. */ ++ res = &(pdev->resource[0]); ++ res->flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED; ++ res->name = dev->mem_resource.name; ++ res->start = dev->mem_resource.start; ++ res->end = dev->mem_resource.end; ++ ++ /* Fixup interrupt lines. */ ++ pdev->irq = ssb_mips_irq(sdev) + 2; ++ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, pdev->irq); ++ ++ return 0; ++} ++ ++int ssb_gige_map_irq(struct ssb_device *sdev, ++ const struct pci_dev *pdev) ++{ ++ struct ssb_gige *dev = ssb_get_drvdata(sdev); ++ ++ if (pdev->bus->ops != &dev->pci_ops) { ++ /* The PCI device is not on this SSB GigE bridge device. */ ++ return -ENODEV; ++ } ++ ++ return ssb_mips_irq(sdev) + 2; ++} ++ ++static struct ssb_driver ssb_gige_driver = { ++ .name = "BCM-GigE", ++ .id_table = ssb_gige_tbl, ++ .probe = ssb_gige_probe, ++}; ++ ++int ssb_gige_init(void) ++{ ++ return ssb_driver_register(&ssb_gige_driver); ++} +Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_gige.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.23.16/include/linux/ssb/ssb_driver_gige.h 2008-03-19 11:16:18.000000000 +0100 +@@ -0,0 +1,174 @@ ++#ifndef LINUX_SSB_DRIVER_GIGE_H_ ++#define LINUX_SSB_DRIVER_GIGE_H_ ++ ++#include <linux/ssb/ssb.h> ++#include <linux/pci.h> ++#include <linux/spinlock.h> ++ ++ ++#ifdef CONFIG_SSB_DRIVER_GIGE ++ ++ ++#define SSB_GIGE_PCIIO 0x0000 /* PCI I/O Registers (1024 bytes) */ ++#define SSB_GIGE_RESERVED 0x0400 /* Reserved (1024 bytes) */ ++#define SSB_GIGE_PCICFG 0x0800 /* PCI config space (256 bytes) */ ++#define SSB_GIGE_SHIM_FLUSHSTAT 0x0C00 /* PCI to OCP: Flush status control (32bit) */ ++#define SSB_GIGE_SHIM_FLUSHRDA 0x0C04 /* PCI to OCP: Flush read address (32bit) */ ++#define SSB_GIGE_SHIM_FLUSHTO 0x0C08 /* PCI to OCP: Flush timeout counter (32bit) */ ++#define SSB_GIGE_SHIM_BARRIER 0x0C0C /* PCI to OCP: Barrier register (32bit) */ ++#define SSB_GIGE_SHIM_MAOCPSI 0x0C10 /* PCI to OCP: MaocpSI Control (32bit) */ ++#define SSB_GIGE_SHIM_SIOCPMA 0x0C14 /* PCI to OCP: SiocpMa Control (32bit) */ ++ ++/* TM Status High flags */ ++#define SSB_GIGE_TMSHIGH_RGMII 0x00010000 /* Have an RGMII PHY-bus */ ++/* TM Status Low flags */ ++#define SSB_GIGE_TMSLOW_TXBYPASS 0x00080000 /* TX bypass (no delay) */ ++#define SSB_GIGE_TMSLOW_RXBYPASS 0x00100000 /* RX bypass (no delay) */ ++#define SSB_GIGE_TMSLOW_DLLEN 0x01000000 /* Enable DLL controls */ ++ ++/* Boardflags (low) */ ++#define SSB_GIGE_BFL_ROBOSWITCH 0x0010 ++ ++ ++#define SSB_GIGE_MEM_RES_NAME "SSB Broadcom 47xx GigE memory" ++#define SSB_GIGE_IO_RES_NAME "SSB Broadcom 47xx GigE I/O" ++ ++struct ssb_gige { ++ struct ssb_device *dev; ++ ++ spinlock_t lock; ++ ++ /* True, if the device has an RGMII bus. ++ * False, if the device has a GMII bus. */ ++ bool has_rgmii; ++ ++ /* The PCI controller device. */ ++ struct pci_controller pci_controller; ++ struct pci_ops pci_ops; ++ struct resource mem_resource; ++ struct resource io_resource; ++}; ++ ++/* Check whether a PCI device is a SSB Gigabit Ethernet core. */ ++extern bool pdev_is_ssb_gige_core(struct pci_dev *pdev); ++ ++/* Convert a pci_dev pointer to a ssb_gige pointer. */ ++static inline struct ssb_gige * pdev_to_ssb_gige(struct pci_dev *pdev) ++{ ++ if (!pdev_is_ssb_gige_core(pdev)) ++ return NULL; ++ return container_of(pdev->bus->ops, struct ssb_gige, pci_ops); ++} ++ ++/* Returns whether the PHY is connected by an RGMII bus. */ ++static inline bool ssb_gige_is_rgmii(struct pci_dev *pdev) ++{ ++ struct ssb_gige *dev = pdev_to_ssb_gige(pdev); ++ return (dev ? dev->has_rgmii : 0); ++} ++ ++/* Returns whether we have a Roboswitch. */ ++static inline bool ssb_gige_have_roboswitch(struct pci_dev *pdev) ++{ ++ struct ssb_gige *dev = pdev_to_ssb_gige(pdev); ++ if (dev) ++ return !!(dev->dev->bus->sprom.boardflags_lo & ++ SSB_GIGE_BFL_ROBOSWITCH); ++ return 0; ++} ++ ++/* Returns whether we can only do one DMA at once. */ ++static inline bool ssb_gige_one_dma_at_once(struct pci_dev *pdev) ++{ ++ struct ssb_gige *dev = pdev_to_ssb_gige(pdev); ++ if (dev) ++ return ((dev->dev->bus->chip_id == 0x4785) && ++ (dev->dev->bus->chip_rev < 2)); ++ return 0; ++} ++ ++/* Returns whether we must flush posted writes. */ ++static inline bool ssb_gige_must_flush_posted_writes(struct pci_dev *pdev) ++{ ++ struct ssb_gige *dev = pdev_to_ssb_gige(pdev); ++ if (dev) ++ return (dev->dev->bus->chip_id == 0x4785); ++ return 0; ++} ++ ++extern char * nvram_get(const char *name); ++/* Get the device MAC address */ ++static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr) ++{ ++#ifdef CONFIG_BCM947XX ++ char *res = nvram_get("et0macaddr"); ++ if (res) ++ memcpy(macaddr, res, 6); ++#endif ++} ++ ++extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, ++ struct pci_dev *pdev); ++extern int ssb_gige_map_irq(struct ssb_device *sdev, ++ const struct pci_dev *pdev); ++ ++/* The GigE driver is not a standalone module, because we don't have support ++ * for unregistering the driver. So we could not unload the module anyway. */ ++extern int ssb_gige_init(void); ++static inline void ssb_gige_exit(void) ++{ ++ /* Currently we can not unregister the GigE driver, ++ * because we can not unregister the PCI bridge. */ ++ BUG(); ++} ++ ++ ++#else /* CONFIG_SSB_DRIVER_GIGE */ ++/* Gigabit Ethernet driver disabled */ ++ ++ ++static inline int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, ++ struct pci_dev *pdev) ++{ ++ return -ENOSYS; ++} ++static inline int ssb_gige_map_irq(struct ssb_device *sdev, ++ const struct pci_dev *pdev) ++{ ++ return -ENOSYS; ++} ++static inline int ssb_gige_init(void) ++{ ++ return 0; ++} ++static inline void ssb_gige_exit(void) ++{ ++} ++ ++static inline bool pdev_is_ssb_gige_core(struct pci_dev *pdev) ++{ ++ return 0; ++} ++static inline struct ssb_gige * pdev_to_ssb_gige(struct pci_dev *pdev) ++{ ++ return NULL; ++} ++static inline bool ssb_gige_is_rgmii(struct pci_dev *pdev) ++{ ++ return 0; ++} ++static inline bool ssb_gige_have_roboswitch(struct pci_dev *pdev) ++{ ++ return 0; ++} ++static inline bool ssb_gige_one_dma_at_once(struct pci_dev *pdev) ++{ ++ return 0; ++} ++static inline bool ssb_gige_must_flush_posted_writes(struct pci_dev *pdev) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_SSB_DRIVER_GIGE */ ++#endif /* LINUX_SSB_DRIVER_GIGE_H_ */ +Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/driver_pcicore.c 2008-03-19 11:16:18.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/driver_pcicore.c 2008-03-19 11:16:18.000000000 +0100 +@@ -60,74 +60,6 @@ static DEFINE_SPINLOCK(cfgspace_lock); + /* Core to access the external PCI config space. Can only have one. */ + static struct ssb_pcicore *extpci_core; + +-static u32 ssb_pcicore_pcibus_iobase = 0x100; +-static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA; +- +-int pcibios_plat_dev_init(struct pci_dev *d) +-{ +- struct resource *res; +- int pos, size; +- u32 *base; +- +- ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", +- pci_name(d)); +- +- /* Fix up resource bases */ +- for (pos = 0; pos < 6; pos++) { +- res = &d->resource[pos]; +- if (res->flags & IORESOURCE_IO) +- base = &ssb_pcicore_pcibus_iobase; +- else +- base = &ssb_pcicore_pcibus_membase; +- res->flags |= IORESOURCE_PCI_FIXED; +- 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 (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0) +- break; +- } +- /* Fix up interrupt lines */ +- d->irq = ssb_mips_irq(extpci_core->dev) + 2; +- pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); +- +- return 0; +-} +- +-static void __init ssb_fixup_pcibridge(struct pci_dev *dev) +-{ +- u8 lat; +- +- if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) +- return; +- +- ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev)); +- +- /* Enable PCI bridge bus mastering and memory space */ +- pci_set_master(dev); +- pcibios_enable_device(dev, ~0); +- +- /* Enable PCI bridge BAR1 prefetch and burst */ +- pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); +- +- /* Make sure our latency is high enough to handle the devices behind us */ +- lat = 168; +- ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n", +- pci_name(dev), lat); +- pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); +-} +-DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); +- +-int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +-{ +- return ssb_mips_irq(extpci_core->dev) + 2; +-} + + static u32 get_cfgspace_addr(struct ssb_pcicore *pc, + unsigned int bus, unsigned int dev, +@@ -317,6 +249,92 @@ static struct pci_controller ssb_pcicore + .mem_offset = 0x24000000, + }; + ++static u32 ssb_pcicore_pcibus_iobase = 0x100; ++static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA; ++ ++/* This function is called when doing a pci_enable_device(). ++ * We must first check if the device is a device on the PCI-core bridge. */ ++int ssb_pcicore_plat_dev_init(struct pci_dev *d) ++{ ++ struct resource *res; ++ int pos, size; ++ u32 *base; ++ ++ if (d->bus->ops != &ssb_pcicore_pciops) { ++ /* This is not a device on the PCI-core bridge. */ ++ return -ENODEV; ++ } ++ ++ ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", ++ pci_name(d)); ++ ++ /* Fix up resource bases */ ++ for (pos = 0; pos < 6; pos++) { ++ res = &d->resource[pos]; ++ if (res->flags & IORESOURCE_IO) ++ base = &ssb_pcicore_pcibus_iobase; ++ else ++ base = &ssb_pcicore_pcibus_membase; ++ res->flags |= IORESOURCE_PCI_FIXED; ++ 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 (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0) ++ break; ++ } ++ /* Fix up interrupt lines */ ++ d->irq = ssb_mips_irq(extpci_core->dev) + 2; ++ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); ++ ++ return 0; ++} ++ ++/* Early PCI fixup for a device on the PCI-core bridge. */ ++static void ssb_pcicore_fixup_pcibridge(struct pci_dev *dev) ++{ ++ u8 lat; ++ ++ if (dev->bus->ops != &ssb_pcicore_pciops) { ++ /* This is not a device on the PCI-core bridge. */ ++ return; ++ } ++ if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) ++ return; ++ ++ ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev)); ++ ++ /* Enable PCI bridge bus mastering and memory space */ ++ pci_set_master(dev); ++ pcibios_enable_device(dev, ~0); ++ ++ /* Enable PCI bridge BAR1 prefetch and burst */ ++ pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); ++ ++ /* Make sure our latency is high enough to handle the devices behind us */ ++ lat = 168; ++ ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n", ++ pci_name(dev), lat); ++ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); ++} ++DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_pcicore_fixup_pcibridge); ++ ++/* PCI device IRQ mapping. */ ++int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ if (dev->bus->ops != &ssb_pcicore_pciops) { ++ /* This is not a device on the PCI-core bridge. */ ++ return -ENODEV; ++ } ++ return ssb_mips_irq(extpci_core->dev) + 2; ++} ++ + static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) + { + u32 val; +Index: linux-2.6.23.16/drivers/ssb/embedded.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/embedded.c 2008-03-19 11:16:18.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/embedded.c 2008-03-19 11:16:18.000000000 +0100 +@@ -10,6 +10,9 @@ + + #include <linux/ssb/ssb.h> + #include <linux/ssb/ssb_embedded.h> ++#include <linux/ssb/ssb_driver_pci.h> ++#include <linux/ssb/ssb_driver_gige.h> ++#include <linux/pci.h> + + #include "ssb_private.h" + +@@ -130,3 +133,90 @@ u32 ssb_gpio_polarity(struct ssb_bus *bu + return res; + } + EXPORT_SYMBOL(ssb_gpio_polarity); ++ ++#ifdef CONFIG_SSB_DRIVER_GIGE ++static int gige_pci_init_callback(struct ssb_bus *bus, unsigned long data) ++{ ++ struct pci_dev *pdev = (struct pci_dev *)data; ++ struct ssb_device *dev; ++ unsigned int i; ++ int res; ++ ++ for (i = 0; i < bus->nr_devices; i++) { ++ dev = &(bus->devices[i]); ++ if (dev->id.coreid != SSB_DEV_ETHERNET_GBIT) ++ continue; ++ if (!dev->dev || ++ !dev->dev->driver || ++ !device_is_registered(dev->dev)) ++ continue; ++ res = ssb_gige_pcibios_plat_dev_init(dev, pdev); ++ if (res >= 0) ++ return res; ++ } ++ ++ return -ENODEV; ++} ++#endif /* CONFIG_SSB_DRIVER_GIGE */ ++ ++int ssb_pcibios_plat_dev_init(struct pci_dev *dev) ++{ ++ int err; ++ ++ err = ssb_pcicore_plat_dev_init(dev); ++ if (!err) ++ return 0; ++#ifdef CONFIG_SSB_DRIVER_GIGE ++ err = ssb_for_each_bus_call((unsigned long)dev, gige_pci_init_callback); ++ if (err >= 0) ++ return err; ++#endif ++ /* This is not a PCI device on any SSB device. */ ++ ++ return -ENODEV; ++} ++ ++#ifdef CONFIG_SSB_DRIVER_GIGE ++static int gige_map_irq_callback(struct ssb_bus *bus, unsigned long data) ++{ ++ const struct pci_dev *pdev = (const struct pci_dev *)data; ++ struct ssb_device *dev; ++ unsigned int i; ++ int res; ++ ++ for (i = 0; i < bus->nr_devices; i++) { ++ dev = &(bus->devices[i]); ++ if (dev->id.coreid != SSB_DEV_ETHERNET_GBIT) ++ continue; ++ if (!dev->dev || ++ !dev->dev->driver || ++ !device_is_registered(dev->dev)) ++ continue; ++ res = ssb_gige_map_irq(dev, pdev); ++ if (res >= 0) ++ return res; ++ } ++ ++ return -ENODEV; ++} ++#endif /* CONFIG_SSB_DRIVER_GIGE */ ++ ++int ssb_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ int res; ++ ++ /* Check if this PCI device is a device on a SSB bus or device ++ * and return the IRQ number for it. */ ++ ++ res = ssb_pcicore_pcibios_map_irq(dev, slot, pin); ++ if (res >= 0) ++ return res; ++#ifdef CONFIG_SSB_DRIVER_GIGE ++ res = ssb_for_each_bus_call((unsigned long)dev, gige_map_irq_callback); ++ if (res >= 0) ++ return res; ++#endif ++ /* This is not a PCI device on any SSB device. */ ++ ++ return -ENODEV; ++} +Index: linux-2.6.23.16/include/linux/ssb/ssb.h +=================================================================== +--- linux-2.6.23.16.orig/include/linux/ssb/ssb.h 2008-03-19 11:16:18.000000000 +0100 ++++ linux-2.6.23.16/include/linux/ssb/ssb.h 2008-03-19 11:16:18.000000000 +0100 +@@ -422,5 +422,12 @@ extern int ssb_bus_powerup(struct ssb_bu + extern u32 ssb_admatch_base(u32 adm); + extern u32 ssb_admatch_size(u32 adm); + ++/* PCI device mapping and fixup routines. ++ * Called from the architecture pcibios init code. ++ * These are only available on SSB_EMBEDDED configurations. */ ++#ifdef CONFIG_SSB_EMBEDDED ++int ssb_pcibios_plat_dev_init(struct pci_dev *dev); ++int ssb_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); ++#endif /* CONFIG_SSB_EMBEDDED */ + + #endif /* LINUX_SSB_H_ */ +Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h +=================================================================== +--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_pci.h 2008-03-19 11:16:18.000000000 +0100 ++++ linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h 2008-03-19 11:16:18.000000000 +0100 +@@ -1,6 +1,11 @@ + #ifndef LINUX_SSB_PCICORE_H_ + #define LINUX_SSB_PCICORE_H_ + ++#include <linux/types.h> ++ ++struct pci_dev; ++ ++ + #ifdef CONFIG_SSB_DRIVER_PCICORE + + /* PCI core registers. */ +@@ -88,6 +93,9 @@ extern void ssb_pcicore_init(struct ssb_ + extern int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, + struct ssb_device *dev); + ++int ssb_pcicore_plat_dev_init(struct pci_dev *d); ++int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); ++ + + #else /* CONFIG_SSB_DRIVER_PCICORE */ + +@@ -107,5 +115,16 @@ int ssb_pcicore_dev_irqvecs_enable(struc + return 0; + } + ++static inline ++int ssb_pcicore_plat_dev_init(struct pci_dev *d) ++{ ++ return -ENODEV; ++} ++static inline ++int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ return -ENODEV; ++} ++ + #endif /* CONFIG_SSB_DRIVER_PCICORE */ + #endif /* LINUX_SSB_PCICORE_H_ */ +Index: linux-2.6.23.16/drivers/ssb/main.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-03-19 11:16:18.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/main.c 2008-03-19 11:16:18.000000000 +0100 +@@ -14,6 +14,7 @@ + #include <linux/io.h> + #include <linux/ssb/ssb.h> + #include <linux/ssb/ssb_regs.h> ++#include <linux/ssb/ssb_driver_gige.h> + #include <linux/dma-mapping.h> + #include <linux/pci.h> + +@@ -68,6 +69,25 @@ found: + } + #endif /* CONFIG_SSB_PCIHOST */ + ++int ssb_for_each_bus_call(unsigned long data, ++ int (*func)(struct ssb_bus *bus, unsigned long data)) ++{ ++ struct ssb_bus *bus; ++ int res; ++ ++ ssb_buses_lock(); ++ list_for_each_entry(bus, &buses, list) { ++ res = func(bus, data); ++ if (res >= 0) { ++ ssb_buses_unlock(); ++ return res; ++ } ++ } ++ ssb_buses_unlock(); ++ ++ return -ENODEV; ++} ++ + static struct ssb_device *ssb_device_get(struct ssb_device *dev) + { + if (dev) +@@ -1175,7 +1195,14 @@ static int __init ssb_modinit(void) + err = b43_pci_ssb_bridge_init(); + if (err) { + ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge " +- "initialization failed"); ++ "initialization failed\n"); ++ /* don't fail SSB init because of this */ ++ err = 0; ++ } ++ err = ssb_gige_init(); ++ if (err) { ++ ssb_printk(KERN_ERR "SSB Broadcom Gigabit Ethernet " ++ "driver initialization failed\n"); + /* don't fail SSB init because of this */ + err = 0; + } +@@ -1189,6 +1216,7 @@ fs_initcall(ssb_modinit); + + static void __exit ssb_modexit(void) + { ++ ssb_gige_exit(); + b43_pci_ssb_bridge_exit(); + bus_unregister(&ssb_bustype); + } +Index: linux-2.6.23.16/drivers/ssb/ssb_private.h +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/ssb_private.h 2008-03-19 11:16:15.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/ssb_private.h 2008-03-19 11:16:18.000000000 +0100 +@@ -118,6 +118,8 @@ extern u32 ssb_calc_clock_rate(u32 pllty + extern int ssb_devices_freeze(struct ssb_bus *bus); + extern int ssb_devices_thaw(struct ssb_bus *bus); + extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); ++int ssb_for_each_bus_call(unsigned long data, ++ int (*func)(struct ssb_bus *bus, unsigned long data)); + + /* b43_pci_bridge.c */ + #ifdef CONFIG_SSB_PCIHOST +Index: linux-2.6.23.16/drivers/net/tg3.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/net/tg3.c 2008-03-19 11:16:15.000000000 +0100 ++++ linux-2.6.23.16/drivers/net/tg3.c 2008-03-19 11:16:18.000000000 +0100 +@@ -38,6 +38,7 @@ + #include <linux/workqueue.h> + #include <linux/prefetch.h> + #include <linux/dma-mapping.h> ++#include <linux/ssb/ssb_driver_gige.h> + + #include <net/checksum.h> + #include <net/ip.h> +@@ -410,8 +411,9 @@ static void _tw32_flush(struct tg3 *tp, + static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val) + { + tp->write32_mbox(tp, off, val); +- if (!(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) && +- !(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND)) ++ if ((tp->tg3_flags3 & TG3_FLG3_FLUSH_POSTED_WRITES) || ++ (!(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) && ++ !(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND))) + tp->read32_mbox(tp, off); + } + +@@ -623,7 +625,7 @@ static void tg3_switch_clocks(struct tg3 + + #define PHY_BUSY_LOOPS 5000 + +-static int tg3_readphy(struct tg3 *tp, int reg, u32 *val) ++static int __tg3_readphy(struct tg3 *tp, unsigned int phy_addr, int reg, u32 *val) + { + u32 frame_val; + unsigned int loops; +@@ -637,7 +639,7 @@ static int tg3_readphy(struct tg3 *tp, i + + *val = 0x0; + +- frame_val = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) & ++ frame_val = ((phy_addr << MI_COM_PHY_ADDR_SHIFT) & + MI_COM_PHY_ADDR_MASK); + frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) & + MI_COM_REG_ADDR_MASK); +@@ -672,7 +674,12 @@ static int tg3_readphy(struct tg3 *tp, i + return ret; + } + +-static int tg3_writephy(struct tg3 *tp, int reg, u32 val) ++static int tg3_readphy(struct tg3 *tp, int reg, u32 *val) ++{ ++ return __tg3_readphy(tp, PHY_ADDR, reg, val); ++} ++ ++static int __tg3_writephy(struct tg3 *tp, unsigned int phy_addr, int reg, u32 val) + { + u32 frame_val; + unsigned int loops; +@@ -688,7 +695,7 @@ static int tg3_writephy(struct tg3 *tp, + udelay(80); + } + +- frame_val = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) & ++ frame_val = ((phy_addr << MI_COM_PHY_ADDR_SHIFT) & + MI_COM_PHY_ADDR_MASK); + frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) & + MI_COM_REG_ADDR_MASK); +@@ -721,6 +728,11 @@ static int tg3_writephy(struct tg3 *tp, + return ret; + } + ++static int tg3_writephy(struct tg3 *tp, int reg, u32 val) ++{ ++ return __tg3_writephy(tp, PHY_ADDR, reg, val); ++} ++ + static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) + { + u32 phy; +@@ -1988,6 +2000,14 @@ static int tg3_setup_copper_phy(struct t + tp->link_config.active_duplex = current_duplex; + } + ++ if (tp->tg3_flags3 & TG3_FLG3_ROBOSWITCH) { ++ current_link_up = 1; ++ current_speed = SPEED_1000; //FIXME ++ current_duplex = DUPLEX_FULL; ++ tp->link_config.active_speed = current_speed; ++ tp->link_config.active_duplex = current_duplex; ++ } ++ + if (current_link_up == 1 && + (tp->link_config.active_duplex == DUPLEX_FULL) && + (tp->link_config.autoneg == AUTONEG_ENABLE)) { +@@ -4813,6 +4833,11 @@ static int tg3_poll_fw(struct tg3 *tp) + int i; + u32 val; + ++ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) { ++ /* We don't use firmware. */ ++ return 0; ++ } ++ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + /* Wait up to 20ms for init done. */ + for (i = 0; i < 200; i++) { +@@ -5040,6 +5065,14 @@ static int tg3_chip_reset(struct tg3 *tp + tw32(0x5000, 0x400); + } + ++ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) { ++ /* BCM4785: In order to avoid repercussions from using potentially ++ * defective internal ROM, stop the Rx RISC CPU, which is not ++ * required. */ ++ tg3_stop_fw(tp); ++ tg3_halt_cpu(tp, RX_CPU_BASE); ++ } ++ + tw32(GRC_MODE, tp->grc_mode); + + if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) { +@@ -5308,9 +5341,12 @@ static int tg3_halt_cpu(struct tg3 *tp, + return -ENODEV; + } + +- /* Clear firmware's nvram arbitration. */ +- if (tp->tg3_flags & TG3_FLAG_NVRAM) +- tw32(NVRAM_SWARB, SWARB_REQ_CLR0); ++ if (!(tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE)) { ++ /* Clear firmware's nvram arbitration. */ ++ if (tp->tg3_flags & TG3_FLAG_NVRAM) ++ tw32(NVRAM_SWARB, SWARB_REQ_CLR0); ++ } ++ + return 0; + } + +@@ -5391,6 +5427,11 @@ static int tg3_load_5701_a0_firmware_fix + struct fw_info info; + int err, i; + ++ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) { ++ /* We don't use firmware. */ ++ return 0; ++ } ++ + info.text_base = TG3_FW_TEXT_ADDR; + info.text_len = TG3_FW_TEXT_LEN; + info.text_data = &tg3FwText[0]; +@@ -5949,6 +5990,11 @@ static int tg3_load_tso_firmware(struct + unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size; + int err, i; + ++ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) { ++ /* We don't use firmware. */ ++ return 0; ++ } ++ + if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) + return 0; + +@@ -6850,6 +6896,11 @@ static void tg3_timer(unsigned long __op + + spin_lock(&tp->lock); + ++ if (tp->tg3_flags3 & TG3_FLG3_FLUSH_POSTED_WRITES) { ++ /* BCM4785: Flush posted writes from GbE to host memory. */ ++ tr32(HOSTCC_MODE); ++ } ++ + if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { + /* All of this garbage is because when using non-tagged + * IRQ status the mailbox/status_block protocol the chip +@@ -8432,6 +8483,11 @@ static int tg3_test_nvram(struct tg3 *tp + u32 *buf, csum, magic; + int i, j, err = 0, size; + ++ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) { ++ /* We don't have NVRAM. */ ++ return 0; ++ } ++ + if (tg3_nvram_read_swab(tp, 0, &magic) != 0) + return -EIO; + +@@ -9154,7 +9210,7 @@ static int tg3_ioctl(struct net_device * + return -EAGAIN; + + spin_lock_bh(&tp->lock); +- err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval); ++ err = __tg3_readphy(tp, data->phy_id & 0x1f, data->reg_num & 0x1f, &mii_regval); + spin_unlock_bh(&tp->lock); + + data->val_out = mii_regval; +@@ -9173,7 +9229,7 @@ static int tg3_ioctl(struct net_device * + return -EAGAIN; + + spin_lock_bh(&tp->lock); +- err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in); ++ err = __tg3_writephy(tp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); + spin_unlock_bh(&tp->lock); + + return err; +@@ -9571,6 +9627,12 @@ static void __devinit tg3_get_5906_nvram + /* Chips other than 5700/5701 use the NVRAM for fetching info. */ + static void __devinit tg3_nvram_init(struct tg3 *tp) + { ++ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) { ++ /* No NVRAM and EEPROM on the SSB Broadcom GigE core. */ ++ tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED); ++ return; ++ } ++ + tw32_f(GRC_EEPROM_ADDR, + (EEPROM_ADDR_FSM_RESET | + (EEPROM_DEFAULT_CLOCK_PERIOD << +@@ -9706,6 +9768,9 @@ static int tg3_nvram_read(struct tg3 *tp + { + int ret; + ++ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) ++ return -ENODEV; ++ + if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) + return tg3_nvram_read_using_eeprom(tp, offset, val); + +@@ -9938,6 +10003,9 @@ static int tg3_nvram_write_block(struct + { + int ret; + ++ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) ++ return -ENODEV; ++ + if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl & + ~GRC_LCLCTRL_GPIO_OUTPUT1); +@@ -10804,7 +10872,6 @@ static int __devinit tg3_get_invariants( + tp->write32 = tg3_write_flush_reg32; + } + +- + if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) || + (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) { + tp->write32_tx_mbox = tg3_write32_tx_mbox; +@@ -10840,6 +10907,11 @@ static int __devinit tg3_get_invariants( + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701))) + tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG; + ++ if (tp->tg3_flags3 & TG3_FLG3_FLUSH_POSTED_WRITES) { ++ tp->write32_tx_mbox = tg3_write_flush_reg32; ++ tp->write32_rx_mbox = tg3_write_flush_reg32; ++ } ++ + /* Get eeprom hw config before calling tg3_set_power_state(). + * In particular, the TG3_FLG2_IS_NIC flag must be + * determined before calling tg3_set_power_state() so that +@@ -11184,6 +11256,10 @@ static int __devinit tg3_get_device_addr + } + + if (!is_valid_ether_addr(&dev->dev_addr[0])) { ++ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) ++ ssb_gige_get_macaddr(tp->pdev, &dev->dev_addr[0]); ++ } ++ if (!is_valid_ether_addr(&dev->dev_addr[0])) { + #ifdef CONFIG_SPARC64 + if (!tg3_get_default_macaddr_sparc(tp)) + return 0; +@@ -11675,6 +11751,7 @@ static char * __devinit tg3_phy_string(s + case PHY_ID_BCM5704: return "5704"; + case PHY_ID_BCM5705: return "5705"; + case PHY_ID_BCM5750: return "5750"; ++ case PHY_ID_BCM5750_2: return "5750-2"; + case PHY_ID_BCM5752: return "5752"; + case PHY_ID_BCM5714: return "5714"; + case PHY_ID_BCM5780: return "5780"; +@@ -11859,6 +11936,13 @@ static int __devinit tg3_init_one(struct + tp->msg_enable = tg3_debug; + else + tp->msg_enable = TG3_DEF_MSG_ENABLE; ++ if (pdev_is_ssb_gige_core(pdev)) { ++ tp->tg3_flags3 |= TG3_FLG3_IS_SSB_CORE; ++ if (ssb_gige_must_flush_posted_writes(pdev)) ++ tp->tg3_flags3 |= TG3_FLG3_FLUSH_POSTED_WRITES; ++ if (ssb_gige_have_roboswitch(pdev)) ++ tp->tg3_flags3 |= TG3_FLG3_ROBOSWITCH; ++ } + + /* The word/byte swap controls here control register access byte + * swapping. DMA data byte swapping is controlled in the GRC_MODE +Index: linux-2.6.23.16/drivers/net/tg3.h +=================================================================== +--- linux-2.6.23.16.orig/drivers/net/tg3.h 2008-03-19 11:16:15.000000000 +0100 ++++ linux-2.6.23.16/drivers/net/tg3.h 2008-03-19 11:16:18.000000000 +0100 +@@ -2279,6 +2279,10 @@ struct tg3 { + #define TG3_FLG2_PHY_JITTER_BUG 0x20000000 + #define TG3_FLG2_NO_FWARE_REPORTED 0x40000000 + #define TG3_FLG2_PHY_ADJUST_TRIM 0x80000000 ++ u32 tg3_flags3; ++#define TG3_FLG3_IS_SSB_CORE 0x00000001 ++#define TG3_FLG3_FLUSH_POSTED_WRITES 0x00000002 ++#define TG3_FLG3_ROBOSWITCH 0x00000004 + + struct timer_list timer; + u16 timer_counter; +@@ -2333,6 +2337,7 @@ struct tg3 { + #define PHY_ID_BCM5714 0x60008340 + #define PHY_ID_BCM5780 0x60008350 + #define PHY_ID_BCM5755 0xbc050cc0 ++#define PHY_ID_BCM5750_2 0xbc050cd0 + #define PHY_ID_BCM5787 0xbc050ce0 + #define PHY_ID_BCM5756 0xbc050ed0 + #define PHY_ID_BCM5906 0xdc00ac40 +@@ -2364,7 +2369,8 @@ struct tg3 { + (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \ + (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \ + (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \ +- (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002) ++ (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002 || \ ++ (X) == PHY_ID_BCM5750_2) + + struct tg3_hw_stats *hw_stats; + dma_addr_t stats_mapping; +Index: linux-2.6.23.16/drivers/ssb/driver_mipscore.c +=================================================================== +--- linux-2.6.23.16.orig/drivers/ssb/driver_mipscore.c 2008-03-19 11:16:18.000000000 +0100 ++++ linux-2.6.23.16/drivers/ssb/driver_mipscore.c 2008-03-19 11:16:18.000000000 +0100 +@@ -211,6 +211,7 @@ void ssb_mipscore_init(struct ssb_mipsco + /* fallthrough */ + case SSB_DEV_PCI: + case SSB_DEV_ETHERNET: ++ case SSB_DEV_ETHERNET_GBIT: + case SSB_DEV_80211: + case SSB_DEV_USB20_HOST: + /* These devices get their own IRQ line if available, the rest goes on IRQ0 */ |