diff options
Diffstat (limited to 'drivers')
1801 files changed, 639207 insertions, 661490 deletions
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 93071417315f..f7ca4c13d61d 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -1134,7 +1134,8 @@ DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */ skb_headlen(skb)); else put_dma(tx->index,eni_dev->dma,&j,(unsigned long) - skb_shinfo(skb)->frags[i].page + skb_shinfo(skb)->frags[i].page_offset, + skb_frag_page(&skb_shinfo(skb)->frags[i]) + + skb_shinfo(skb)->frags[i].page_offset, skb_shinfo(skb)->frags[i].size); } if (skb->len & 3) 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..4bc10aa57bd4 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c @@ -11,6 +11,13 @@ #include "bcma_private.h" #include <linux/bcma/bcma.h> +static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset) +{ + 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); +} + static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask, u32 set) { @@ -83,6 +90,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 +117,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 +161,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, |