diff options
19 files changed, 1841 insertions, 335 deletions
diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/Kconfig b/target/linux/brcm47xx-2.6/files/drivers/ssb/Kconfig index 09330dfa6b..03c4945868 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/Kconfig +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/Kconfig @@ -71,4 +71,23 @@ config SSB_PCICORE_HOSTMODE help PCIcore hostmode operation (external PCI bus). +config SSB_DRIVER_MIPS + bool "SSB Broadcom MIPS core driver" + depends on SSB && MIPS + select SSB_SERIAL + help + Driver for the Sonics Silicon Backplane attached + Broadcom MIPS core. + + If unsure, say N + +config SSB_DRIVER_EXTIF + bool "SSB Broadcom EXTIF core driver" + depends on SSB_DRIVER_MIPS + help + Driver for the Sonics Silicon Backplane attached + Broadcom EXTIF core. + + If unsure, say N + endmenu diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/Makefile b/target/linux/brcm47xx-2.6/files/drivers/ssb/Makefile index 9f85d225dd..9a2b379fbf 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/Makefile +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/Makefile @@ -1,14 +1,11 @@ -ssb-driver-chipcommon-y := driver_chipcommon/chipcommon.o -ssb-driver-mips-$(CONFIG_BCM947XX) := driver_mips/mips.o -ssb-driver-pci-$(CONFIG_SSB_DRIVER_PCICORE) := driver_pci/pcicore.o +ssb-builtin-drivers-y += driver_chipcommon.o +ssb-builtin-drivers-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o +ssb-builtin-drivers-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o -ssb-$(CONFIG_SSB_PCIHOST) += pci.o -ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o +ssb-hostsupport-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o +ssb-hostsupport-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o obj-$(CONFIG_SSB) += ssb.o -ssb-objs := core.o scan.o \ - $(ssb-y) $(ssb-m) \ - $(ssb-driver-chipcommon-y) \ - $(ssb-driver-mips-y) \ - $(ssb-driver-pci-y) +ssb-objs := main.o scan.o \ + $(ssb-hostsupport-y) $(ssb-builtin-drivers-y) diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_chipcommon/chipcommon.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_chipcommon.c index a17910947e..8e511c77b5 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_chipcommon/chipcommon.c +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_chipcommon.c @@ -12,7 +12,7 @@ #include <linux/ssb/ssb_regs.h> #include <linux/pci.h> -#include "../ssb_private.h" +#include "ssb_private.h" /* Clock sources */ @@ -39,7 +39,6 @@ static inline void chipco_write32(struct ssb_chipcommon *cc, ssb_write32(cc->dev, offset, value); } - void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, enum ssb_clkmode mode) { @@ -89,7 +88,6 @@ void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, assert(0); } } -EXPORT_SYMBOL(ssb_chipco_set_clockmode); /* Get the Slow Clock Source */ static int chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc) @@ -98,8 +96,8 @@ static int chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc) u32 tmp = 0; if (cc->dev->id.revision < 6) { - if (bus->bustype == SSB_BUSTYPE_SSB /*TODO || - bus->bustype == SSB_BUSTYPE_PCMCIA*/) + if (bus->bustype == SSB_BUSTYPE_SSB || + bus->bustype == SSB_BUSTYPE_PCMCIA) return SSB_CHIPCO_CLKSRC_XTALOS; if (bus->bustype == SSB_BUSTYPE_PCI) { pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &tmp); @@ -246,8 +244,8 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) { if (!cc->dev) return; /* We don't have a ChipCommon */ - ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); chipco_powercontrol_init(cc); + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); calc_fast_powerup_delay(cc); } @@ -262,37 +260,8 @@ void ssb_chipco_resume(struct ssb_chipcommon *cc) { if (!cc->dev) return; - ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); chipco_powercontrol_init(cc); -} - -void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, u32 chip_id, u32 *rate, - u32 *plltype, u32 *n, u32 *m) -{ - *rate = 0; - *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); - *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); - switch (*plltype) { - case SSB_PLLTYPE_2: - case SSB_PLLTYPE_4: - case SSB_PLLTYPE_6: - case SSB_PLLTYPE_7: - *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); - break; - case SSB_PLLTYPE_5: - *rate = 200000000; - break; - case SSB_PLLTYPE_3: - /* 5350 uses m2 to control mips */ - *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); - break; - default: - *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); - break; - } - - if (*rate == 0 && chip_id == 0x5365) - *rate = 200000000; + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); } void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, @@ -351,6 +320,7 @@ void ssb_chipco_timing_init(struct ssb_chipcommon *cc, } } + #ifdef CONFIG_SSB_SERIAL int ssb_chipco_serial_init(struct ssb_chipcommon *cc, struct ssb_serial_port *ports) @@ -430,13 +400,3 @@ int ssb_chipco_serial_init(struct ssb_chipcommon *cc, return nr_ports; } #endif /* CONFIG_SSB_SERIAL */ - -/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ -int -ssb_chipco_watchdog(struct ssb_chipcommon *cc, uint ticks) -{ - /* instant NMI */ - chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); - return 0; -} -EXPORT_SYMBOL(ssb_chipco_watchdog); diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_mips/mips.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_mipscore.c index 7b3880ab01..67d10178b6 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_mips/mips.c +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_mipscore.c @@ -4,7 +4,6 @@ * * Copyright 2005, Broadcom Corporation * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> - * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org> * * Licensed under the GNU/GPL. See COPYING for details. */ @@ -16,12 +15,21 @@ #include <linux/serial_reg.h> #include <asm/time.h> -#include "../ssb_private.h" +#include "ssb_private.h" -#define mips_read32(mcore, offset) ssb_read32((mcore)->dev, offset) -#define mips_write32(mcore, offset, value) ssb_write32((mcore)->dev, offset, value) -#define extif_read32(extif, offset) ssb_read32((extif)->dev, offset) -#define extif_write32(extif, offset, value) ssb_write32((extif)->dev, offset, value) + +static inline u32 mips_read32(struct ssb_mipscore *mcore, + u16 offset) +{ + return ssb_read32(mcore->dev, offset); +} + +static inline void mips_write32(struct ssb_mipscore *mcore, + u16 offset, + u32 value) +{ + ssb_write32(mcore->dev, offset, value); +} static const u32 ipsflag_irq_mask[] = { 0, @@ -109,8 +117,17 @@ static void set_irq(struct ssb_device *dev, unsigned int irq) ssb_write32(mdev, SSB_IPSFLAG, irqflag); } -static int ssb_extif_serial_init(struct ssb_extif *dev, struct ssb_serial_port *ports) +/* XXX: leave here or move into separate extif driver? */ +static int ssb_extif_serial_init(struct ssb_device *dev, struct ssb_serial_ports *ports) +{ + +} + + +static void ssb_mips_serial_init(struct ssb_mipscore *mcore) { + struct ssb_bus *bus = mcore->dev->bus; + //TODO if (EXTIF available #if 0 extifregs_t *eir = (extifregs_t *) regs; @@ -145,14 +162,6 @@ static int ssb_extif_serial_init(struct ssb_extif *dev, struct ssb_serial_port * add((void *) &eir->uartdata, irq, sb_clock(sbh), 2); #endif - -} - - -static void ssb_mips_serial_init(struct ssb_mipscore *mcore) -{ - struct ssb_bus *bus = mcore->dev->bus; - if (bus->extif.dev) mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports); else if (bus->chipco.dev) @@ -165,68 +174,18 @@ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) { struct ssb_bus *bus = mcore->dev->bus; - mcore->flash_buswidth = 2; if (bus->chipco.dev) { mcore->flash_window = 0x1c000000; - mcore->flash_window_size = 0x02000000; - if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG) - & SSB_CHIPCO_CFG_DS16) == 0) - mcore->flash_buswidth = 1; + mcore->flash_window_size = 0x800000; } else { mcore->flash_window = 0x1fc00000; - mcore->flash_window_size = 0x00400000; + mcore->flash_window_size = 0x400000; } } -static void ssb_extif_timing_init(struct ssb_extif *extif, u32 ns) -{ - u32 tmp; - - /* Initialize extif so we can get to the LEDs and external UART */ - extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN); - - /* Set timing for the flash */ - tmp = ceildiv(10, ns) << SSB_PROG_WCNT_3_SHIFT; - tmp |= ceildiv(40, ns) << SSB_PROG_WCNT_1_SHIFT; - tmp |= ceildiv(120, ns); - extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); - - /* Set programmable interface timing for external uart */ - tmp = ceildiv(10, ns) << SSB_PROG_WCNT_3_SHIFT; - tmp |= ceildiv(20, ns) << SSB_PROG_WCNT_2_SHIFT; - tmp |= ceildiv(100, ns) << SSB_PROG_WCNT_1_SHIFT; - tmp |= ceildiv(120, ns); - extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); -} - -static inline void ssb_extif_get_clockcontrol(struct ssb_extif *extif, - u32 *pll_type, u32 *n, u32 *m) -{ - *pll_type = SSB_PLLTYPE_1; - *n = extif_read32(extif, SSB_EXTIF_CLOCK_N); - *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB); -} -u32 ssb_cpu_clock(struct ssb_mipscore *mcore) +static void ssb_cpu_clock(struct ssb_mipscore *mcore) { - struct ssb_bus *bus = mcore->dev->bus; - u32 pll_type, n, m, rate = 0; - - if (bus->extif.dev) { - ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m); - } else if (bus->chipco.dev) { - ssb_chipco_get_clockcpu(&bus->chipco, bus->chip_id, &rate, - &pll_type, &n, &m); - } else - return 0; - - if (rate == 0) - rate = ssb_calc_clock_rate(pll_type, n, m); - - if (pll_type == SSB_PLLTYPE_6) - rate *= 2; - - return rate; } void ssb_mipscore_init(struct ssb_mipscore *mcore) @@ -246,9 +205,28 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) hz = 100000000; ns = 1000000000 / hz; - if (bus->extif.dev) - ssb_extif_timing_init(&bus->extif, ns); - else if (bus->chipco.dev) +//TODO +#if 0 + if (have EXTIF) { + /* Initialize extif so we can get to the LEDs and external UART */ + W_REG(&eir->prog_config, CF_EN); + + /* Set timing for the flash */ + tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */ + tmp = tmp | (CEIL(40, ns) << FW_W1_SHIFT); /* W1 = 40nS */ + tmp = tmp | CEIL(120, ns); /* W0 = 120nS */ + W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */ + + /* Set programmable interface timing for external uart */ + tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */ + tmp = tmp | (CEIL(20, ns) << FW_W2_SHIFT); /* W2 = 20nS */ + tmp = tmp | (CEIL(100, ns) << FW_W1_SHIFT); /* W1 = 100nS */ + tmp = tmp | CEIL(120, ns); /* W0 = 120nS */ + W_REG(&eir->prog_waitcount, tmp); + } + else... chipcommon +#endif + if (bus->chipco.dev) ssb_chipco_timing_init(&bus->chipco, ns); /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */ @@ -278,5 +256,3 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) ssb_mips_serial_init(mcore); ssb_mips_flash_detect(mcore); } - -EXPORT_SYMBOL(ssb_mips_irq); diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_pci/pcicore.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_pcicore.c index 3ad97036f2..a59dff083e 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_pci/pcicore.c +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/driver_pcicore.c @@ -12,7 +12,8 @@ #include <linux/pci.h> #include <linux/delay.h> -#include "../ssb_private.h" +#include "ssb_private.h" + static inline u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset) @@ -92,9 +93,6 @@ static void __init ssb_fixup_pcibridge(struct pci_dev *dev) /* 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 */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8); } DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); @@ -112,7 +110,7 @@ static u32 get_cfgspace_addr(struct ssb_pcicore *pc, if (unlikely(pc->cardbusmode && dev > 1)) goto out; - if (bus == 0) {//FIXME busnumber ok? + if (bus == 0) { /* Type 0 transaction */ if (unlikely(dev >= SSB_PCI_SLOT_MAX)) goto out; @@ -164,7 +162,8 @@ static int ssb_extpci_read_config(struct ssb_pcicore *pc, val = 0xffffffff; goto unmap; } - + + val = readl(mmio); val >>= (8 * (off & 3)); switch (len) { @@ -212,10 +211,12 @@ static int ssb_extpci_write_config(struct ssb_pcicore *pc, switch (len) { case 1: + val = readl(mmio); val &= ~(0xFF << (8 * (off & 3))); val |= *((const u8 *)buf) << (8 * (off & 3)); break; case 2: + val = readl(mmio); val &= ~(0xFFFF << (8 * (off & 3))); val |= *((const u16 *)buf) << (8 * (off & 3)); break; @@ -223,7 +224,7 @@ static int ssb_extpci_write_config(struct ssb_pcicore *pc, val = *((const u32 *)buf); break; } - writel(val, mmio); + writel(*((const u32 *)buf), mmio); err = 0; unmap: @@ -290,7 +291,10 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) { u32 val; - assert(!extpci_core); + if (extpci_core) { + WARN_ON(1); + return; + } extpci_core = pc; ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n"); @@ -303,8 +307,6 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) udelay(150); val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */ pcicore_write32(pc, SSB_PCICORE_CTL, val); - val = SSB_PCICORE_ARBCTL_INTERN; - pcicore_write32(pc, SSB_PCICORE_ARBCTL, val); udelay(1); //TODO cardbus mode @@ -321,7 +323,10 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) /* Enable PCI bridge BAR0 prefetch and burst */ val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; - ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 4); + ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2); + /* Clear error conditions */ + val = 0; + ssb_extpci_write_config(pc, 0, 0, 0, PCI_STATUS, &val, 2); /* Enable PCI interrupts */ pcicore_write32(pc, SSB_PCICORE_IMASK, @@ -331,7 +336,6 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) * 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)); - mdelay(300); register_pci_controller(&ssb_pcicore_controller); } @@ -383,7 +387,8 @@ void ssb_pcicore_init(struct ssb_pcicore *pc) if (!dev) return; bus = dev->bus; - ssb_device_enable(dev, 0); + if (!ssb_device_is_enabled(dev)) + ssb_device_enable(dev, 0); #ifdef CONFIG_SSB_PCICORE_HOSTMODE pc->hostmode = pcicore_is_in_hostmode(pc); diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/core.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/main.c index 2ee13d2d36..a2d22312ca 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/core.c +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/main.c @@ -35,35 +35,55 @@ static LIST_HEAD(buses); static int nr_buses; static DEFINE_MUTEX(buses_mutex); -#define ssb_buses_lock() do { \ - if (!is_early_boot()) \ - mutex_lock(&buses_mutex); \ - } while (0) +static void ssb_buses_lock(void); +static void ssb_buses_unlock(void); -#define ssb_buses_unlock() do { \ - if (!is_early_boot()) \ - mutex_unlock(&buses_mutex); \ - } while (0) +#ifdef CONFIG_SSB_PCIHOST +struct ssb_bus * ssb_pci_dev_to_bus(struct pci_dev *pdev) +{ + struct ssb_bus *bus; + + ssb_buses_lock(); + list_for_each_entry(bus, &buses, list) { + if (bus->bustype == SSB_BUSTYPE_PCI && + bus->host_pci == pdev) + goto found; + } + bus = NULL; +found: + ssb_buses_unlock(); + + return bus; +} +#endif /* CONFIG_SSB_PCIHOST */ static struct ssb_device * ssb_device_get(struct ssb_device *dev) { if (dev) - get_device(&dev->dev); + get_device(dev->dev); return dev; } static void ssb_device_put(struct ssb_device *dev) { if (dev) - put_device(&dev->dev); + put_device(dev->dev); } -static void ssb_bus_resume(struct ssb_bus *bus) +static int ssb_bus_resume(struct ssb_bus *bus) { -printk("SSB BUS RESUME\n"); + int err; + ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); + err = ssb_pcmcia_init(bus); + if (err) { + /* No need to disable XTAL, as we don't have one on PCMCIA. */ + return err; + } ssb_chipco_resume(&bus->chipco); + + return 0; } static int ssb_device_resume(struct device *dev) @@ -73,10 +93,12 @@ static int ssb_device_resume(struct device *dev) struct ssb_bus *bus; int err = 0; -printk("SSB DEV RESUME\n"); bus = ssb_dev->bus; - if (bus->suspend_cnt == bus->nr_devices) - ssb_bus_resume(bus); + if (bus->suspend_cnt == bus->nr_devices) { + err = ssb_bus_resume(bus); + if (err) + return err; + } bus->suspend_cnt--; if (dev->driver) { ssb_drv = drv_to_ssb_drv(dev->driver); @@ -91,9 +113,15 @@ out: static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state) { -printk("SSB BUS SUSPEND\n"); -// ssb_chipco_suspend(&bus->chipco, state); -// ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); + ssb_chipco_suspend(&bus->chipco, state); + ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); + + /* Reset HW state information in memory, so that HW is + * completely reinitialized on resume. */ + bus->mapped_device = NULL; +#ifdef CONFIG_SSB_DRIVER_PCICORE + bus->pcicore.setup_done = 0; +#endif } static int ssb_device_suspend(struct device *dev, pm_message_t state) @@ -103,7 +131,6 @@ static int ssb_device_suspend(struct device *dev, pm_message_t state) struct ssb_bus *bus; int err = 0; -printk("SSB DEV SUSPEND\n"); if (dev->driver) { ssb_drv = drv_to_ssb_drv(dev->driver); if (ssb_drv && ssb_drv->suspend) @@ -123,6 +150,57 @@ out: return err; } +#ifdef CONFIG_SSB_PCIHOST +int ssb_devices_freeze(struct ssb_bus *bus) +{ + struct ssb_device *dev; + struct ssb_driver *drv; + int err = 0; + int i; + pm_message_t state = PMSG_FREEZE; + + for (i = 0; i < bus->nr_devices; i++) { + dev = &(bus->devices[i]); + if (!dev->dev->driver) + continue; + if (!device_is_registered(dev->dev)) + continue; + drv = drv_to_ssb_drv(dev->dev->driver); + if (drv && drv->suspend) { + err = drv->suspend(dev, state); + if (err) + goto out; + } + } +out: + return err; +} + +int ssb_devices_thaw(struct ssb_bus *bus) +{ + struct ssb_device *dev; + struct ssb_driver *drv; + int err = 0; + int i; + + for (i = 0; i < bus->nr_devices; i++) { + dev = &(bus->devices[i]); + if (!dev->dev->driver) + continue; + if (!device_is_registered(dev->dev)) + continue; + drv = drv_to_ssb_drv(dev->dev->driver); + if (drv && drv->resume) { + err = drv->resume(dev); + if (err) + goto out; + } + } +out: + return err; +} +#endif /* CONFIG_SSB_PCIHOST */ + static void ssb_device_shutdown(struct device *dev) { struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); @@ -193,7 +271,7 @@ static int ssb_bus_match(struct device *dev, struct device_driver *drv) return 0; } -struct bus_type ssb_bustype = { +static struct bus_type ssb_bustype = { .name = NULL, /* Intentionally NULL to indicate early boot */ .match = ssb_bus_match, .probe = ssb_device_probe, @@ -205,51 +283,156 @@ struct bus_type ssb_bustype = { #define is_early_boot() (ssb_bustype.name == NULL) -void ssb_bus_unregister(struct ssb_bus *bus) +static void ssb_buses_lock(void) { - struct ssb_device *dev; + if (!is_early_boot()) + mutex_lock(&buses_mutex); +} + +static void ssb_buses_unlock(void) +{ + if (!is_early_boot()) + mutex_unlock(&buses_mutex); +} + +static void ssb_devices_unregister(struct ssb_bus *bus) +{ + struct ssb_device *sdev; int i; - ssb_buses_lock(); for (i = bus->nr_devices - 1; i >= 0; i--) { - dev = &(bus->devices[i]); - device_unregister(&dev->dev); + sdev = &(bus->devices[i]); + if (sdev->dev) + device_unregister(sdev->dev); } +} + +void ssb_bus_unregister(struct ssb_bus *bus) +{ + ssb_buses_lock(); + ssb_devices_unregister(bus); list_del(&bus->list); ssb_buses_unlock(); + /* ssb_pcmcia_exit(bus); */ + ssb_pci_exit(bus); ssb_iounmap(bus); } EXPORT_SYMBOL(ssb_bus_unregister); static void ssb_release_dev(struct device *dev) { - /* Nothing, devices are allocated together with struct ssb_bus. */ + struct __ssb_dev_wrapper *devwrap; + + devwrap = container_of(dev, struct __ssb_dev_wrapper, dev); + kfree(devwrap); +} + +static int ssb_devices_register(struct ssb_bus *bus) +{ + struct ssb_device *sdev; + struct device *dev; + struct __ssb_dev_wrapper *devwrap; + int i, err = 0; + int dev_idx = 0; + + for (i = 0; i < bus->nr_devices; i++) { + sdev = &(bus->devices[i]); + + /* We don't register SSB-system devices to the kernel, + * as the drivers for them are built into SSB. */ + switch (sdev->id.coreid) { + case SSB_DEV_CHIPCOMMON: + case SSB_DEV_PCI: + case SSB_DEV_PCIE: + case SSB_DEV_PCMCIA: + case SSB_DEV_MIPS: + case SSB_DEV_MIPS_3302: + case SSB_DEV_EXTIF: + continue; + } + + devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL); + if (!devwrap) { + ssb_printk(KERN_ERR PFX + "Could not allocate device\n"); + err = -ENOMEM; + goto error; + } + dev = &devwrap->dev; + devwrap->sdev = sdev; + + dev->release = ssb_release_dev; + dev->bus = &ssb_bustype; + snprintf(dev->bus_id, sizeof(dev->bus_id), + "ssb%d:%d", bus->busnumber, dev_idx); + + switch (bus->bustype) { + case SSB_BUSTYPE_PCI: +#ifdef CONFIG_SSB_PCIHOST + sdev->irq = bus->host_pci->irq; + dev->parent = &bus->host_pci->dev; +#endif + break; + case SSB_BUSTYPE_PCMCIA: +#ifdef CONFIG_SSB_PCMCIAHOST + dev->parent = &bus->host_pcmcia->dev; +#endif + break; + case SSB_BUSTYPE_SSB: + break; + } + + sdev->dev = dev; + err = device_register(dev); + if (err) { + ssb_printk(KERN_ERR PFX + "Could not register %s\n", + dev->bus_id); + /* Set dev to NULL to not unregister + * dev on error unwinding. */ + sdev->dev = NULL; + kfree(devwrap); + goto error; + } + dev_idx++; + } + + return 0; +error: + /* Unwind the already registered devices. */ + ssb_devices_unregister(bus); + return err; } /* Needs ssb_buses_lock() */ static int ssb_attach_queued_buses(void) { struct ssb_bus *bus, *n; - struct ssb_device *dev; - int i, err; + int err = 0; + int drop_them_all = 0; list_for_each_entry_safe(bus, n, &attach_queue, list) { + if (drop_them_all) { + list_del(&bus->list); + continue; + } + /* Can't init the PCIcore in ssb_bus_register(), as that + * is too early in boot for embedded systems + * (no udelay() available). So do it here in attach stage. + */ ssb_pcicore_init(&bus->pcicore); - for (i = 0; i < bus->nr_devices; i++) { - dev = &(bus->devices[i]); - - dev->dev.release = ssb_release_dev; - err = device_register(&dev->dev); - if (err) { - ssb_printk(KERN_ERR PFX - "Could not register %s\n", - dev->dev.bus_id); - } + + err = ssb_devices_register(bus); + if (err) { + drop_them_all = 1; + list_del(&bus->list); + continue; } list_move_tail(&bus->list, &buses); } - return 0; + + return err; } static void ssb_get_boardtype(struct ssb_bus *bus) @@ -307,23 +490,6 @@ static int ssb_bus_register(struct ssb_bus *bus, { int err; - ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "); - switch (bus->bustype) { - case SSB_BUSTYPE_SSB: - ssb_printk("address 0x%08lX\n", baseaddr); - break; - case SSB_BUSTYPE_PCI: -#ifdef CONFIG_SSB_PCIHOST - ssb_printk("PCI device %s\n", bus->host_pci->dev.bus_id); -#endif - break; - case SSB_BUSTYPE_PCMCIA: -#ifdef CONFIG_SSB_PCMCIAHOST - ssb_printk("PCMCIA device %s\n", bus->host_pcmcia->devname); -#endif - break; - } - spin_lock_init(&bus->bar_lock); INIT_LIST_HEAD(&bus->list); @@ -346,7 +512,7 @@ static int ssb_bus_register(struct ssb_bus *bus, /* Init PCMCIA-host device (if any) */ err = ssb_pcmcia_init(bus); if (err) - goto err_unmap; + goto err_pci_exit; /* Initialize basic system devices (if available) */ ssb_chipcommon_init(&bus->chipco); @@ -368,12 +534,16 @@ out: err_dequeue: list_del(&bus->list); +/* err_pcmcia_exit: */ +/* ssb_pcmcia_exit(bus); */ +err_pci_exit: + ssb_pci_exit(bus); err_unmap: ssb_iounmap(bus); err_disable_xtal: ssb_buses_unlock(); ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); - goto out; + return err; } #ifdef CONFIG_SSB_PCIHOST @@ -387,6 +557,10 @@ int ssb_bus_pcibus_register(struct ssb_bus *bus, bus->ops = &ssb_pci_ops; err = ssb_bus_register(bus, 0); + if (!err) { + ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " + "PCI device %s\n", host_pci->dev.bus_id); + } return err; } @@ -407,6 +581,10 @@ int ssb_bus_pcmciabus_register(struct ssb_bus *bus, fill_sprom(&bus->sprom); err = ssb_bus_register(bus, baseaddr); + if (!err) { + ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " + "PCMCIA device %s\n", pcmcia_dev->devname); + } return err; } @@ -422,7 +600,12 @@ int ssb_bus_ssbbus_register(struct ssb_bus *bus, bus->bustype = SSB_BUSTYPE_SSB; bus->ops = &ssb_ssb_ops; fill_sprom(&bus->sprom); + err = ssb_bus_register(bus, baseaddr); + if (!err) { + ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found at " + "address 0x%08lX\n", baseaddr); + } return err; } @@ -603,12 +786,29 @@ u32 ssb_clockspeed(struct ssb_bus *bus) } EXPORT_SYMBOL(ssb_clockspeed); +static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev) +{ + /* The REJECT bit changed position in TMSLOW between + * Backplane revisions. */ + switch (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV) { + case SSB_IDLOW_SSBREV_22: + return SSB_TMSLOW_REJECT_22; + case SSB_IDLOW_SSBREV_23: + return SSB_TMSLOW_REJECT_23; + default: + assert(0); + } + return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23); +} + int ssb_device_is_enabled(struct ssb_device *dev) { u32 val; + u32 reject; + reject = ssb_tmslow_reject_bitmask(dev); val = ssb_read32(dev, SSB_TMSLOW); - val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT; + val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | reject; return (val == SSB_TMSLOW_CLOCK); } @@ -677,22 +877,25 @@ static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask, void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags) { + u32 reject; + if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET) return; - ssb_write32(dev, SSB_TMSLOW, SSB_TMSLOW_REJECT | SSB_TMSLOW_CLOCK); - ssb_wait_bit(dev, SSB_TMSLOW, SSB_TMSLOW_REJECT, 1000, 1); + reject = ssb_tmslow_reject_bitmask(dev); + ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK); + ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1); ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0); ssb_write32(dev, SSB_TMSLOW, SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | - SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET | + reject | SSB_TMSLOW_RESET | core_specific_flags); /* flush */ ssb_read32(dev, SSB_TMSLOW); udelay(1); ssb_write32(dev, SSB_TMSLOW, - SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET | + reject | SSB_TMSLOW_RESET | core_specific_flags); /* flush */ ssb_read32(dev, SSB_TMSLOW); @@ -715,7 +918,7 @@ EXPORT_SYMBOL(ssb_dma_translation); int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask) { - struct device *dev = &ssb_dev->dev; + struct device *dev = ssb_dev->dev; #ifdef CONFIG_SSB_PCIHOST if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI && @@ -729,6 +932,50 @@ int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask) } EXPORT_SYMBOL(ssb_dma_set_mask); +int ssb_bus_may_powerdown(struct ssb_bus *bus) +{ + struct ssb_chipcommon *cc; + int err; + + /* On buses where more than one core may be working + * at a time, we must not powerdown stuff if there are + * still cores that may want to run. */ + if (bus->bustype == SSB_BUSTYPE_SSB) + return 0; + + cc = &bus->chipco; + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW); + err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); + if (err) + goto error; + + return 0; +error: + ssb_printk(KERN_ERR PFX "Bus powerdown failed\n"); + return err; +} +EXPORT_SYMBOL(ssb_bus_may_powerdown); + +int ssb_bus_powerup(struct ssb_bus *bus, int dynamic_pctl) +{ + struct ssb_chipcommon *cc; + int err; + enum ssb_clkmode mode; + + err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); + if (err) + goto error; + cc = &bus->chipco; + mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; + ssb_chipco_set_clockmode(cc, mode); + + return 0; +error: + ssb_printk(KERN_ERR PFX "Bus powerup failed\n"); + return err; +} +EXPORT_SYMBOL(ssb_bus_powerup); + u32 ssb_admatch_base(u32 adm) { u32 base = 0; @@ -793,6 +1040,8 @@ static int __init ssb_modinit(void) ssb_buses_lock(); err = ssb_attach_queued_buses(); ssb_buses_unlock(); + if (err) + bus_unregister(&ssb_bustype); return err; } diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/pci.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/pci.c index 811af789ed..fcd8e871cb 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/pci.c +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/pci.c @@ -121,7 +121,7 @@ int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on) err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); if (err) goto err_pci; - msleep(2); + msleep(5); } } @@ -240,6 +240,52 @@ static void sprom_do_read(struct ssb_bus *bus, u16 *sprom) sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2)); } +static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) +{ + struct pci_dev *pdev = bus->host_pci; + int i, err; + u32 spromctl; + + ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); + err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); + if (err) + goto err_ctlreg; + spromctl |= SSB_SPROMCTL_WE; + err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); + if (err) + goto err_ctlreg; + ssb_printk(KERN_NOTICE PFX "[ 0%%"); + msleep(500); + for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) { + if (i == SSB_SPROMSIZE_WORDS / 4) + ssb_printk("25%%"); + else if (i == SSB_SPROMSIZE_WORDS / 2) + ssb_printk("50%%"); + else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3) + ssb_printk("75%%"); + else if (i % 2) + ssb_printk("."); + writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2)); + mmiowb(); + msleep(20); + } + err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); + if (err) + goto err_ctlreg; + spromctl &= ~SSB_SPROMCTL_WE; + err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); + if (err) + goto err_ctlreg; + msleep(500); + ssb_printk("100%% ]\n"); + ssb_printk(KERN_NOTICE PFX "SPROM written.\n"); + + return 0; +err_ctlreg: + ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + return err; +} + static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in) { int i; @@ -472,9 +518,155 @@ const struct ssb_bus_ops ssb_pci_ops = { .write32 = ssb_pci_write32, }; +static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len) +{ + int i, pos = 0; + + for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) { + pos += snprintf(buf + pos, buf_len - pos - 1, + "%04X", swab16(sprom[i]) & 0xFFFF); + } + pos += snprintf(buf + pos, buf_len - pos - 1, "\n"); + + return pos + 1; +} + +static int hex2sprom(u16 *sprom, const char *dump, size_t len) +{ + char tmp[5] = { 0 }; + int cnt = 0; + unsigned long parsed; + + if (len < SSB_SPROMSIZE_BYTES * 2) + return -EINVAL; + + while (cnt < SSB_SPROMSIZE_WORDS) { + memcpy(tmp, dump, 4); + dump += 4; + parsed = simple_strtoul(tmp, NULL, 16); + sprom[cnt++] = swab16((u16)parsed); + } + + return 0; +} + +static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); + struct ssb_bus *bus; + u16 *sprom; + int err = -ENODEV; + ssize_t count = 0; + + bus = ssb_pci_dev_to_bus(pdev); + if (!bus) + goto out; + err = -ENOMEM; + sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); + if (!sprom) + goto out; + + err = -ERESTARTSYS; + if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) + goto out_kfree; + sprom_do_read(bus, sprom); + mutex_unlock(&bus->pci_sprom_mutex); + + count = sprom2hex(sprom, buf, PAGE_SIZE); + err = 0; + +out_kfree: + kfree(sprom); +out: + return err ? err : count; +} + +static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); + struct ssb_bus *bus; + u16 *sprom; + int res = 0, err = -ENODEV; + + bus = ssb_pci_dev_to_bus(pdev); + if (!bus) + goto out; + err = -ENOMEM; + sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); + if (!sprom) + goto out; + err = hex2sprom(sprom, buf, count); + if (err) { + err = -EINVAL; + goto out_kfree; + } + err = sprom_check_crc(sprom); + if (err) { + err = -EINVAL; + goto out_kfree; + } + + err = -ERESTARTSYS; + if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) + goto out_kfree; + err = ssb_devices_freeze(bus); + if (err) { + ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); + goto out_unlock; + } + res = sprom_do_write(bus, sprom); + err = ssb_devices_thaw(bus); + if (err) + ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); +out_unlock: + mutex_unlock(&bus->pci_sprom_mutex); +out_kfree: + kfree(sprom); +out: + if (res) + return res; + return err ? err : count; +} + +static DEVICE_ATTR(ssb_sprom, 0600, + ssb_pci_attr_sprom_show, + ssb_pci_attr_sprom_store); + +void ssb_pci_exit(struct ssb_bus *bus) +{ + struct pci_dev *pdev; + + if (bus->bustype != SSB_BUSTYPE_PCI) + return; + + pdev = bus->host_pci; + device_remove_file(&pdev->dev, &dev_attr_ssb_sprom); +} + int ssb_pci_init(struct ssb_bus *bus) { + struct pci_dev *pdev; + int err; + if (bus->bustype != SSB_BUSTYPE_PCI) return 0; - return ssb_pci_sprom_get(bus); + + pdev = bus->host_pci; + mutex_init(&bus->pci_sprom_mutex); + err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom); + if (err) + goto out; + err = ssb_pci_sprom_get(bus); + if (err) + goto err_remove_sprom_file; + +out: + return err; +err_remove_sprom_file: + device_remove_file(&pdev->dev, &dev_attr_ssb_sprom); + return err; } diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/pcihost_wrapper.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/pcihost_wrapper.c new file mode 100644 index 0000000000..82a10abef6 --- /dev/null +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/pcihost_wrapper.c @@ -0,0 +1,104 @@ +/* + * Sonics Silicon Backplane + * PCI Hostdevice wrapper + * + * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de> + * Copyright (c) 2005 Stefano Brivio <st3@riseup.net> + * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> + * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> + * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de> + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include <linux/pci.h> +#include <linux/ssb/ssb.h> + + +#ifdef CONFIG_PM +static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) +{ + pci_save_state(dev); + pci_disable_device(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); + + return 0; +} + +static int ssb_pcihost_resume(struct pci_dev *dev) +{ + int err; + + pci_set_power_state(dev, 0); + err = pci_enable_device(dev); + if (err) + return err; + pci_restore_state(dev); + + return 0; +} +#else /* CONFIG_PM */ +# define ssb_pcihost_suspend NULL +# define ssb_pcihost_resume NULL +#endif /* CONFIG_PM */ + +static int ssb_pcihost_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct ssb_bus *ssb; + int err = -ENOMEM; + const char *name; + + ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); + if (!ssb) + goto out; + err = pci_enable_device(dev); + if (err) + goto err_kfree_ssb; + name = dev->dev.bus_id; + if (dev->driver && dev->driver->name) + name = dev->driver->name; + err = pci_request_regions(dev, name); + if (err) + goto err_pci_disable; + pci_set_master(dev); + + err = ssb_bus_pcibus_register(ssb, dev); + if (err) + goto err_pci_release_regions; + + pci_set_drvdata(dev, ssb); + +out: + return err; + +err_pci_release_regions: + pci_release_regions(dev); +err_pci_disable: + pci_disable_device(dev); +err_kfree_ssb: + kfree(ssb); + return err; +} + +static void ssb_pcihost_remove(struct pci_dev *dev) +{ + struct ssb_bus *ssb = pci_get_drvdata(dev); + + ssb_bus_unregister(ssb); + pci_release_regions(dev); + pci_disable_device(dev); + kfree(ssb); + pci_set_drvdata(dev, NULL); +} + +int ssb_pcihost_register(struct pci_driver *driver) +{ + driver->probe = ssb_pcihost_probe; + driver->remove = ssb_pcihost_remove; + driver->suspend = ssb_pcihost_suspend; + driver->resume = ssb_pcihost_resume; + + return pci_register_driver(driver); +} +EXPORT_SYMBOL(ssb_pcihost_register); diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/scan.c b/target/linux/brcm47xx-2.6/files/drivers/ssb/scan.c index 9e4a121c12..feaf1e57d0 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/scan.c +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/scan.c @@ -17,6 +17,13 @@ #include <linux/pci.h> #include <asm/io.h> +#ifdef CONFIG_SSB_PCMCIAHOST +# include <pcmcia/cs_types.h> +# include <pcmcia/cs.h> +# include <pcmcia/cistpl.h> +# include <pcmcia/ds.h> +#endif + #include "ssb_private.h" @@ -222,14 +229,32 @@ static void __iomem * ssb_ioremap(struct ssb_bus *bus, return mmio; } +static int we_support_multiple_80211_cores(struct ssb_bus *bus) +{ + /* More than one 802.11 core is only supported by special chips. + * There are chips with two 802.11 cores, but with dangling + * pins on the second core. Be careful and reject them here. + */ + +#ifdef CONFIG_SSB_PCIHOST + if (bus->bustype == SSB_BUSTYPE_PCI) { + if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM && + bus->host_pci->device == 0x4324) + return 1; + } +#endif /* CONFIG_SSB_PCIHOST */ + return 0; +} + int ssb_bus_scan(struct ssb_bus *bus, unsigned long baseaddr) { int err = -ENOMEM; void __iomem *mmio; u32 idhi, cc, rev, tmp; - int i; + int dev_i, i; struct ssb_device *dev; + int nr_80211_cores = 0; mmio = ssb_ioremap(bus, baseaddr); if (!mmio) @@ -293,11 +318,11 @@ int ssb_bus_scan(struct ssb_bus *bus, } /* Fetch basic information about each core/device */ - for (i = 0; i < bus->nr_devices; i++) { + for (i = 0, dev_i = 0; i < bus->nr_devices; i++) { err = scan_switchcore(bus, i); if (err) goto err_unmap; - dev = &(bus->devices[i]); + dev = &(bus->devices[dev_i]); idhi = scan_read32(bus, i, SSB_IDHIGH); dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT; @@ -306,8 +331,7 @@ int ssb_bus_scan(struct ssb_bus *bus, dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT; dev->core_index = i; dev->bus = bus; - if ((dev->bus->bustype == SSB_BUSTYPE_PCI) && (bus->host_pci)) - dev->irq = bus->host_pci->irq; + dev->ops = bus->ops; ssb_dprintk(KERN_INFO PFX "Core %d found: %s " @@ -315,13 +339,19 @@ int ssb_bus_scan(struct ssb_bus *bus, i, ssb_core_name(dev->id.coreid), dev->id.coreid, dev->id.revision, dev->id.vendor); - dev->dev.bus = &ssb_bustype; - snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), - "ssb%02x:%02x", bus->busnumber, i); - switch (dev->id.coreid) { + case SSB_DEV_80211: + nr_80211_cores++; + if (nr_80211_cores > 1) { + if (!we_support_multiple_80211_cores(bus)) { + ssb_dprintk(KERN_INFO PFX "Ignoring additional " + "802.11 core\n"); + continue; + } + } + break; case SSB_DEV_EXTIF: -#ifdef CONFIG_BCM947XX +#ifdef CONFIG_SSB_DRIVER_EXTIF if (bus->extif.dev) { ssb_printk(KERN_WARNING PFX "WARNING: Multiple EXTIFs found\n"); @@ -340,14 +370,14 @@ int ssb_bus_scan(struct ssb_bus *bus, break; case SSB_DEV_MIPS: case SSB_DEV_MIPS_3302: -#ifdef CONFIG_BCM947XX +#ifdef CONFIG_SSB_DRIVER_MIPS if (bus->mipscore.dev) { ssb_printk(KERN_WARNING PFX "WARNING: Multiple MIPS cores found\n"); break; } bus->mipscore.dev = dev; -#endif /* CONFIG_BCM947XX */ +#endif /* CONFIG_SSB_DRIVER_MIPS */ break; case SSB_DEV_PCI: case SSB_DEV_PCIE: @@ -363,7 +393,11 @@ int ssb_bus_scan(struct ssb_bus *bus, default: break; } + + dev_i++; } + bus->nr_devices = dev_i; + err = 0; out: return err; diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/ssb_private.h b/target/linux/brcm47xx-2.6/files/drivers/ssb/ssb_private.h index 59645f5a6f..ae1fc0633d 100644 --- a/target/linux/brcm47xx-2.6/files/drivers/ssb/ssb_private.h +++ b/target/linux/brcm47xx-2.6/files/drivers/ssb/ssb_private.h @@ -53,6 +53,7 @@ extern int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on); extern int ssb_pci_sprom_get(struct ssb_bus *bus); extern void ssb_pci_get_boardtype(struct ssb_bus *bus); +extern void ssb_pci_exit(struct ssb_bus *bus); extern int ssb_pci_init(struct ssb_bus *bus); extern const struct ssb_bus_ops ssb_pci_ops; @@ -80,6 +81,9 @@ static inline int ssb_pci_sprom_get(struct ssb_bus *bus) static inline void ssb_pci_get_boardtype(struct ssb_bus *bus) { } +static inline void ssb_pci_exit(struct ssb_bus *bus) +{ +} static inline int ssb_pci_init(struct ssb_bus *bus) { return 0; @@ -128,8 +132,12 @@ extern void ssb_iounmap(struct ssb_bus *ssb); /* core.c */ -extern struct bus_type ssb_bustype; extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); +#ifdef CONFIG_SSB_PCIHOST +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); +#endif /* CONFIG_SSB_PCIHOST */ /* Ceiling division helper. Divides x by y. */ diff --git a/target/linux/brcm47xx-2.6/files/drivers/usb/host/ohci-ssb.c b/target/linux/brcm47xx-2.6/files/drivers/usb/host/ohci-ssb.c new file mode 100644 index 0000000000..2b3ef36b14 --- /dev/null +++ b/target/linux/brcm47xx-2.6/files/drivers/usb/host/ohci-ssb.c @@ -0,0 +1,254 @@ +/* + * 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 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 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, + +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + + .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; + + chipid_top = (dev->bus->chip_id & 0xFF00); + if (chipid_top != 0x4700 && + chipid_top != 0x5300) { + /* USBcores are only connected on embedded devices. */ + return -ENODEV; + } + /* TODO: Probably need more checks here whether the core is 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 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-2.6/files/include/linux/ssb/ssb.h b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb.h index 7fdeae71cb..1ed3cbc1e5 100644 --- a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb.h +++ b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb.h @@ -6,6 +6,9 @@ #include <linux/list.h> #include <linux/types.h> #include <linux/spinlock.h> +#ifdef CONFIG_SSB_PCIHOST +# include <linux/pci.h> +#endif #include <linux/ssb/ssb_regs.h> @@ -98,6 +101,17 @@ struct ssb_sprom { }; +struct ssb_device; +/* Lowlevel read/write operations on the device MMIO. + * Internal, don't use that outside of ssb. */ +struct ssb_bus_ops { + u16 (*read16)(struct ssb_device *dev, u16 offset); + u32 (*read32)(struct ssb_device *dev, u16 offset); + void (*write16)(struct ssb_device *dev, u16 offset, u16 value); + void (*write32)(struct ssb_device *dev, u16 offset, u32 value); +}; + + /* Core-ID values. */ #define SSB_DEV_CHIPCOMMON 0x800 #define SSB_DEV_ILINE20 0x801 @@ -149,18 +163,37 @@ struct ssb_device_id { #define SSB_ANY_ID 0xFFFF #define SSB_ANY_REV 0xFF +/* Some kernel subsystems poke with dev->drvdata, so we must use the + * following ugly workaround to get from struct device to struct ssb_device */ +struct __ssb_dev_wrapper { + struct device dev; + struct ssb_device *sdev; +}; struct ssb_device { - struct device dev; + /* Having a copy of the ops pointer in each dev struct + * is an optimization. */ + const struct ssb_bus_ops *ops; + + struct device *dev; struct ssb_bus *bus; struct ssb_device_id id; u8 core_index; unsigned int irq; + + /* Internal-only stuff follows. */ void *drvdata; /* Per-device data */ void *devtypedata; /* Per-devicetype (eg 802.11) data */ }; -#define dev_to_ssb_dev(_dev) container_of(_dev, struct ssb_device, dev) + +/* Go from struct device to struct ssb_device. */ +static inline +struct ssb_device * dev_to_ssb_dev(struct device *dev) +{ + struct __ssb_dev_wrapper *wrap = container_of(dev, struct __ssb_dev_wrapper, dev); + return wrap->sdev; +} /* Device specific user data */ static inline @@ -182,13 +215,6 @@ void * ssb_get_devtypedata(struct ssb_device *dev) return dev->devtypedata; } -struct ssb_bus_ops { - u16 (*read16)(struct ssb_device *dev, u16 offset); - u32 (*read32)(struct ssb_device *dev, u16 offset); - void (*write16)(struct ssb_device *dev, u16 offset, u16 value); - void (*write32)(struct ssb_device *dev, u16 offset, u32 value); -}; - struct ssb_driver { const char *name; @@ -218,7 +244,6 @@ enum ssb_bustype { SSB_BUSTYPE_SSB, /* This SSB bus is the system bus */ SSB_BUSTYPE_PCI, /* SSB is connected to PCI bus */ SSB_BUSTYPE_PCMCIA, /* SSB is connected to PCMCIA bus */ - //TODO SSB_BUSTYPE_JTAG, }; /* board_vendor */ @@ -238,12 +263,6 @@ enum ssb_bustype { #define SSB_CHIPPACK_BCM4712M 2 /* Medium 225pin 4712 */ #define SSB_CHIPPACK_BCM4712L 0 /* Large 340pin 4712 */ -static inline u16 ssb_read16(struct ssb_device *dev, u16 offset); -static inline u32 ssb_read32(struct ssb_device *dev, u16 offset); -static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value); -static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value); -static inline u32 ssb_write32_masked(struct ssb_device *dev, u16 offset, u32 mask, u32 value); - #include <linux/ssb/ssb_driver_chipcommon.h> #include <linux/ssb/ssb_driver_mips.h> #include <linux/ssb/ssb_driver_extif.h> @@ -269,6 +288,10 @@ struct ssb_bus { /* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */ struct pcmcia_device *host_pcmcia; +#ifdef CONFIG_SSB_PCIHOST + struct mutex pci_sprom_mutex; +#endif + /* ID information about the PCB. */ u16 board_vendor; u16 board_type; @@ -328,32 +351,22 @@ void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags); void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags); +/* Device MMIO register read/write functions. */ static inline u16 ssb_read16(struct ssb_device *dev, u16 offset) { - return dev->bus->ops->read16(dev, offset); + return dev->ops->read16(dev, offset); } static inline u32 ssb_read32(struct ssb_device *dev, u16 offset) { - return dev->bus->ops->read32(dev, offset); + return dev->ops->read32(dev, offset); } static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value) { - dev->bus->ops->write16(dev, offset, value); + dev->ops->write16(dev, offset, value); } static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value) { - dev->bus->ops->write32(dev, offset, value); -} - -static inline u32 ssb_write32_masked(struct ssb_device *dev, - u16 offset, - u32 mask, - u32 value) -{ - value &= mask; - value |= ssb_read32(dev, offset) & ~mask; - ssb_write32(dev, offset, value); - return value; + dev->ops->write32(dev, offset, value); } @@ -366,6 +379,21 @@ extern u32 ssb_dma_translation(struct ssb_device *dev); extern int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask); +#ifdef CONFIG_SSB_PCIHOST +/* PCI-host wrapper driver */ +extern int ssb_pcihost_register(struct pci_driver *driver); +static inline void ssb_pcihost_unregister(struct pci_driver *driver) +{ + pci_unregister_driver(driver); +} +#endif /* CONFIG_SSB_PCIHOST */ + + +/* Bus-Power handling functions. */ +extern int ssb_bus_may_powerdown(struct ssb_bus *bus); +extern int ssb_bus_powerup(struct ssb_bus *bus, int dynamic_pctl); + + /* Various helper functions */ extern u32 ssb_admatch_base(u32 adm); extern u32 ssb_admatch_size(u32 adm); diff --git a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_chipcommon.h b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_chipcommon.h index e0c0e61b80..8856590230 100644 --- a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_chipcommon.h +++ b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_chipcommon.h @@ -124,8 +124,8 @@ #define SSB_CHIPCO_GPIOOUT 0x0064 #define SSB_CHIPCO_GPIOOUTEN 0x0068 #define SSB_CHIPCO_GPIOCTL 0x006C -#define SSB_CHIPCO_GPIOINTPOL 0x0070 -#define SSB_CHIPCO_GPIOINTMASK 0x0074 +#define SSB_CHIPCO_GPIOPOL 0x0070 +#define SSB_CHIPCO_GPIOIRQ 0x0074 #define SSB_CHIPCO_WATCHDOG 0x0080 #define SSB_CHIPCO_GPIOTIMER 0x0088 /* LED powersave (corerev >= 16) */ #define SSB_CHIPCO_GPIOTIMER_ONTIME_SHIFT 16 @@ -364,8 +364,6 @@ extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state); extern void ssb_chipco_resume(struct ssb_chipcommon *cc); -extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, u32 chip_id, - u32 *rate, u32 *plltype, u32 *n, u32 *m); extern void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, u32 *plltype, u32 *n, u32 *m); extern void ssb_chipco_timing_init(struct ssb_chipcommon *cc, @@ -380,47 +378,6 @@ enum ssb_clkmode { extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, enum ssb_clkmode mode); - -/* GPIO functions */ -static inline u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, - u32 mask) -{ - return ssb_read32(cc->dev, SSB_CHIPCO_GPIOIN) & mask; -} - -static inline u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, - u32 mask, u32 value) -{ - return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOOUT, mask, value); -} - -static inline u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, - u32 mask, u32 value) -{ - return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOOUTEN, mask, value); -} - -static inline u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, - u32 mask, u32 value) -{ - return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOCTL, mask, value); -} - -static inline u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, - u32 mask, u32 value) -{ - return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOINTMASK, mask, value); -} - -static inline u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, - u32 mask, u32 value) -{ - return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOINTPOL, mask, value); -} -/* TODO: GPIO reservation */ - -extern int ssb_chipco_watchdog(struct ssb_chipcommon *cc, uint ticks); - #ifdef CONFIG_SSB_SERIAL extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc, struct ssb_serial_port *ports); diff --git a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_extif.h b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_extif.h index 63add56620..278a637e86 100644 --- a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_extif.h +++ b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_extif.h @@ -159,37 +159,5 @@ struct ssb_extif { #define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */ -/* GPIO functions */ -static inline u32 ssb_extif_gpio_in(struct ssb_extif *extif, - u32 mask) -{ - return ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN) & mask; -} - -static inline u32 ssb_extif_gpio_out(struct ssb_extif *extif, - u32 mask, u32 value) -{ - return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_OUT(0), mask, value); -} - -static inline u32 ssb_extif_gpio_outen(struct ssb_extif *extif, - u32 mask, u32 value) -{ - return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_OUTEN(0), mask, value); -} - -static inline u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, - u32 mask, u32 value) -{ - return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_INTPOL, mask, value); -} - -static inline u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, - u32 mask, u32 value) -{ - return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_INTMASK, mask, value); -} - - #endif /* __KERNEL__ */ #endif /* LINUX_SSB_EXTIFCORE_H_ */ diff --git a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_mips.h b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_mips.h index 61c766550c..91f2373be4 100644 --- a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_mips.h +++ b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_driver_mips.h @@ -3,7 +3,7 @@ #ifdef __KERNEL__ -#ifdef CONFIG_BCM947XX +#ifdef CONFIG_SSB_DRIVER_MIPS struct ssb_device; @@ -22,17 +22,16 @@ struct ssb_mipscore { int nr_serial_ports; struct ssb_serial_port serial_ports[4]; - int flash_buswidth; u32 flash_window; u32 flash_window_size; }; extern void ssb_mipscore_init(struct ssb_mipscore *mcore); -extern u32 ssb_cpu_clock(struct ssb_mipscore *mcore); + extern unsigned int ssb_mips_irq(struct ssb_device *dev); -#else /* CONFIG_BCM947XX */ +#else /* CONFIG_SSB_DRIVER_MIPS */ struct ssb_mipscore { }; @@ -42,7 +41,7 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) { } -#endif /* CONFIG_BCM947XX */ +#endif /* CONFIG_SSB_DRIVER_MIPS */ #endif /* __KERNEL__ */ #endif /* LINUX_SSB_MIPSCORE_H_ */ diff --git a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_regs.h b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_regs.h index 6bb40464d4..e1c7ff78a8 100644 --- a/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_regs.h +++ b/target/linux/brcm47xx-2.6/files/include/linux/ssb/ssb_regs.h @@ -96,7 +96,8 @@ #define SSB_INTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */ #define SSB_TMSLOW 0x0F98 /* SB Target State Low */ #define SSB_TMSLOW_RESET 0x00000001 /* Reset */ -#define SSB_TMSLOW_REJECT 0x00000002 /* Reject */ +#define SSB_TMSLOW_REJECT_22 0x00000002 /* Reject (Backplane rev 2.2) */ +#define SSB_TMSLOW_REJECT_23 0x00000004 /* Reject (Backplane rev 2.3) */ #define SSB_TMSLOW_CLOCK 0x00010000 /* Clock Enable */ #define SSB_TMSLOW_FGC 0x00020000 /* Force Gated Clocks On */ #define SSB_TMSLOW_PE 0x40000000 /* Power Management Enable */ diff --git a/target/linux/brcm47xx-2.6/patches/200-b44_ssb_fixup.patch b/target/linux/brcm47xx-2.6/patches/200-b44_ssb_fixup.patch new file mode 100644 index 0000000000..816d7e18b6 --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches/200-b44_ssb_fixup.patch @@ -0,0 +1,256 @@ +Index: linux-2.6.22-rc4/drivers/net/b44.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/net/b44.c 2007-06-10 21:33:15.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/net/b44.c 2007-06-10 21:33:23.000000000 +0100 +@@ -128,7 +128,7 @@ + unsigned long offset, + enum dma_data_direction dir) + { +- dma_sync_single_range_for_device(&sdev->dev, dma_base, ++ dma_sync_single_range_for_device(sdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); + } +@@ -138,7 +138,7 @@ + unsigned long offset, + enum dma_data_direction dir) + { +- dma_sync_single_range_for_cpu(&sdev->dev, dma_base, ++ dma_sync_single_range_for_cpu(sdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); + } +@@ -563,7 +563,7 @@ + + BUG_ON(skb == NULL); + +- dma_unmap_single(&bp->sdev->dev, ++ dma_unmap_single(bp->sdev->dev, + pci_unmap_addr(rp, mapping), + skb->len, + DMA_TO_DEVICE); +@@ -603,7 +603,7 @@ + if (skb == NULL) + return -ENOMEM; + +- mapping = dma_map_single(&bp->sdev->dev, skb->data, ++ mapping = dma_map_single(bp->sdev->dev, skb->data, + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); + +@@ -613,18 +613,18 @@ + mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { + /* Sigh... */ + if (!dma_mapping_error(mapping)) +- dma_unmap_single(&bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); ++ dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + skb = __dev_alloc_skb(RX_PKT_BUF_SZ,GFP_DMA); + if (skb == NULL) + return -ENOMEM; +- mapping = dma_map_single(&bp->sdev->dev, skb->data, ++ mapping = dma_map_single(bp->sdev->dev, skb->data, + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); + if (dma_mapping_error(mapping) || + mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { + if (!dma_mapping_error(mapping)) +- dma_unmap_single(&bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); ++ dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + return -ENOMEM; + } +@@ -702,7 +702,7 @@ + dest_idx * sizeof(dest_desc), + DMA_BIDIRECTIONAL); + +- dma_sync_single_for_device(&bp->sdev->dev, le32_to_cpu(src_desc->addr), ++ dma_sync_single_for_device(bp->sdev->dev, le32_to_cpu(src_desc->addr), + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); + } +@@ -724,7 +724,7 @@ + struct rx_header *rh; + u16 len; + +- dma_sync_single_for_cpu(&bp->sdev->dev, map, ++ dma_sync_single_for_cpu(bp->sdev->dev, map, + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); + rh = (struct rx_header *) skb->data; +@@ -758,7 +758,7 @@ + skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod); + if (skb_size < 0) + goto drop_it; +- dma_unmap_single(&bp->sdev->dev, map, ++ dma_unmap_single(bp->sdev->dev, map, + skb_size, DMA_FROM_DEVICE); + /* Leave out rx_header */ + skb_put(skb, len+bp->rx_offset); +@@ -931,22 +931,22 @@ + goto err_out; + } + +- mapping = dma_map_single(&bp->sdev->dev, skb->data, len, DMA_TO_DEVICE); ++ mapping = dma_map_single(bp->sdev->dev, skb->data, len, DMA_TO_DEVICE); + if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { + /* Chip can't handle DMA to/from >1GB, use bounce buffer */ + if (!dma_mapping_error(mapping)) +- dma_unmap_single(&bp->sdev->dev, mapping, len, DMA_TO_DEVICE); ++ dma_unmap_single(bp->sdev->dev, mapping, len, DMA_TO_DEVICE); + + bounce_skb = __dev_alloc_skb(TX_PKT_BUF_SZ, + GFP_ATOMIC|GFP_DMA); + if (!bounce_skb) + goto err_out; + +- mapping = dma_map_single(&bp->sdev->dev, bounce_skb->data, ++ 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)) +- dma_unmap_single(&bp->sdev->dev, mapping, ++ dma_unmap_single(bp->sdev->dev, mapping, + len, DMA_TO_DEVICE); + dev_kfree_skb_any(bounce_skb); + goto err_out; +@@ -1046,7 +1046,7 @@ + + if (rp->skb == NULL) + continue; +- dma_unmap_single(&bp->sdev->dev, ++ dma_unmap_single(bp->sdev->dev, + pci_unmap_addr(rp, mapping), + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); +@@ -1060,7 +1060,7 @@ + + if (rp->skb == NULL) + continue; +- dma_unmap_single(&bp->sdev->dev, ++ dma_unmap_single(bp->sdev->dev, + pci_unmap_addr(rp, mapping), + rp->skb->len, + DMA_TO_DEVICE); +@@ -1085,12 +1085,12 @@ + memset(bp->tx_ring, 0, B44_TX_RING_BYTES); + + if (bp->flags & B44_FLAG_RX_RING_HACK) +- dma_sync_single_for_device(&bp->sdev->dev, bp->rx_ring_dma, ++ 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->sdev->dev, bp->tx_ring_dma, ++ dma_sync_single_for_device(bp->sdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); + +@@ -1112,24 +1112,24 @@ + bp->tx_buffers = NULL; + if (bp->rx_ring) { + if (bp->flags & B44_FLAG_RX_RING_HACK) { +- dma_unmap_single(&bp->sdev->dev, bp->rx_ring_dma, ++ dma_unmap_single(bp->sdev->dev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); + kfree(bp->rx_ring); + } else +- dma_free_coherent(&bp->sdev->dev, 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->sdev->dev, bp->tx_ring_dma, ++ dma_unmap_single(bp->sdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); + kfree(bp->tx_ring); + } else +- dma_free_coherent(&bp->sdev->dev, 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; +@@ -1155,7 +1155,7 @@ + goto out_err; + + size = DMA_TABLE_BYTES; +- bp->rx_ring = dma_alloc_coherent(&bp->sdev->dev, size, &bp->rx_ring_dma, GFP_ATOMIC); ++ 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 +@@ -1167,7 +1167,7 @@ + if (!rx_ring) + goto out_err; + +- rx_ring_dma = dma_map_single(&bp->sdev->dev, rx_ring, ++ rx_ring_dma = dma_map_single(bp->sdev->dev, rx_ring, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); + +@@ -1182,7 +1182,7 @@ + bp->flags |= B44_FLAG_RX_RING_HACK; + } + +- bp->tx_ring = dma_alloc_coherent(&bp->sdev->dev, size, &bp->tx_ring_dma, GFP_ATOMIC); ++ 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 dma_alloc_coherent + insisting on use of GFP_DMA, which is more restrictive +@@ -1194,7 +1194,7 @@ + if (!tx_ring) + goto out_err; + +- tx_ring_dma = dma_map_single(&bp->sdev->dev, tx_ring, ++ tx_ring_dma = dma_map_single(bp->sdev->dev, tx_ring, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); + +@@ -2314,13 +2314,13 @@ + + dev = alloc_etherdev(sizeof(*bp)); + if (!dev) { +- dev_err(&sdev->dev, "Etherdev alloc failed, aborting.\n"); ++ dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n"); + err = -ENOMEM; + goto out; + } + + SET_MODULE_OWNER(dev); +- SET_NETDEV_DEV(dev,&sdev->dev); ++ SET_NETDEV_DEV(dev,sdev->dev); + + /* No interesting netdevice features in this card... */ + dev->features |= 0; +@@ -2358,7 +2358,7 @@ + + err = b44_get_invariants(bp); + if (err) { +- dev_err(&sdev->dev, ++ dev_err(sdev->dev, + "Problem fetching invariants of chip, aborting.\n"); + goto err_out_free_dev; + } +@@ -2379,7 +2379,7 @@ + + err = register_netdev(dev); + if (err) { +- dev_err(&sdev->dev, "Cannot register net device, aborting.\n"); ++ dev_err(sdev->dev, "Cannot register net device, aborting.\n"); + goto out; + } + +@@ -2458,7 +2458,6 @@ + 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; + } + diff --git a/target/linux/brcm47xx-2.6/patches/205-ssb_integrate.patch b/target/linux/brcm47xx-2.6/patches/205-ssb_integrate.patch new file mode 100644 index 0000000000..67882454d8 --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches/205-ssb_integrate.patch @@ -0,0 +1,78 @@ +Index: linux-2.6.22-rc4/drivers/usb/host/Kconfig +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/usb/host/Kconfig 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/usb/host/Kconfig 2007-06-10 21:33:24.000000000 +0100 +@@ -142,6 +142,19 @@ + Enables support for PCI-bus plug-in USB controller cards. + If unsure, say Y. + ++config USB_OHCI_HCD_SSB ++ bool "OHCI support for the Broadcom SSB OHCI core (embedded systems only)" ++ depends on USB_OHCI_HCD && ((USB_OHCI_HCD=m && SSB) || (USB_OHCI_HCD=y && SSB=y)) && EXPERIMENTAL ++ default n ++ ---help--- ++ Support for the Sonics Silicon Backplane (SSB) attached ++ Broadcom USB OHCI core. ++ ++ This device is only 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.22-rc4/drivers/usb/host/ohci-hcd.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/usb/host/ohci-hcd.c 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/usb/host/ohci-hcd.c 2007-06-10 21:33:24.000000000 +0100 +@@ -920,11 +920,17 @@ + #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_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 + +@@ -972,10 +978,20 @@ + 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 +@@ -1001,6 +1017,9 @@ + + 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 diff --git a/target/linux/brcm47xx-2.6/patches/210-ssb_merge.patch b/target/linux/brcm47xx-2.6/patches/210-ssb_merge.patch new file mode 100644 index 0000000000..21986b3426 --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches/210-ssb_merge.patch @@ -0,0 +1,421 @@ +Index: linux-2.6.22-rc4/drivers/ssb/driver_chipcommon.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/ssb/driver_chipcommon.c 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/ssb/driver_chipcommon.c 2007-06-10 21:33:25.000000000 +0100 +@@ -264,6 +264,31 @@ + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); + } + ++/* TODO: These two functions are a clear candidate for merging, but one gets ++ * the processor clock, and the other gets the bus clock. ++ */ ++void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, ++ u32 *plltype, u32 *n, u32 *m) ++{ ++ *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); ++ *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); ++ switch (*plltype) { ++ case SSB_PLLTYPE_2: ++ case SSB_PLLTYPE_4: ++ case SSB_PLLTYPE_6: ++ case SSB_PLLTYPE_7: ++ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); ++ break; ++ case SSB_PLLTYPE_3: ++ /* 5350 uses m2 to control mips */ ++ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); ++ break; ++ default: ++ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); ++ break; ++ } ++} ++ + void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m) + { +@@ -400,3 +425,13 @@ + return nr_ports; + } + #endif /* CONFIG_SSB_SERIAL */ ++ ++/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ ++int ++ssb_chipco_watchdog(struct ssb_chipcommon *cc, uint ticks) ++{ ++ /* instant NMI */ ++ chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); ++ return 0; ++} ++EXPORT_SYMBOL(ssb_chipco_watchdog); +Index: linux-2.6.22-rc4/drivers/ssb/driver_mipscore.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/ssb/driver_mipscore.c 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/ssb/driver_mipscore.c 2007-06-10 21:33:25.000000000 +0100 +@@ -4,6 +4,7 @@ + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> ++ * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org> + * + * Licensed under the GNU/GPL. See COPYING for details. + */ +@@ -31,6 +32,16 @@ + ssb_write32(mcore->dev, offset, value); + } + ++static inline u32 extif_read32(struct ssb_extif *extif, u16 offset) ++{ ++ return ssb_read32(extif->dev, offset); ++} ++ ++static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value) ++{ ++ ssb_write32(extif->dev, offset, value); ++} ++ + static const u32 ipsflag_irq_mask[] = { + 0, + SSB_IPSFLAG_IRQ1, +@@ -118,9 +129,9 @@ + } + + /* XXX: leave here or move into separate extif driver? */ +-static int ssb_extif_serial_init(struct ssb_device *dev, struct ssb_serial_ports *ports) ++static int ssb_extif_serial_init(struct ssb_extif *dev, struct ssb_serial_port *ports) + { +- ++ return 0; + } + + +@@ -174,23 +185,76 @@ + { + struct ssb_bus *bus = mcore->dev->bus; + ++ mcore->flash_buswidth = 2; + if (bus->chipco.dev) { + mcore->flash_window = 0x1c000000; +- mcore->flash_window_size = 0x800000; ++ mcore->flash_window_size = 0x02000000; ++ if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG) ++ & SSB_CHIPCO_CFG_DS16) == 0) ++ mcore->flash_buswidth = 1; + } else { + mcore->flash_window = 0x1fc00000; +- mcore->flash_window_size = 0x400000; ++ mcore->flash_window_size = 0x00400000; + } + } + ++static void ssb_extif_timing_init(struct ssb_extif *extif, u32 ns) ++{ ++ u32 tmp; ++ ++ /* Initialize extif so we can get to the LEDs and external UART */ ++ extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN); ++ ++ /* Set timing for the flash */ ++ tmp = ceildiv(10, ns) << SSB_PROG_WCNT_3_SHIFT; ++ tmp |= ceildiv(40, ns) << SSB_PROG_WCNT_1_SHIFT; ++ tmp |= ceildiv(120, ns); ++ extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); ++ ++ /* Set programmable interface timing for external uart */ ++ tmp = ceildiv(10, ns) << SSB_PROG_WCNT_3_SHIFT; ++ tmp |= ceildiv(20, ns) << SSB_PROG_WCNT_2_SHIFT; ++ tmp |= ceildiv(100, ns) << SSB_PROG_WCNT_1_SHIFT; ++ tmp |= ceildiv(120, ns); ++ extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); ++} + +-static void ssb_cpu_clock(struct ssb_mipscore *mcore) ++static inline void ssb_extif_get_clockcontrol(struct ssb_extif *extif, ++ u32 *pll_type, u32 *n, u32 *m) + { ++ *pll_type = SSB_PLLTYPE_1; ++ *n = extif_read32(extif, SSB_EXTIF_CLOCK_N); ++ *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB); + } + +-void ssb_mipscore_init(struct ssb_mipscore *mcore) ++u32 ssb_cpu_clock(struct ssb_mipscore *mcore) + { + struct ssb_bus *bus = mcore->dev->bus; ++ u32 pll_type, n, m, rate = 0; ++ ++ if (bus->extif.dev) { ++ ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m); ++ } else if (bus->chipco.dev) { ++ ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m); ++ } else ++ return 0; ++ ++ if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) { ++ rate = 200000000; ++ } else { ++ rate = ssb_calc_clock_rate(pll_type, n, m); ++ } ++ ++ if (pll_type == SSB_PLLTYPE_6) { ++ rate *= 2; ++ } ++ ++ return rate; ++} ++ ++void ssb_mipscore_init(struct ssb_mipscore *mcore) ++{ ++ struct ssb_bus *bus; + struct ssb_device *dev; + unsigned long hz, ns; + unsigned int irq, i; +@@ -198,6 +262,8 @@ + if (!mcore->dev) + return; /* We don't have a MIPS core */ + ++ bus = mcore->dev->bus; ++ + ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n"); + + hz = ssb_clockspeed(bus); +@@ -205,28 +271,9 @@ + hz = 100000000; + ns = 1000000000 / hz; + +-//TODO +-#if 0 +- if (have EXTIF) { +- /* Initialize extif so we can get to the LEDs and external UART */ +- W_REG(&eir->prog_config, CF_EN); +- +- /* Set timing for the flash */ +- tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */ +- tmp = tmp | (CEIL(40, ns) << FW_W1_SHIFT); /* W1 = 40nS */ +- tmp = tmp | CEIL(120, ns); /* W0 = 120nS */ +- W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */ +- +- /* Set programmable interface timing for external uart */ +- tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */ +- tmp = tmp | (CEIL(20, ns) << FW_W2_SHIFT); /* W2 = 20nS */ +- tmp = tmp | (CEIL(100, ns) << FW_W1_SHIFT); /* W1 = 100nS */ +- tmp = tmp | CEIL(120, ns); /* W0 = 120nS */ +- W_REG(&eir->prog_waitcount, tmp); +- } +- else... chipcommon +-#endif +- if (bus->chipco.dev) ++ if (bus->extif.dev) ++ ssb_extif_timing_init(&bus->extif, ns); ++ else if (bus->chipco.dev) + ssb_chipco_timing_init(&bus->chipco, ns); + + /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */ +@@ -256,3 +303,5 @@ + ssb_mips_serial_init(mcore); + ssb_mips_flash_detect(mcore); + } ++ ++EXPORT_SYMBOL(ssb_mips_irq); +Index: linux-2.6.22-rc4/drivers/ssb/driver_pcicore.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/ssb/driver_pcicore.c 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/ssb/driver_pcicore.c 2007-06-10 21:33:25.000000000 +0100 +@@ -93,6 +93,9 @@ + + /* 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 */ ++ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8); + } + DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); + +@@ -110,7 +113,7 @@ + + if (unlikely(pc->cardbusmode && dev > 1)) + goto out; +- if (bus == 0) { ++ if (bus == 0) {//FIXME busnumber ok? + /* Type 0 transaction */ + if (unlikely(dev >= SSB_PCI_SLOT_MAX)) + goto out; +@@ -224,7 +227,7 @@ + val = *((const u32 *)buf); + break; + } +- writel(*((const u32 *)buf), mmio); ++ writel(val, mmio); + + err = 0; + unmap: +@@ -307,6 +310,8 @@ + udelay(150); + val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */ + pcicore_write32(pc, SSB_PCICORE_CTL, val); ++ val = SSB_PCICORE_ARBCTL_INTERN; ++ pcicore_write32(pc, SSB_PCICORE_ARBCTL, val); + udelay(1); + + //TODO cardbus mode +@@ -336,6 +341,7 @@ + * 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)); ++ mdelay(300); + register_pci_controller(&ssb_pcicore_controller); + } + +Index: linux-2.6.22-rc4/include/linux/ssb/ssb_driver_chipcommon.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb_driver_chipcommon.h 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/include/linux/ssb/ssb_driver_chipcommon.h 2007-06-10 21:33:25.000000000 +0100 +@@ -364,6 +364,8 @@ + extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state); + extern void ssb_chipco_resume(struct ssb_chipcommon *cc); + ++extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, ++ u32 *plltype, u32 *n, u32 *m); + extern void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m); + extern void ssb_chipco_timing_init(struct ssb_chipcommon *cc, +@@ -378,6 +380,46 @@ + extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, + enum ssb_clkmode mode); + ++/* GPIO functions */ ++static inline u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, ++ u32 mask) ++{ ++ return ssb_read32(cc->dev, SSB_CHIPCO_GPIOIN) & mask; ++} ++ ++static inline u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOOUT, mask, value); ++} ++ ++static inline u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOOUTEN, mask, value); ++} ++ ++static inline u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOCTL, mask, value); ++} ++ ++static inline u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOIRQ, mask, value); ++} ++ ++static inline u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOPOL, mask, value); ++} ++/* TODO: GPIO reservation */ ++ ++extern int ssb_chipco_watchdog(struct ssb_chipcommon *cc, uint ticks); ++ + #ifdef CONFIG_SSB_SERIAL + extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc, + struct ssb_serial_port *ports); +Index: linux-2.6.22-rc4/include/linux/ssb/ssb_driver_extif.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb_driver_extif.h 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/include/linux/ssb/ssb_driver_extif.h 2007-06-10 21:33:25.000000000 +0100 +@@ -158,6 +158,36 @@ + /* watchdog */ + #define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */ + ++/* GPIO functions */ ++static inline u32 ssb_extif_gpio_in(struct ssb_extif *extif, ++ u32 mask) ++{ ++ return ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN) & mask; ++} ++ ++static inline u32 ssb_extif_gpio_out(struct ssb_extif *extif, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_OUT(0), mask, value); ++} ++ ++static inline u32 ssb_extif_gpio_outen(struct ssb_extif *extif, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_OUTEN(0), mask, value); ++} ++ ++static inline u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_INTPOL, mask, value); ++} ++ ++static inline u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_INTMASK, mask, value); ++} + + #endif /* __KERNEL__ */ + #endif /* LINUX_SSB_EXTIFCORE_H_ */ +Index: linux-2.6.22-rc4/include/linux/ssb/ssb_driver_mips.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb_driver_mips.h 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/include/linux/ssb/ssb_driver_mips.h 2007-06-10 21:33:25.000000000 +0100 +@@ -22,11 +22,13 @@ + int nr_serial_ports; + struct ssb_serial_port serial_ports[4]; + ++ int flash_buswidth; + u32 flash_window; + u32 flash_window_size; + }; + + extern void ssb_mipscore_init(struct ssb_mipscore *mcore); ++extern u32 ssb_cpu_clock(struct ssb_mipscore *mcore); + + extern unsigned int ssb_mips_irq(struct ssb_device *dev); + +Index: linux-2.6.22-rc4/include/linux/ssb/ssb.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb.h 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/include/linux/ssb/ssb.h 2007-06-10 21:33:25.000000000 +0100 +@@ -263,6 +263,12 @@ + #define SSB_CHIPPACK_BCM4712M 2 /* Medium 225pin 4712 */ + #define SSB_CHIPPACK_BCM4712L 0 /* Large 340pin 4712 */ + ++static inline u16 ssb_read16(struct ssb_device *dev, u16 offset); ++static inline u32 ssb_read32(struct ssb_device *dev, u16 offset); ++static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value); ++static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value); ++static inline u32 ssb_write32_masked(struct ssb_device *dev, u16 offset, u32 mask, u32 value); ++ + #include <linux/ssb/ssb_driver_chipcommon.h> + #include <linux/ssb/ssb_driver_mips.h> + #include <linux/ssb/ssb_driver_extif.h> +@@ -369,6 +375,16 @@ + dev->ops->write32(dev, offset, value); + } + ++static inline u32 ssb_write32_masked(struct ssb_device *dev, ++ u16 offset, ++ u32 mask, ++ u32 value) ++{ ++ value &= mask; ++ value |= ssb_read32(dev, offset) & ~mask; ++ ssb_write32(dev, offset, value); ++ return value; ++} + + /* Translation (routing) bits that need to be ORed to DMA + * addresses before they are given to a device. */ |