diff options
author | noz <noz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-06-21 20:10:50 +0000 |
---|---|---|
committer | noz <noz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-06-21 20:10:50 +0000 |
commit | 6546ee2d5f04d335314782ca0577901b7c2d83b0 (patch) | |
tree | b8c2124cfa4e97458937733d65bfac60ff625457 /target/linux/brcm47xx-2.6/files/drivers/ssb | |
parent | ebd093f2fa1855b10efdc70772e1024dd37b1a4a (diff) |
brcm43xx: update SSB driver
* files/ now contains the wireless-dev tree version
* patches/210-ssb_merge is nbd's subsequent changes
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@7691 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/brcm47xx-2.6/files/drivers/ssb')
10 files changed, 765 insertions, 221 deletions
diff --git a/target/linux/brcm47xx-2.6/files/drivers/ssb/Kconfig b/target/linux/brcm47xx-2.6/files/drivers/ssb/Kconfig index 09330dfa6..03c494586 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 9f85d225d..9a2b379fb 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 a17910947..8e511c77b 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 7b3880ab0..67d10178b 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 3ad97036f..a59dff083 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 2ee13d2d3..a2d22312c 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 811af789e..fcd8e871c 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 000000000..82a10abef --- /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 9e4a121c1..feaf1e57d 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 59645f5a6..ae1fc0633 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. */ |