diff options
Diffstat (limited to 'drivers/bcma')
-rw-r--r-- | drivers/bcma/Kconfig | 13 | ||||
-rw-r--r-- | drivers/bcma/Makefile | 2 | ||||
-rw-r--r-- | drivers/bcma/bcma_private.h | 16 | ||||
-rw-r--r-- | drivers/bcma/core.c | 2 | ||||
-rw-r--r-- | drivers/bcma/driver_chipcommon.c | 53 | ||||
-rw-r--r-- | drivers/bcma/driver_chipcommon_pmu.c | 191 | ||||
-rw-r--r-- | drivers/bcma/driver_mips.c | 256 | ||||
-rw-r--r-- | drivers/bcma/driver_pci.c | 16 | ||||
-rw-r--r-- | drivers/bcma/host_soc.c | 183 | ||||
-rw-r--r-- | drivers/bcma/main.c | 82 | ||||
-rw-r--r-- | drivers/bcma/scan.c | 348 | ||||
-rw-r--r-- | drivers/bcma/sprom.c | 15 |
12 files changed, 1053 insertions, 124 deletions
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index ae0a02e1b808..c1172dafdffa 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -33,6 +33,19 @@ config BCMA_DRIVER_PCI_HOSTMODE help PCI core hostmode operation (external PCI bus). +config BCMA_HOST_SOC + bool + depends on BCMA_DRIVER_MIPS + +config BCMA_DRIVER_MIPS + bool "BCMA Broadcom MIPS core driver" + depends on BCMA && MIPS + help + Driver for the Broadcom MIPS core attached to Broadcom specific + Advanced Microcontroller Bus. + + If unsure, say N + config BCMA_DEBUG bool "BCMA debugging" depends on BCMA diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile index a2161cceafb9..82de24e5340c 100644 --- a/drivers/bcma/Makefile +++ b/drivers/bcma/Makefile @@ -2,7 +2,9 @@ bcma-y += main.o scan.o core.o sprom.o bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o bcma-y += driver_pci.o bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o +bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o +bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o obj-$(CONFIG_BCMA) += bcma.o ccflags-$(CONFIG_BCMA_DEBUG) := -DDEBUG diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index e02ff21835c9..30a3085d3354 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -15,13 +15,29 @@ struct bcma_bus; /* main.c */ int bcma_bus_register(struct bcma_bus *bus); void bcma_bus_unregister(struct bcma_bus *bus); +int __init bcma_bus_early_register(struct bcma_bus *bus, + struct bcma_device *core_cc, + struct bcma_device *core_mips); /* scan.c */ int bcma_bus_scan(struct bcma_bus *bus); +int __init bcma_bus_scan_early(struct bcma_bus *bus, + struct bcma_device_id *match, + struct bcma_device *core); +void bcma_init_bus(struct bcma_bus *bus); /* sprom.c */ int bcma_sprom_get(struct bcma_bus *bus); +/* driver_chipcommon.c */ +#ifdef CONFIG_BCMA_DRIVER_MIPS +void bcma_chipco_serial_init(struct bcma_drv_cc *cc); +#endif /* CONFIG_BCMA_DRIVER_MIPS */ + +/* driver_chipcommon_pmu.c */ +u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc); +u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc); + #ifdef CONFIG_BCMA_HOST_PCI /* host_pci.c */ extern int __init bcma_host_pci_init(void); diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c index 4a04a49cc06d..189a97b51be9 100644 --- a/drivers/bcma/core.c +++ b/drivers/bcma/core.c @@ -110,6 +110,8 @@ EXPORT_SYMBOL_GPL(bcma_core_pll_ctl); u32 bcma_core_dma_translation(struct bcma_device *core) { switch (core->bus->hosttype) { + case BCMA_HOSTTYPE_SOC: + return 0; case BCMA_HOSTTYPE_PCI: if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64) return BCMA_DMA_TRANSLATION_DMA64_CMT; diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index 851e05bc948a..47cce9d69630 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c @@ -26,6 +26,9 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) u32 leddc_on = 10; u32 leddc_off = 90; + if (cc->setup_done) + return; + if (cc->core->id.rev >= 11) cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); @@ -52,6 +55,8 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) | (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT))); } + + cc->setup_done = true; } /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ @@ -101,3 +106,51 @@ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value) { return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value); } + +#ifdef CONFIG_BCMA_DRIVER_MIPS +void bcma_chipco_serial_init(struct bcma_drv_cc *cc) +{ + unsigned int irq; + u32 baud_base; + u32 i; + unsigned int ccrev = cc->core->id.rev; + struct bcma_serial_port *ports = cc->serial_ports; + + if (ccrev >= 11 && ccrev != 15) { + /* Fixed ALP clock */ + baud_base = bcma_pmu_alp_clock(cc); + if (ccrev >= 21) { + /* Turn off UART clock before switching clocksource. */ + bcma_cc_write32(cc, BCMA_CC_CORECTL, + bcma_cc_read32(cc, BCMA_CC_CORECTL) + & ~BCMA_CC_CORECTL_UARTCLKEN); + } + /* Set the override bit so we don't divide it */ + bcma_cc_write32(cc, BCMA_CC_CORECTL, + bcma_cc_read32(cc, BCMA_CC_CORECTL) + | BCMA_CC_CORECTL_UARTCLK0); + if (ccrev >= 21) { + /* Re-enable the UART clock. */ + bcma_cc_write32(cc, BCMA_CC_CORECTL, + bcma_cc_read32(cc, BCMA_CC_CORECTL) + | BCMA_CC_CORECTL_UARTCLKEN); + } + } else { + pr_err("serial not supported on this device ccrev: 0x%x\n", + ccrev); + return; + } + + irq = bcma_core_mips_irq(cc->core); + + /* Determine the registers of the UARTs */ + cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART); + for (i = 0; i < cc->nr_serial_ports; i++) { + ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA + + (i * 256); + ports[i].irq = irq; + ports[i].baud_base = baud_base; + ports[i].reg_shift = 0; + } +} +#endif /* CONFIG_BCMA_DRIVER_MIPS */ diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index fcc63db0ce75..2968d809d49f 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c @@ -11,20 +11,47 @@ #include "bcma_private.h" #include <linux/bcma/bcma.h> -static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, - u32 offset, u32 mask, u32 set) +static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset) { - u32 value; + bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset); + bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR); + return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA); +} - bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); +void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value) +{ + bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset); + bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR); + bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value); +} +EXPORT_SYMBOL_GPL(bcma_chipco_pll_write); + +void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask, + u32 set) +{ + bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset); + bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR); + bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set); +} +EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset); + +void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, + u32 offset, u32 mask, u32 set) +{ bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset); bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); - value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA); - value &= mask; - value |= set; - bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value); - bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA); + bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set); +} +EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset); + +void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask, + u32 set) +{ + bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset); + bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR); + bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set); } +EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset); static void bcma_pmu_pll_init(struct bcma_drv_cc *cc) { @@ -83,6 +110,24 @@ void bcma_pmu_swreg_init(struct bcma_drv_cc *cc) } } +/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */ +void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable) +{ + struct bcma_bus *bus = cc->core->bus; + u32 val; + + val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL); + if (enable) { + val |= BCMA_CHIPCTL_4331_EXTPA_EN; + if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11) + val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5; + } else { + val &= ~BCMA_CHIPCTL_4331_EXTPA_EN; + val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5; + } + bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val); +} + void bcma_pmu_workarounds(struct bcma_drv_cc *cc) { struct bcma_bus *bus = cc->core->bus; @@ -92,7 +137,7 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc) bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7); break; case 0x4331: - pr_err("Enabling Ext PA lines not implemented\n"); + /* BCM4331 workaround is SPROM-related, we put it in sprom.c */ break; case 43224: if (bus->chipinfo.rev == 0) { @@ -136,3 +181,129 @@ void bcma_pmu_init(struct bcma_drv_cc *cc) bcma_pmu_swreg_init(cc); bcma_pmu_workarounds(cc); } + +u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + + switch (bus->chipinfo.id) { + case 0x4716: + case 0x4748: + case 47162: + case 0x4313: + case 0x5357: + case 0x4749: + case 53572: + /* always 20Mhz */ + return 20000 * 1000; + case 0x5356: + case 0x5300: + /* always 25Mhz */ + return 25000 * 1000; + default: + pr_warn("No ALP clock specified for %04X device, " + "pmu rev. %d, using default %d Hz\n", + bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK); + } + return BCMA_CC_PMU_ALP_CLOCK; +} + +/* Find the output of the "m" pll divider given pll controls that start with + * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc. + */ +static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m) +{ + u32 tmp, div, ndiv, p1, p2, fc; + struct bcma_bus *bus = cc->core->bus; + + BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0)); + + BUG_ON(!m || m > 4); + + if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) { + /* Detect failure in clock setting */ + tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); + if (tmp & 0x40000) + return 133 * 1000000; + } + + tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF); + p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT; + p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT; + + tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF); + div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) & + BCMA_CC_PPL_MDIV_MASK; + + tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF); + ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT; + + /* Do calculation in Mhz */ + fc = bcma_pmu_alp_clock(cc) / 1000000; + fc = (p1 * ndiv * fc) / p2; + + /* Return clock in Hertz */ + return (fc / div) * 1000000; +} + +/* query bus clock frequency for PMU-enabled chipcommon */ +u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + + switch (bus->chipinfo.id) { + case 0x4716: + case 0x4748: + case 47162: + return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0, + BCMA_CC_PMU5_MAINPLL_SSB); + case 0x5356: + return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0, + BCMA_CC_PMU5_MAINPLL_SSB); + case 0x5357: + case 0x4749: + return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0, + BCMA_CC_PMU5_MAINPLL_SSB); + case 0x5300: + return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0, + BCMA_CC_PMU5_MAINPLL_SSB); + case 53572: + return 75000000; + default: + pr_warn("No backplane clock specified for %04X device, " + "pmu rev. %d, using default %d Hz\n", + bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK); + } + return BCMA_CC_PMU_HT_CLOCK; +} + +/* query cpu clock frequency for PMU-enabled chipcommon */ +u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + + if (bus->chipinfo.id == 53572) + return 300000000; + + if (cc->pmu.rev >= 5) { + u32 pll; + switch (bus->chipinfo.id) { + case 0x5356: + pll = BCMA_CC_PMU5356_MAINPLL_PLL0; + break; + case 0x5357: + case 0x4749: + pll = BCMA_CC_PMU5357_MAINPLL_PLL0; + break; + default: + pll = BCMA_CC_PMU4716_MAINPLL_PLL0; + break; + } + + /* TODO: if (bus->chipinfo.id == 0x5300) + return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */ + return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU); + } + + return bcma_pmu_get_clockcontrol(cc); +} diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c new file mode 100644 index 000000000000..c3e9dff4224e --- /dev/null +++ b/drivers/bcma/driver_mips.c @@ -0,0 +1,256 @@ +/* + * Broadcom specific AMBA + * Broadcom MIPS32 74K core driver + * + * Copyright 2009, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> + * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com> + * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de> + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" + +#include <linux/bcma/bcma.h> + +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/serial_reg.h> +#include <linux/time.h> + +/* The 47162a0 hangs when reading MIPS DMP registers registers */ +static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev) +{ + return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 && + dev->id.id == BCMA_CORE_MIPS_74K; +} + +/* The 5357b0 hangs when reading USB20H DMP registers */ +static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev) +{ + return (dev->bus->chipinfo.id == 0x5357 || + dev->bus->chipinfo.id == 0x4749) && + dev->bus->chipinfo.pkg == 11 && + dev->id.id == BCMA_CORE_USB20_HOST; +} + +static inline u32 mips_read32(struct bcma_drv_mips *mcore, + u16 offset) +{ + return bcma_read32(mcore->core, offset); +} + +static inline void mips_write32(struct bcma_drv_mips *mcore, + u16 offset, + u32 value) +{ + bcma_write32(mcore->core, offset, value); +} + +static const u32 ipsflag_irq_mask[] = { + 0, + BCMA_MIPS_IPSFLAG_IRQ1, + BCMA_MIPS_IPSFLAG_IRQ2, + BCMA_MIPS_IPSFLAG_IRQ3, + BCMA_MIPS_IPSFLAG_IRQ4, +}; + +static const u32 ipsflag_irq_shift[] = { + 0, + BCMA_MIPS_IPSFLAG_IRQ1_SHIFT, + BCMA_MIPS_IPSFLAG_IRQ2_SHIFT, + BCMA_MIPS_IPSFLAG_IRQ3_SHIFT, + BCMA_MIPS_IPSFLAG_IRQ4_SHIFT, +}; + +static u32 bcma_core_mips_irqflag(struct bcma_device *dev) +{ + u32 flag; + + if (bcma_core_mips_bcm47162a0_quirk(dev)) + return dev->core_index; + if (bcma_core_mips_bcm5357b0_quirk(dev)) + return dev->core_index; + flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30); + + return flag & 0x1F; +} + +/* Get the MIPS IRQ assignment for a specified device. + * If unassigned, 0 is returned. + */ +unsigned int bcma_core_mips_irq(struct bcma_device *dev) +{ + struct bcma_device *mdev = dev->bus->drv_mips.core; + u32 irqflag; + unsigned int irq; + + irqflag = bcma_core_mips_irqflag(dev); + + for (irq = 1; irq <= 4; irq++) + if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) & + (1 << irqflag)) + return irq; + + return 0; +} +EXPORT_SYMBOL(bcma_core_mips_irq); + +static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) +{ + unsigned int oldirq = bcma_core_mips_irq(dev); + struct bcma_bus *bus = dev->bus; + struct bcma_device *mdev = bus->drv_mips.core; + u32 irqflag; + + irqflag = bcma_core_mips_irqflag(dev); + BUG_ON(oldirq == 6); + + dev->irq = irq + 2; + + /* clear the old irq */ + if (oldirq == 0) + bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0), + bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) & + ~(1 << irqflag)); + else + bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0); + + /* assign the new one */ + if (irq == 0) { + bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0), + bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) | + (1 << irqflag)); + } else { + u32 oldirqflag = bcma_read32(mdev, + BCMA_MIPS_MIPS74K_INTMASK(irq)); + if (oldirqflag) { + struct bcma_device *core; + + /* backplane irq line is in use, find out who uses + * it and set user to irq 0 + */ + list_for_each_entry_reverse(core, &bus->cores, list) { + if ((1 << bcma_core_mips_irqflag(core)) == + oldirqflag) { + bcma_core_mips_set_irq(core, 0); + break; + } + } + } + bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), + 1 << irqflag); + } + + pr_info("set_irq: core 0x%04x, irq %d => %d\n", + dev->id.id, oldirq + 2, irq + 2); +} + +static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq) +{ + int i; + static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"}; + printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id); + for (i = 0; i <= 6; i++) + printk(" %s%s", irq_name[i], i == irq ? "*" : " "); + printk("\n"); +} + +static void bcma_core_mips_dump_irq(struct bcma_bus *bus) +{ + struct bcma_device *core; + + list_for_each_entry_reverse(core, &bus->cores, list) { + bcma_core_mips_print_irq(core, bcma_core_mips_irq(core)); + } +} + +u32 bcma_cpu_clock(struct bcma_drv_mips *mcore) +{ + struct bcma_bus *bus = mcore->core->bus; + + if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU) + return bcma_pmu_get_clockcpu(&bus->drv_cc); + + pr_err("No PMU available, need this to get the cpu clock\n"); + return 0; +} +EXPORT_SYMBOL(bcma_cpu_clock); + +static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) +{ + struct bcma_bus *bus = mcore->core->bus; + + switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) { + case BCMA_CC_FLASHT_STSER: + case BCMA_CC_FLASHT_ATSER: + pr_err("Serial flash not supported.\n"); + break; + case BCMA_CC_FLASHT_PARA: + pr_info("found parallel flash.\n"); + bus->drv_cc.pflash.window = 0x1c000000; + bus->drv_cc.pflash.window_size = 0x02000000; + + if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) & + BCMA_CC_FLASH_CFG_DS) == 0) + bus->drv_cc.pflash.buswidth = 1; + else + bus->drv_cc.pflash.buswidth = 2; + break; + default: + pr_err("flash not supported.\n"); + } +} + +void bcma_core_mips_init(struct bcma_drv_mips *mcore) +{ + struct bcma_bus *bus; + struct bcma_device *core; + bus = mcore->core->bus; + + pr_info("Initializing MIPS core...\n"); + + if (!mcore->setup_done) + mcore->assigned_irqs = 1; + + /* Assign IRQs to all cores on the bus */ + list_for_each_entry_reverse(core, &bus->cores, list) { + int mips_irq; + if (core->irq) + continue; + + mips_irq = bcma_core_mips_irq(core); + if (mips_irq > 4) + core->irq = 0; + else + core->irq = mips_irq + 2; + if (core->irq > 5) + continue; + switch (core->id.id) { + case BCMA_CORE_PCI: + case BCMA_CORE_PCIE: + case BCMA_CORE_ETHERNET: + case BCMA_CORE_ETHERNET_GBIT: + case BCMA_CORE_MAC_GBIT: + case BCMA_CORE_80211: + case BCMA_CORE_USB20_HOST: + /* These devices get their own IRQ line if available, + * the rest goes on IRQ0 + */ + if (mcore->assigned_irqs <= 4) + bcma_core_mips_set_irq(core, + mcore->assigned_irqs++); + break; + } + } + pr_info("IRQ reconfiguration done\n"); + bcma_core_mips_dump_irq(bus); + + if (mcore->setup_done) + return; + + bcma_chipco_serial_init(&bus->drv_cc); + bcma_core_mips_flash_detect(mcore); + mcore->setup_done = true; +} diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index 25f3ddf33823..81f3d0a4b856 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -173,7 +173,7 @@ static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc) return false; #ifdef CONFIG_SSB_DRIVER_PCICORE - if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI) + if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI) return false; #endif /* CONFIG_SSB_DRIVER_PCICORE */ @@ -189,6 +189,9 @@ static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc) void bcma_core_pci_init(struct bcma_drv_pci *pc) { + if (pc->setup_done) + return; + if (bcma_core_pci_is_in_hostmode(pc)) { #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE bcma_core_pci_hostmode_init(pc); @@ -198,6 +201,8 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc) } else { bcma_core_pci_clientmode_init(pc); } + + pc->setup_done = true; } int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, @@ -205,7 +210,14 @@ int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, { struct pci_dev *pdev = pc->core->bus->host_pci; u32 coremask, tmp; - int err; + int err = 0; + + if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) { + /* This bcma device is not on a PCI host-bus. So the IRQs are + * not routed through the PCI core. + * So we must not enable routing through the PCI core. */ + goto out; + } err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); if (err) diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c new file mode 100644 index 000000000000..3c381fb8f9c4 --- /dev/null +++ b/drivers/bcma/host_soc.c @@ -0,0 +1,183 @@ +/* + * Broadcom specific AMBA + * System on Chip (SoC) Host + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include "scan.h" +#include <linux/bcma/bcma.h> +#include <linux/bcma/bcma_soc.h> + +static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset) +{ + return readb(core->io_addr + offset); +} + +static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset) +{ + return readw(core->io_addr + offset); +} + +static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset) +{ + return readl(core->io_addr + offset); +} + +static void bcma_host_soc_write8(struct bcma_device *core, u16 offset, + u8 value) +{ + writeb(value, core->io_addr + offset); +} + +static void bcma_host_soc_write16(struct bcma_device *core, u16 offset, + u16 value) +{ + writew(value, core->io_addr + offset); +} + +static void bcma_host_soc_write32(struct bcma_device *core, u16 offset, + u32 value) +{ + writel(value, core->io_addr + offset); +} + +#ifdef CONFIG_BCMA_BLOCKIO +static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + void __iomem *addr = core->io_addr + offset; + + switch (reg_width) { + case sizeof(u8): { + u8 *buf = buffer; + + while (count) { + *buf = __raw_readb(addr); + buf++; + count--; + } + break; + } + case sizeof(u16): { + __le16 *buf = buffer; + + WARN_ON(count & 1); + while (count) { + *buf = (__force __le16)__raw_readw(addr); + buf++; + count -= 2; + } + break; + } + case sizeof(u32): { + __le32 *buf = buffer; + + WARN_ON(count & 3); + while (count) { + *buf = (__force __le32)__raw_readl(addr); + buf++; + count -= 4; + } + break; + } + default: + WARN_ON(1); + } +} + +static void bcma_host_soc_block_write(struct bcma_device *core, + const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + void __iomem *addr = core->io_addr + offset; + + switch (reg_width) { + case sizeof(u8): { + const u8 *buf = buffer; + + while (count) { + __raw_writeb(*buf, addr); + buf++; + count--; + } + break; + } + case sizeof(u16): { + const __le16 *buf = buffer; + + WARN_ON(count & 1); + while (count) { + __raw_writew((__force u16)(*buf), addr); + buf++; + count -= 2; + } + break; + } + case sizeof(u32): { + const __le32 *buf = buffer; + + WARN_ON(count & 3); + while (count) { + __raw_writel((__force u32)(*buf), addr); + buf++; + count -= 4; + } + break; + } + default: + WARN_ON(1); + } +} +#endif /* CONFIG_BCMA_BLOCKIO */ + +static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset) +{ + return readl(core->io_wrap + offset); +} + +static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset, + u32 value) +{ + writel(value, core->io_wrap + offset); +} + +const struct bcma_host_ops bcma_host_soc_ops = { + .read8 = bcma_host_soc_read8, + .read16 = bcma_host_soc_read16, + .read32 = bcma_host_soc_read32, + .write8 = bcma_host_soc_write8, + .write16 = bcma_host_soc_write16, + .write32 = bcma_host_soc_write32, +#ifdef CONFIG_BCMA_BLOCKIO + .block_read = bcma_host_soc_block_read, + .block_write = bcma_host_soc_block_write, +#endif + .aread32 = bcma_host_soc_aread32, + .awrite32 = bcma_host_soc_awrite32, +}; + +int __init bcma_host_soc_register(struct bcma_soc *soc) +{ + struct bcma_bus *bus = &soc->bus; + int err; + + /* iomap only first core. We have to read some register on this core + * to scan the bus. + */ + bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1); + if (!bus->mmio) + return -ENOMEM; + + /* Host specific */ + bus->hosttype = BCMA_HOSTTYPE_SOC; + bus->ops = &bcma_host_soc_ops; + + /* Register */ + err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips); + if (err) + iounmap(bus->mmio); + + return err; +} diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 873e2e4ac55f..8c09c3e547cd 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -15,6 +15,7 @@ MODULE_LICENSE("GPL"); static int bcma_bus_match(struct device *dev, struct device_driver *drv); static int bcma_device_probe(struct device *dev); static int bcma_device_remove(struct device *dev); +static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env); static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -49,6 +50,7 @@ static struct bus_type bcma_bus_type = { .match = bcma_bus_match, .probe = bcma_device_probe, .remove = bcma_device_remove, + .uevent = bcma_device_uevent, .dev_attrs = bcma_device_attrs, }; @@ -66,6 +68,10 @@ static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid) static void bcma_release_core_dev(struct device *dev) { struct bcma_device *core = container_of(dev, struct bcma_device, dev); + if (core->io_addr) + iounmap(core->io_addr); + if (core->io_wrap) + iounmap(core->io_wrap); kfree(core); } @@ -80,6 +86,7 @@ static int bcma_register_cores(struct bcma_bus *bus) case BCMA_CORE_CHIPCOMMON: case BCMA_CORE_PCI: case BCMA_CORE_PCIE: + case BCMA_CORE_MIPS_74K: continue; } @@ -93,7 +100,10 @@ static int bcma_register_cores(struct bcma_bus *bus) core->dma_dev = &bus->host_pci->dev; core->irq = bus->host_pci->irq; break; - case BCMA_HOSTTYPE_NONE: + case BCMA_HOSTTYPE_SOC: + core->dev.dma_mask = &core->dev.coherent_dma_mask; + core->dma_dev = &core->dev; + break; case BCMA_HOSTTYPE_SDIO: break; } @@ -140,6 +150,13 @@ int bcma_bus_register(struct bcma_bus *bus) bcma_core_chipcommon_init(&bus->drv_cc); } + /* Init MIPS core */ + core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); + if (core) { + bus->drv_mips.core = core; + bcma_core_mips_init(&bus->drv_mips); + } + /* Init PCIE core */ core = bcma_find_core(bus, BCMA_CORE_PCIE); if (core) { @@ -169,6 +186,59 @@ void bcma_bus_unregister(struct bcma_bus *bus) bcma_unregister_cores(bus); } +int __init bcma_bus_early_register(struct bcma_bus *bus, + struct bcma_device *core_cc, + struct bcma_device *core_mips) +{ + int err; + struct bcma_device *core; + struct bcma_device_id match; + + bcma_init_bus(bus); + + match.manuf = BCMA_MANUF_BCM; + match.id = BCMA_CORE_CHIPCOMMON; + match.class = BCMA_CL_SIM; + match.rev = BCMA_ANY_REV; + + /* Scan for chip common core */ + err = bcma_bus_scan_early(bus, &match, core_cc); + if (err) { + pr_err("Failed to scan for common core: %d\n", err); + return -1; + } + + match.manuf = BCMA_MANUF_MIPS; + match.id = BCMA_CORE_MIPS_74K; + match.class = BCMA_CL_SIM; + match.rev = BCMA_ANY_REV; + + /* Scan for mips core */ + err = bcma_bus_scan_early(bus, &match, core_mips); + if (err) { + pr_err("Failed to scan for mips core: %d\n", err); + return -1; + } + + /* Init CC core */ + core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON); + if (core) { + bus->drv_cc.core = core; + bcma_core_chipcommon_init(&bus->drv_cc); + } + + /* Init MIPS core */ + core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); + if (core) { + bus->drv_mips.core = core; + bcma_core_mips_init(&bus->drv_mips); + } + + pr_info("Early bus registered\n"); + + return 0; +} + int __bcma_driver_register(struct bcma_driver *drv, struct module *owner) { drv->drv.name = drv->name; @@ -227,6 +297,16 @@ static int bcma_device_remove(struct device *dev) return 0; } +static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + + return add_uevent_var(env, + "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X", + core->id.manuf, core->id.id, + core->id.rev, core->id.class); +} + static int __init bcma_modinit(void) { int err; diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index 40d7dcce8933..cad994857683 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -200,18 +200,162 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr, return addrl; } -int bcma_bus_scan(struct bcma_bus *bus) +static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus, + u16 index) { - u32 erombase; - u32 __iomem *eromptr, *eromend; + struct bcma_device *core; + list_for_each_entry(core, &bus->cores, list) { + if (core->core_index == index) + return core; + } + return NULL; +} + +static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, + struct bcma_device_id *match, int core_num, + struct bcma_device *core) +{ + s32 tmp; + u8 i, j; s32 cia, cib; u8 ports[2], wrappers[2]; + /* get CIs */ + cia = bcma_erom_get_ci(bus, eromptr); + if (cia < 0) { + bcma_erom_push_ent(eromptr); + if (bcma_erom_is_end(bus, eromptr)) + return -ESPIPE; + return -EILSEQ; + } + cib = bcma_erom_get_ci(bus, eromptr); + if (cib < 0) + return -EILSEQ; + + /* parse CIs */ + core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT; + core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT; + core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT; + ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT; + ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT; + wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT; + wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT; + core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT; + + if (((core->id.manuf == BCMA_MANUF_ARM) && + (core->id.id == 0xFFF)) || + (ports[1] == 0)) { + bcma_erom_skip_component(bus, eromptr); + return -ENXIO; + } + + /* check if component is a core at all */ + if (wrappers[0] + wrappers[1] == 0) { + /* we could save addrl of the router + if (cid == BCMA_CORE_OOB_ROUTER) + */ + bcma_erom_skip_component(bus, eromptr); + return -ENXIO; + } + + if (bcma_erom_is_bridge(bus, eromptr)) { + bcma_erom_skip_component(bus, eromptr); + return -ENXIO; + } + + if (bcma_find_core_by_index(bus, core_num)) { + bcma_erom_skip_component(bus, eromptr); + return -ENODEV; + } + + if (match && ((match->manuf != BCMA_ANY_MANUF && + match->manuf != core->id.manuf) || + (match->id != BCMA_ANY_ID && match->id != core->id.id) || + (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) || + (match->class != BCMA_ANY_CLASS && match->class != core->id.class) + )) { + bcma_erom_skip_component(bus, eromptr); + return -ENODEV; + } + + /* get & parse master ports */ + for (i = 0; i < ports[0]; i++) { + s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr); + if (mst_port_d < 0) + return -EILSEQ; + } + + /* get & parse slave ports */ + for (i = 0; i < ports[1]; i++) { + for (j = 0; ; j++) { + tmp = bcma_erom_get_addr_desc(bus, eromptr, + SCAN_ADDR_TYPE_SLAVE, i); + if (tmp < 0) { + /* no more entries for port _i_ */ + /* pr_debug("erom: slave port %d " + * "has %d descriptors\n", i, j); */ + break; + } else { + if (i == 0 && j == 0) + core->addr = tmp; + } + } + } + + /* get & parse master wrappers */ + for (i = 0; i < wrappers[0]; i++) { + for (j = 0; ; j++) { + tmp = bcma_erom_get_addr_desc(bus, eromptr, + SCAN_ADDR_TYPE_MWRAP, i); + if (tmp < 0) { + /* no more entries for port _i_ */ + /* pr_debug("erom: master wrapper %d " + * "has %d descriptors\n", i, j); */ + break; + } else { + if (i == 0 && j == 0) + core->wrap = tmp; + } + } + } + + /* get & parse slave wrappers */ + for (i = 0; i < wrappers[1]; i++) { + u8 hack = (ports[1] == 1) ? 0 : 1; + for (j = 0; ; j++) { + tmp = bcma_erom_get_addr_desc(bus, eromptr, + SCAN_ADDR_TYPE_SWRAP, i + hack); + if (tmp < 0) { + /* no more entries for port _i_ */ + /* pr_debug("erom: master wrapper %d " + * has %d descriptors\n", i, j); */ + break; + } else { + if (wrappers[0] == 0 && !i && !j) + core->wrap = tmp; + } + } + } + if (bus->hosttype == BCMA_HOSTTYPE_SOC) { + core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE); + if (!core->io_addr) + return -ENOMEM; + core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE); + if (!core->io_wrap) { + iounmap(core->io_addr); + return -ENOMEM; + } + } + return 0; +} + +void bcma_init_bus(struct bcma_bus *bus) +{ s32 tmp; - u8 i, j; - int err; + if (bus->init_done) + return; INIT_LIST_HEAD(&bus->cores); bus->nr_cores = 0; @@ -222,9 +366,27 @@ int bcma_bus_scan(struct bcma_bus *bus) bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT; bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT; bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; + bus->init_done = true; +} + +int bcma_bus_scan(struct bcma_bus *bus) +{ + u32 erombase; + u32 __iomem *eromptr, *eromend; + + int err, core_num = 0; + + bcma_init_bus(bus); erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); - eromptr = bus->mmio; + if (bus->hosttype == BCMA_HOSTTYPE_SOC) { + eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE); + if (!eromptr) + return -ENOMEM; + } else { + eromptr = bus->mmio; + } + eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); bcma_scan_switch_core(bus, erombase); @@ -236,125 +398,89 @@ int bcma_bus_scan(struct bcma_bus *bus) INIT_LIST_HEAD(&core->list); core->bus = bus; - /* get CIs */ - cia = bcma_erom_get_ci(bus, &eromptr); - if (cia < 0) { - bcma_erom_push_ent(&eromptr); - if (bcma_erom_is_end(bus, &eromptr)) - break; - err= -EILSEQ; - goto out; - } - cib = bcma_erom_get_ci(bus, &eromptr); - if (cib < 0) { - err= -EILSEQ; - goto out; - } - - /* parse CIs */ - core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT; - core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT; - core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT; - ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT; - ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT; - wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT; - wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT; - core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT; - - if (((core->id.manuf == BCMA_MANUF_ARM) && - (core->id.id == 0xFFF)) || - (ports[1] == 0)) { - bcma_erom_skip_component(bus, &eromptr); + err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core); + if (err == -ENODEV) { + core_num++; continue; - } - - /* check if component is a core at all */ - if (wrappers[0] + wrappers[1] == 0) { - /* we could save addrl of the router - if (cid == BCMA_CORE_OOB_ROUTER) - */ - bcma_erom_skip_component(bus, &eromptr); + } else if (err == -ENXIO) continue; - } + else if (err == -ESPIPE) + break; + else if (err < 0) + return err; - if (bcma_erom_is_bridge(bus, &eromptr)) { - bcma_erom_skip_component(bus, &eromptr); - continue; - } + core->core_index = core_num++; + bus->nr_cores++; - /* get & parse master ports */ - for (i = 0; i < ports[0]; i++) { - u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr); - if (mst_port_d < 0) { - err= -EILSEQ; - goto out; - } - } + pr_info("Core %d found: %s " + "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", + core->core_index, bcma_device_name(&core->id), + core->id.manuf, core->id.id, core->id.rev, + core->id.class); - /* get & parse slave ports */ - for (i = 0; i < ports[1]; i++) { - for (j = 0; ; j++) { - tmp = bcma_erom_get_addr_desc(bus, &eromptr, - SCAN_ADDR_TYPE_SLAVE, i); - if (tmp < 0) { - /* no more entries for port _i_ */ - /* pr_debug("erom: slave port %d " - * "has %d descriptors\n", i, j); */ - break; - } else { - if (i == 0 && j == 0) - core->addr = tmp; - } - } - } + list_add(&core->list, &bus->cores); + } - /* get & parse master wrappers */ - for (i = 0; i < wrappers[0]; i++) { - for (j = 0; ; j++) { - tmp = bcma_erom_get_addr_desc(bus, &eromptr, - SCAN_ADDR_TYPE_MWRAP, i); - if (tmp < 0) { - /* no more entries for port _i_ */ - /* pr_debug("erom: master wrapper %d " - * "has %d descriptors\n", i, j); */ - break; - } else { - if (i == 0 && j == 0) - core->wrap = tmp; - } - } - } + if (bus->hosttype == BCMA_HOSTTYPE_SOC) + iounmap(eromptr); - /* get & parse slave wrappers */ - for (i = 0; i < wrappers[1]; i++) { - u8 hack = (ports[1] == 1) ? 0 : 1; - for (j = 0; ; j++) { - tmp = bcma_erom_get_addr_desc(bus, &eromptr, - SCAN_ADDR_TYPE_SWRAP, i + hack); - if (tmp < 0) { - /* no more entries for port _i_ */ - /* pr_debug("erom: master wrapper %d " - * has %d descriptors\n", i, j); */ - break; - } else { - if (wrappers[0] == 0 && !i && !j) - core->wrap = tmp; - } - } - } + return 0; +} + +int __init bcma_bus_scan_early(struct bcma_bus *bus, + struct bcma_device_id *match, + struct bcma_device *core) +{ + u32 erombase; + u32 __iomem *eromptr, *eromend; + + int err = -ENODEV; + int core_num = 0; + + erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); + if (bus->hosttype == BCMA_HOSTTYPE_SOC) { + eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE); + if (!eromptr) + return -ENOMEM; + } else { + eromptr = bus->mmio; + } + + eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); + + bcma_scan_switch_core(bus, erombase); + + while (eromptr < eromend) { + memset(core, 0, sizeof(*core)); + INIT_LIST_HEAD(&core->list); + core->bus = bus; + err = bcma_get_next_core(bus, &eromptr, match, core_num, core); + if (err == -ENODEV) { + core_num++; + continue; + } else if (err == -ENXIO) + continue; + else if (err == -ESPIPE) + break; + else if (err < 0) + return err; + + core->core_index = core_num++; + bus->nr_cores++; pr_info("Core %d found: %s " "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", - bus->nr_cores, bcma_device_name(&core->id), + core->core_index, bcma_device_name(&core->id), core->id.manuf, core->id.id, core->id.rev, core->id.class); - core->core_index = bus->nr_cores++; list_add(&core->list, &bus->cores); - continue; -out: - return err; + err = 0; + break; } - return 0; + if (bus->hosttype == BCMA_HOSTTYPE_SOC) + iounmap(eromptr); + + return err; } diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 8b5b7856abe3..d7292390d236 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -133,6 +133,15 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i]; *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v); } + + bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)]; + + bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)]; + bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)]; + bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)]; + bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)]; + + bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)]; } int bcma_sprom_get(struct bcma_bus *bus) @@ -152,6 +161,9 @@ int bcma_sprom_get(struct bcma_bus *bus) if (!sprom) return -ENOMEM; + if (bus->chipinfo.id == 0x4331) + bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false); + /* Most cards have SPROM moved by additional offset 0x30 (48 dwords). * According to brcm80211 this applies to cards with PCIe rev >= 6 * TODO: understand this condition and use it */ @@ -159,6 +171,9 @@ int bcma_sprom_get(struct bcma_bus *bus) BCMA_CC_SPROM_PCIE6; bcma_sprom_read(bus, offset, sprom); + if (bus->chipinfo.id == 0x4331) + bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true); + err = bcma_sprom_valid(sprom); if (err) goto out; |