diff options
author | Hauke Mehrtens <hauke@hauke-m.de> | 2011-07-23 01:20:09 +0200 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-08-08 20:29:26 +0200 |
commit | 21e0534ad7415559bb8dee0dc00e39646fed83c9 (patch) | |
tree | e9e082dfdf6ce9798d6201f1ae4109b68b11920a /drivers/bcma | |
parent | bcma: add SOC bus (diff) | |
download | linux-21e0534ad7415559bb8dee0dc00e39646fed83c9.tar.xz linux-21e0534ad7415559bb8dee0dc00e39646fed83c9.zip |
bcma: add mips driver
This adds a mips driver to bcma. This is only found on embedded
devices. For now the driver just initializes the irqs used on this
system.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Acked-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/bcma')
-rw-r--r-- | drivers/bcma/Kconfig | 9 | ||||
-rw-r--r-- | drivers/bcma/Makefile | 1 | ||||
-rw-r--r-- | drivers/bcma/driver_mips.c | 243 | ||||
-rw-r--r-- | drivers/bcma/main.c | 15 |
4 files changed, 268 insertions, 0 deletions
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index 4a062f858e7a..c1172dafdffa 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -35,7 +35,16 @@ config BCMA_DRIVER_PCI_HOSTMODE 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" diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile index 8dc730de7786..82de24e5340c 100644 --- a/drivers/bcma/Makefile +++ b/drivers/bcma/Makefile @@ -2,6 +2,7 @@ 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 diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c new file mode 100644 index 000000000000..4b60c9f95839 --- /dev/null +++ b/drivers/bcma/driver_mips.c @@ -0,0 +1,243 @@ +/* + * 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)); + } +} + +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_core_mips_flash_detect(mcore); + mcore->setup_done = true; +} diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 2648522432be..7072216a2a3f 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -84,6 +84,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; } @@ -147,6 +148,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) { @@ -217,6 +225,13 @@ int __init bcma_bus_early_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); + } + pr_info("Early bus registered\n"); return 0; |