This patch series adds support for embedded devices like bcm47xx to
bcma. Bcma is used on bcm4716 and bcm4718 SoCs as the system bus and
replaced ssb used on older devices. With these patches my bcm4716
device boots up till it tries to access the flash, because the serial
flash chip is unsupported for now, this will be my next task. This adds
support for MIPS cores, interrupt configuration and the serial console.
These patches are not containing all functions needed to get the SoC to
fully work and support every feature, but it is a good start.
These patches are now integrated in OpenWrt for everyone how wants to
test them.
This was tested with a BCM4704 device (SoC with ssb bus), a BCM4716
device and a pcie wireless card supported by bcma.
@John could you please merge this into wireless-testing. I hope Ralf is
fine with it when some MIPS bits will go through wireless. This will
make it much easier for Linus to merge wireless-testing and the mips
tree together as there are many other changes for bcma in wireless-
testing.
PATCH v3:
* rebase on wireless-testing master-2011-07-22-2
* remove BCMA_HOSTTYPE_NONE
* add Acked-by Rafał
* rename bcm47xx_active_bus_type to bcm47xx_bus_type
* set core->dev.dma_mask and core->dma_dev for SoC
* fix comment
PATCH v2:
* define inline function bcma_core_mips_init() if mips driver is not build
* iounmap core->io_wrap and core->io_addr after it was used.
* update bcma based on new braodcom driver code
* add workaround for 5357b0
* move flash informations into own struct and store it in chipcommon.
When adding serial flash support it will be in chipcommon and then all flash structs should be there.
* some changes to bcma_chipco_serial_init()
* some changes are done after looking into a more recent version of broadcom driver.
* changes suggested by Jonas
* serial struct is in chipcommon as it is accessed through chipcommon.
* use bcma_pmu_alp_clock() to get the clock.
* cpu clock: add detection support for some newer SoCs.
PATCH v1:
* rebased on mips tree (mips/queue)
* drop pcie hostmode patch as Rafał sent a better patch to wireless mailing list
* drop sprom patch because sprom is not supported in bcma version from mips tree,
I will send a separate patch to wireless mailing list.
* fix compilation of arch/mips/bcm47xx/wgt634u.c
* fix texts in arch/mips/bcm47xx/Kconfig
RFC v3:
* make bcm47xx built either with bcma, ssb or both and use mips MIPS 74K optimizations if possible
* add block io support
* some minor fixes for code and doku
RFC v2:
* use list and no arry to store cores
* rename bcma_host_bcma_ to bcma_host_soc_
* use core->io_addr and core->io_wrap to access cores
* checkpatch fixes
* some minor fixes
Hauke Mehrtens (11):
bcma: move parsing of EEPROM into own function.
bcma: move initializing of struct bcma_bus to own function.
bcma: add functions to scan cores needed on SoCs
bcma: add SOC bus
bcma: add mips driver
bcma: add serial console support
bcma: get CPU clock
bcm47xx: prepare to support different buses
bcm47xx: make it possible to build bcm47xx without ssb.
bcm47xx: add support for bcma bus
bcm47xx: fix irq assignment for new SoCs.
arch/mips/Kconfig | 8 +-
arch/mips/bcm47xx/Kconfig | 31 +++
arch/mips/bcm47xx/Makefile | 3 +-
arch/mips/bcm47xx/gpio.c | 82 +++++--
arch/mips/bcm47xx/irq.c | 12 +
arch/mips/bcm47xx/nvram.c | 29 ++-
arch/mips/bcm47xx/serial.c | 46 ++++-
arch/mips/bcm47xx/setup.c | 90 ++++++-
arch/mips/bcm47xx/time.c | 16 +-
arch/mips/bcm47xx/wgt634u.c | 14 +-
arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 26 ++-
arch/mips/include/asm/mach-bcm47xx/gpio.h | 108 +++++++--
arch/mips/pci/pci-bcm47xx.c | 6 +
drivers/bcma/Kconfig | 13 +
drivers/bcma/Makefile | 2 +
drivers/bcma/bcma_private.h | 16 ++
drivers/bcma/core.c | 2 +
drivers/bcma/driver_chipcommon.c | 53 ++++
drivers/bcma/driver_chipcommon_pmu.c | 133 ++++++++++
drivers/bcma/driver_mips.c | 256 +++++++++++++++++++
drivers/bcma/driver_pci.c | 14 +-
drivers/bcma/host_soc.c | 183 ++++++++++++++
drivers/bcma/main.c | 70 +++++-
drivers/bcma/scan.c | 348 ++++++++++++++++++--------
drivers/watchdog/bcm47xx_wdt.c | 27 ++-
include/linux/bcma/bcma.h | 9 +-
include/linux/bcma/bcma_driver_chipcommon.h | 67 +++++
include/linux/bcma/bcma_driver_mips.h | 51 ++++
include/linux/bcma/bcma_soc.h | 16 ++
29 files changed, 1549 insertions(+), 182 deletions(-)
create mode 100644 arch/mips/bcm47xx/Kconfig
create mode 100644 drivers/bcma/driver_mips.c
create mode 100644 drivers/bcma/host_soc.c
create mode 100644 include/linux/bcma/bcma_driver_mips.h
create mode 100644 include/linux/bcma/bcma_soc.h
--
1.7.4.1
This patch adds support for using bcma on a Broadcom SoC as the system
bus. An SoC like the bcm4716 could register this bus and use it to
searches for the bcma cores and register the devices on this bus.
BCMA_HOSTTYPE_NONE was intended for SoCs at first but BCMA_HOSTTYPE_SOC
is a better name.
Acked-by: Rafał Miłecki <[email protected]>
Signed-off-by: Hauke Mehrtens <[email protected]>
---
drivers/bcma/Kconfig | 4 +
drivers/bcma/Makefile | 1 +
drivers/bcma/core.c | 2 +
drivers/bcma/driver_pci.c | 9 ++-
drivers/bcma/host_soc.c | 183 +++++++++++++++++++++++++++++++++++++++++
drivers/bcma/main.c | 9 ++-
drivers/bcma/scan.c | 42 ++++++++-
include/linux/bcma/bcma.h | 5 +-
include/linux/bcma/bcma_soc.h | 16 ++++
9 files changed, 263 insertions(+), 8 deletions(-)
create mode 100644 drivers/bcma/host_soc.c
create mode 100644 include/linux/bcma/bcma_soc.h
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index ae0a02e..4a062f8 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -33,6 +33,10 @@ config BCMA_DRIVER_PCI_HOSTMODE
help
PCI core hostmode operation (external PCI bus).
+config BCMA_HOST_SOC
+ bool
+ depends on BCMA && MIPS
+
config BCMA_DEBUG
bool "BCMA debugging"
depends on BCMA
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
index a2161cc..8dc730d 100644
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -3,6 +3,7 @@ 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_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/core.c b/drivers/bcma/core.c
index 4a04a49..189a97b 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_pci.c b/drivers/bcma/driver_pci.c
index bdd3bc9..1902cdb 100644
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -208,7 +208,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 0000000..3c381fb
--- /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 360a289..2648522 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -66,6 +66,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);
}
@@ -93,7 +97,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;
}
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index bf9f806..0ea390f 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -337,6 +337,16 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
}
}
}
+ 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;
}
@@ -369,7 +379,14 @@ int bcma_bus_scan(struct bcma_bus *bus)
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);
@@ -404,6 +421,9 @@ int bcma_bus_scan(struct bcma_bus *bus)
list_add(&core->list, &bus->cores);
}
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+ iounmap(eromptr);
+
return 0;
}
@@ -414,10 +434,18 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus,
u32 erombase;
u32 __iomem *eromptr, *eromend;
- int err, core_num = 0;
+ int err = -ENODEV;
+ int core_num = 0;
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);
@@ -447,8 +475,12 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus,
core->id.class);
list_add(&core->list, &bus->cores);
- return 0;
+ err = 0;
+ break;
}
- return -ENODEV;
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+ iounmap(eromptr);
+
+ return err;
}
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index e31c9b4..c70cec5 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -14,9 +14,9 @@ struct bcma_device;
struct bcma_bus;
enum bcma_hosttype {
- BCMA_HOSTTYPE_NONE,
BCMA_HOSTTYPE_PCI,
BCMA_HOSTTYPE_SDIO,
+ BCMA_HOSTTYPE_SOC,
};
struct bcma_chipinfo {
@@ -138,6 +138,9 @@ struct bcma_device {
u32 addr;
u32 wrap;
+ void __iomem *io_addr;
+ void __iomem *io_wrap;
+
void *drvdata;
struct list_head list;
};
diff --git a/include/linux/bcma/bcma_soc.h b/include/linux/bcma/bcma_soc.h
new file mode 100644
index 0000000..4203c55
--- /dev/null
+++ b/include/linux/bcma/bcma_soc.h
@@ -0,0 +1,16 @@
+#ifndef LINUX_BCMA_SOC_H_
+#define LINUX_BCMA_SOC_H_
+
+#include <linux/bcma/bcma.h>
+
+struct bcma_soc {
+ struct bcma_bus bus;
+ struct bcma_device core_cc;
+ struct bcma_device core_mips;
+};
+
+int __init bcma_host_soc_register(struct bcma_soc *soc);
+
+int bcma_bus_register(struct bcma_bus *bus);
+
+#endif /* LINUX_BCMA_SOC_H_ */
--
1.7.4.1
Signed-off-by: Hauke Mehrtens <[email protected]>
---
arch/mips/bcm47xx/irq.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c
index 325757a..8cf3833 100644
--- a/arch/mips/bcm47xx/irq.c
+++ b/arch/mips/bcm47xx/irq.c
@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <asm/irq_cpu.h>
+#include <bcm47xx.h>
void plat_irq_dispatch(void)
{
@@ -51,5 +52,16 @@ void plat_irq_dispatch(void)
void __init arch_init_irq(void)
{
+#ifdef CONFIG_BCM47XX_BCMA
+ if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA) {
+ bcma_write32(bcm47xx_bus.bcma.bus.drv_mips.core,
+ BCMA_MIPS_MIPS74K_INTMASK(5), 1 << 31);
+ /*
+ * the kernel reads the timer irq from some register and thinks
+ * it's #5, but we offset it by 2 and route to #7
+ */
+ cp0_compare_irq = 7;
+ }
+#endif
mips_cpu_irq_init();
}
--
1.7.4.1
Hi Jonas,
On 07/13/2011 09:36 PM, Jonas Gorski wrote:
> Hi,
>
> some minor things I saw:
>
> On 9 July 2011 13:05, Hauke Mehrtens <[email protected]> wrote:
>> This patch adds support for using bcma on a Broadcom SoC as the system
>> bus. An SoC like the bcm4716 could register this bus and use it to
>> searches for the bcma cores and register the devices on this bus.
>>
>> Signed-off-by: Hauke Mehrtens <[email protected]>
>> ---
>> drivers/bcma/Kconfig | 5 +
>> drivers/bcma/Makefile | 1 +
>> drivers/bcma/host_soc.c | 178 +++++++++++++++++++++++++++++++++++++++++
>> drivers/bcma/main.c | 1 +
>> drivers/bcma/scan.c | 24 +++++-
>> include/linux/bcma/bcma.h | 4 +
>> include/linux/bcma/bcma_soc.h | 16 ++++
>> 7 files changed, 227 insertions(+), 2 deletions(-)
>> create mode 100644 drivers/bcma/host_soc.c
>> create mode 100644 include/linux/bcma/bcma_soc.h
>>
>> diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
>> index 353781b..8d82f42 100644
>> --- a/drivers/bcma/Kconfig
>> +++ b/drivers/bcma/Kconfig
>> @@ -22,6 +22,11 @@ config BCMA_HOST_PCI
>> bool "Support for BCMA on PCI-host bus"
>> depends on BCMA_HOST_PCI_POSSIBLE
>>
>> +config BCMA_HOST_SOC
>> + bool
>> + depends on BCMA && MIPS
>> + default n
>
> Default default is already "n", so this line is superfluous.
Will remove this.
>
>> +
>> config BCMA_DEBUG
>> bool "BCMA debugging"
>> depends on BCMA
>> diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
>> index 0d56245..42d61dd 100644
>> --- a/drivers/bcma/Makefile
>> +++ b/drivers/bcma/Makefile
>> @@ -2,6 +2,7 @@ bcma-y += main.o scan.o core.o
>> bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
>> bcma-y += driver_pci.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/host_soc.c b/drivers/bcma/host_soc.c
>> new file mode 100644
>> index 0000000..a6fe724
>> --- /dev/null
>> +++ b/drivers/bcma/host_soc.c
>> @@ -0,0 +1,178 @@
>> +/*
>> + * 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;
>> +
>> + /* iomap only first core. We have to read some register on this core
>> + * to scan the bus.
>> + */
>> + bus->mmio = ioremap(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 */
>> + return bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
>> +}
>> diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
>> index e6c308c..2ca5eeb 100644
>> --- a/drivers/bcma/main.c
>> +++ b/drivers/bcma/main.c
>> @@ -92,6 +92,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
>> break;
>> case BCMA_HOSTTYPE_NONE:
>> case BCMA_HOSTTYPE_SDIO:
>> + case BCMA_HOSTTYPE_SOC:
>> break;
>> }
>>
>> diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
>> index bf9f806..202edc8 100644
>> --- a/drivers/bcma/scan.c
>> +++ b/drivers/bcma/scan.c
>> @@ -337,6 +337,14 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
>> }
>> }
>> }
>> + if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
>> + core->io_addr = ioremap(core->addr, BCMA_CORE_SIZE);
>> + if (!core->io_addr)
>> + return -ENOMEM;
>> + core->io_wrap = ioremap(core->wrap, BCMA_CORE_SIZE);
>> + if (!core->io_wrap)
>> + return -ENOMEM;
>
> Shouldn't you unmap core->io_addr if remapping io_wrap fails?
Ok I will add iounmap() on the error path and when the core is freed.
>
>> + }
>> return 0;
>> }
>>
>> @@ -369,7 +377,13 @@ int bcma_bus_scan(struct bcma_bus *bus)
>> bcma_init_bus(bus);
>>
>> erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
>> - eromptr = bus->mmio;
>> + if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
>> + eromptr = ioremap(erombase, BCMA_CORE_SIZE);
>> + if (!eromptr)
>> + return -ENOMEM;
>> + } else
>> + eromptr = bus->mmio;
>
> Documentation/CodingStyle says use braces in both branches if one needs them.
Will fix this.
>
>> +
>> eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
>>
>> bcma_scan_switch_core(bus, erombase);
>> @@ -417,7 +431,13 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus,
>> int err, core_num = 0;
>>
>> erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
>> - eromptr = bus->mmio;
>> + if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
>> + eromptr = ioremap(erombase, BCMA_CORE_SIZE);
>> + if (!eromptr)
>> + return -ENOMEM;
>> + } else
>> + eromptr = bus->mmio;
>
> Ditto.
>
>> +
>> eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
>>
>> bcma_scan_switch_core(bus, erombase);
>> diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
>> index 6bd7b7f..73fda1c 100644
>> --- a/include/linux/bcma/bcma.h
>> +++ b/include/linux/bcma/bcma.h
>> @@ -16,6 +16,7 @@ enum bcma_hosttype {
>> BCMA_HOSTTYPE_NONE,
>> BCMA_HOSTTYPE_PCI,
>> BCMA_HOSTTYPE_SDIO,
>> + BCMA_HOSTTYPE_SOC,
>> };
>>
>> struct bcma_chipinfo {
>> @@ -124,6 +125,9 @@ struct bcma_device {
>> u32 addr;
>> u32 wrap;
>>
>> + void __iomem *io_addr;
>> + void __iomem *io_wrap;
>> +
>> void *drvdata;
>> struct list_head list;
>> };
>> diff --git a/include/linux/bcma/bcma_soc.h b/include/linux/bcma/bcma_soc.h
>> new file mode 100644
>> index 0000000..4203c55
>> --- /dev/null
>> +++ b/include/linux/bcma/bcma_soc.h
>> @@ -0,0 +1,16 @@
>> +#ifndef LINUX_BCMA_SOC_H_
>> +#define LINUX_BCMA_SOC_H_
>> +
>> +#include <linux/bcma/bcma.h>
>> +
>> +struct bcma_soc {
>> + struct bcma_bus bus;
>> + struct bcma_device core_cc;
>> + struct bcma_device core_mips;
>> +};
>> +
>> +int __init bcma_host_soc_register(struct bcma_soc *soc);
>> +
>> +int bcma_bus_register(struct bcma_bus *bus);
>> +
>> +#endif /* LINUX_BCMA_SOC_H_ */
>> --
>> 1.7.4.1
On Sat, Jul 23, 2011 at 01:20:04AM +0200, Hauke Mehrtens wrote:
> This patch series adds support for embedded devices like bcm47xx to
> bcma. Bcma is used on bcm4716 and bcm4718 SoCs as the system bus and
> replaced ssb used on older devices. With these patches my bcm4716
> device boots up till it tries to access the flash, because the serial
> flash chip is unsupported for now, this will be my next task. This adds
> support for MIPS cores, interrupt configuration and the serial console.
>
> These patches are not containing all functions needed to get the SoC to
> fully work and support every feature, but it is a good start.
> These patches are now integrated in OpenWrt for everyone how wants to
> test them.
>
> This was tested with a BCM4704 device (SoC with ssb bus), a BCM4716
> device and a pcie wireless card supported by bcma.
>
> @John could you please merge this into wireless-testing. I hope Ralf is
> fine with it when some MIPS bits will go through wireless. This will
> make it much easier for Linus to merge wireless-testing and the mips
> tree together as there are many other changes for bcma in wireless-
> testing.
Any chance we could see an ACK from Ralf?
John
--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
arch/mips/Kconfig | 8 +-------
arch/mips/bcm47xx/Kconfig | 18 ++++++++++++++++++
arch/mips/bcm47xx/Makefile | 3 ++-
arch/mips/bcm47xx/gpio.c | 6 ++++++
arch/mips/bcm47xx/nvram.c | 4 ++++
arch/mips/bcm47xx/serial.c | 4 ++++
arch/mips/bcm47xx/setup.c | 8 ++++++++
arch/mips/bcm47xx/time.c | 2 ++
arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 4 ++++
arch/mips/include/asm/mach-bcm47xx/gpio.h | 12 ++++++++++++
arch/mips/pci/pci-bcm47xx.c | 6 ++++++
drivers/watchdog/bcm47xx_wdt.c | 4 ++++
12 files changed, 71 insertions(+), 8 deletions(-)
create mode 100644 arch/mips/bcm47xx/Kconfig
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 653da62..ac6f237 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -91,15 +91,8 @@ config BCM47XX
select DMA_NONCOHERENT
select HW_HAS_PCI
select IRQ_CPU
- select SYS_HAS_CPU_MIPS32_R1
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
- select SSB
- select SSB_DRIVER_MIPS
- select SSB_DRIVER_EXTIF
- select SSB_EMBEDDED
- select SSB_B43_PCI_BRIDGE if PCI
- select SSB_PCICORE_HOSTMODE if PCI
select GENERIC_GPIO
select SYS_HAS_EARLY_PRINTK
select CFE
@@ -785,6 +778,7 @@ endchoice
source "arch/mips/alchemy/Kconfig"
source "arch/mips/ath79/Kconfig"
+source "arch/mips/bcm47xx/Kconfig"
source "arch/mips/bcm63xx/Kconfig"
source "arch/mips/jazz/Kconfig"
source "arch/mips/jz4740/Kconfig"
diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
new file mode 100644
index 0000000..0346f92
--- /dev/null
+++ b/arch/mips/bcm47xx/Kconfig
@@ -0,0 +1,18 @@
+if BCM47XX
+
+config BCM47XX_SSB
+ bool "SSB Support for Broadcom BCM47XX"
+ select SYS_HAS_CPU_MIPS32_R1
+ select SSB
+ select SSB_DRIVER_MIPS
+ select SSB_DRIVER_EXTIF
+ select SSB_EMBEDDED
+ select SSB_B43_PCI_BRIDGE if PCI
+ select SSB_PCICORE_HOSTMODE if PCI
+ default y
+ help
+ Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support.
+
+ This will generate an image with support for SSB and MIPS32 R1 instruction set.
+
+endif
diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile
index 7465e8a..4add173 100644
--- a/arch/mips/bcm47xx/Makefile
+++ b/arch/mips/bcm47xx/Makefile
@@ -3,4 +3,5 @@
# under Linux.
#
-obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o
+obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o
+obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o
diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
index 99e1c50..2b804c3 100644
--- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c
@@ -21,6 +21,7 @@ static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES);
int gpio_request(unsigned gpio, const char *tag)
{
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
@@ -34,6 +35,7 @@ int gpio_request(unsigned gpio, const char *tag)
return -EBUSY;
return 0;
+#endif
}
return -EINVAL;
}
@@ -42,6 +44,7 @@ EXPORT_SYMBOL(gpio_request);
void gpio_free(unsigned gpio)
{
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
@@ -53,6 +56,7 @@ void gpio_free(unsigned gpio)
clear_bit(gpio, gpio_in_use);
return;
+#endif
}
}
EXPORT_SYMBOL(gpio_free);
@@ -60,6 +64,7 @@ EXPORT_SYMBOL(gpio_free);
int gpio_to_irq(unsigned gpio)
{
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
@@ -67,6 +72,7 @@ int gpio_to_irq(unsigned gpio)
return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
else
return -EINVAL;
+#endif
}
return -EINVAL;
}
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index bcac2ff..4e994ed 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -26,7 +26,9 @@ static char nvram_buf[NVRAM_SPACE];
/* Probe for NVRAM header */
static void early_nvram_init(void)
{
+#ifdef CONFIG_BCM47XX_SSB
struct ssb_mipscore *mcore_ssb;
+#endif
struct nvram_header *header;
int i;
u32 base = 0;
@@ -35,11 +37,13 @@ static void early_nvram_init(void)
u32 *src, *dst;
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
mcore_ssb = &bcm47xx_bus.ssb.mipscore;
base = mcore_ssb->flash_window;
lim = mcore_ssb->flash_window_size;
break;
+#endif
}
off = FLASH_MIN;
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index 17c67e2..fcef688 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -23,6 +23,7 @@ static struct platform_device uart8250_device = {
},
};
+#ifdef CONFIG_BCM47XX_SSB
static int __init uart8250_init_ssb(void)
{
int i;
@@ -44,12 +45,15 @@ static int __init uart8250_init_ssb(void)
}
return platform_device_register(&uart8250_device);
}
+#endif
static int __init uart8250_init(void)
{
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
return uart8250_init_ssb();
+#endif
}
return -EINVAL;
}
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 9828b60..39e8465 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -47,9 +47,11 @@ static void bcm47xx_machine_restart(char *command)
local_irq_disable();
/* Set the watchdog timer to reset immediately */
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
break;
+#endif
}
while (1)
cpu_relax();
@@ -60,14 +62,17 @@ static void bcm47xx_machine_halt(void)
/* Disable interrupts and watchdog and spin forever */
local_irq_disable();
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
break;
+#endif
}
while (1)
cpu_relax();
}
+#ifdef CONFIG_BCM47XX_SSB
#define READ_FROM_NVRAM(_outvar, name, buf) \
if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\
sprom->_outvar = simple_strtoul(buf, NULL, 0);
@@ -288,13 +293,16 @@ static void __init bcm47xx_register_ssb(void)
}
}
}
+#endif
void __init plat_mem_setup(void)
{
struct cpuinfo_mips *c = ¤t_cpu_data;
+#ifdef CONFIG_BCM47XX_SSB
bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB;
bcm47xx_register_ssb();
+#endif
_machine_restart = bcm47xx_machine_restart;
_machine_halt = bcm47xx_machine_halt;
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index 50aea2e..03dfc65 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -40,9 +40,11 @@ void __init plat_time_init(void)
write_c0_compare(0xffff);
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
break;
+#endif
}
if (!hz)
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index 7cf481b..d037afb 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -22,11 +22,15 @@
#include <linux/ssb/ssb.h>
enum bcm47xx_bus_type {
+#ifdef CONFIG_BCM47XX_SSB
BCM47XX_BUS_TYPE_SSB,
+#endif
};
union bcm47xx_bus {
+#ifdef CONFIG_BCM47XX_SSB
struct ssb_bus ssb;
+#endif
};
extern union bcm47xx_bus bcm47xx_bus;
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 6b78827..1d5f5af 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -22,8 +22,10 @@ extern int gpio_to_irq(unsigned gpio);
static inline int gpio_get_value(unsigned gpio)
{
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
+#endif
}
return -EINVAL;
}
@@ -31,18 +33,22 @@ static inline int gpio_get_value(unsigned gpio)
static inline void gpio_set_value(unsigned gpio, int value)
{
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
value ? 1 << gpio : 0);
+#endif
}
}
static inline int gpio_direction_input(unsigned gpio)
{
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
return 0;
+#endif
}
return -EINVAL;
}
@@ -50,6 +56,7 @@ static inline int gpio_direction_input(unsigned gpio)
static inline int gpio_direction_output(unsigned gpio, int value)
{
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
/* first set the gpio out value */
ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
@@ -57,6 +64,7 @@ static inline int gpio_direction_output(unsigned gpio, int value)
/* then set the gpio mode */
ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
return 0;
+#endif
}
return -EINVAL;
}
@@ -64,10 +72,12 @@ static inline int gpio_direction_output(unsigned gpio, int value)
static inline int gpio_intmask(unsigned gpio, int value)
{
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
value ? 1 << gpio : 0);
return 0;
+#endif
}
return -EINVAL;
}
@@ -75,10 +85,12 @@ static inline int gpio_intmask(unsigned gpio, int value)
static inline int gpio_polarity(unsigned gpio, int value)
{
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
value ? 1 << gpio : 0);
return 0;
+#endif
}
return -EINVAL;
}
diff --git a/arch/mips/pci/pci-bcm47xx.c b/arch/mips/pci/pci-bcm47xx.c
index 455f8e5..400535a 100644
--- a/arch/mips/pci/pci-bcm47xx.c
+++ b/arch/mips/pci/pci-bcm47xx.c
@@ -25,6 +25,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/ssb/ssb.h>
+#include <bcm47xx.h>
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
@@ -33,9 +34,13 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
int pcibios_plat_dev_init(struct pci_dev *dev)
{
+#ifdef CONFIG_BCM47XX_SSB
int res;
u8 slot, pin;
+ if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB)
+ return 0;
+
res = ssb_pcibios_plat_dev_init(dev);
if (res < 0) {
printk(KERN_ALERT "PCI: Failed to init device %s\n",
@@ -55,5 +60,6 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
}
dev->irq = res;
+#endif
return 0;
}
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index c43406c..6b03702 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -55,17 +55,21 @@ static inline void bcm47xx_wdt_hw_start(void)
{
/* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
break;
+#endif
}
}
static inline int bcm47xx_wdt_hw_stop(void)
{
switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+#endif
}
return -EINVAL;
}
--
1.7.4.1
On Sat, Jul 23, 2011 at 01:20:04AM +0200, Hauke Mehrtens wrote:
> This patch series adds support for embedded devices like bcm47xx to
> bcma. Bcma is used on bcm4716 and bcm4718 SoCs as the system bus and
> replaced ssb used on older devices. With these patches my bcm4716
> device boots up till it tries to access the flash, because the serial
> flash chip is unsupported for now, this will be my next task. This adds
> support for MIPS cores, interrupt configuration and the serial console.
>
> These patches are not containing all functions needed to get the SoC to
> fully work and support every feature, but it is a good start.
> These patches are now integrated in OpenWrt for everyone how wants to
> test them.
>
> This was tested with a BCM4704 device (SoC with ssb bus), a BCM4716
> device and a pcie wireless card supported by bcma.
>
> @John could you please merge this into wireless-testing. I hope Ralf is
> fine with it when some MIPS bits will go through wireless. This will
> make it much easier for Linus to merge wireless-testing and the mips
> tree together as there are many other changes for bcma in wireless-
> testing.
John, if you want to merge the MIPS bits through the wireless tree, feel
free to:
Acked-by: Ralf Baechle <[email protected]>
Ralf
This makes it possible to use this code in some other method.
Acked-by: Rafał Miłecki <[email protected]>
Signed-off-by: Hauke Mehrtens <[email protected]>
---
drivers/bcma/scan.c | 17 +++++++++++------
1 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 4012d8d..7970553 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -312,15 +312,10 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
return 0;
}
-int bcma_bus_scan(struct bcma_bus *bus)
+static void bcma_init_bus(struct bcma_bus *bus)
{
- u32 erombase;
- u32 __iomem *eromptr, *eromend;
-
s32 tmp;
- int err;
-
INIT_LIST_HEAD(&bus->cores);
bus->nr_cores = 0;
@@ -330,6 +325,16 @@ 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;
+}
+
+int bcma_bus_scan(struct bcma_bus *bus)
+{
+ u32 erombase;
+ u32 __iomem *eromptr, *eromend;
+
+ int err;
+
+ bcma_init_bus(bus);
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
eromptr = bus->mmio;
--
1.7.4.1
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 <[email protected]>
---
drivers/bcma/Kconfig | 9 +
drivers/bcma/Makefile | 1 +
drivers/bcma/driver_mips.c | 243 +++++++++++++++++++++++++++
drivers/bcma/main.c | 15 ++
include/linux/bcma/bcma.h | 3 +
include/linux/bcma/bcma_driver_chipcommon.h | 13 ++
include/linux/bcma/bcma_driver_mips.h | 49 ++++++
7 files changed, 333 insertions(+), 0 deletions(-)
create mode 100644 drivers/bcma/driver_mips.c
create mode 100644 include/linux/bcma/bcma_driver_mips.h
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index 4a062f8..c1172da 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 8dc730d..82de24e 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 0000000..4b60c9f9
--- /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 <[email protected]>
+ * Copyright 2010, Bernhard Loos <[email protected]>
+ * Copyright 2011, Hauke Mehrtens <[email protected]>
+ *
+ * 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 2648522..7072216 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;
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index c70cec5..5dbd705 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -6,6 +6,7 @@
#include <linux/bcma/bcma_driver_chipcommon.h>
#include <linux/bcma/bcma_driver_pci.h>
+#include <linux/bcma/bcma_driver_mips.h>
#include <linux/ssb/ssb.h> /* SPROM sharing */
#include "bcma_regs.h"
@@ -130,6 +131,7 @@ struct bcma_device {
struct device dev;
struct device *dma_dev;
+
unsigned int irq;
bool dev_registered;
@@ -197,6 +199,7 @@ struct bcma_bus {
struct bcma_drv_cc drv_cc;
struct bcma_drv_pci drv_pci;
+ struct bcma_drv_mips drv_mips;
/* We decided to share SPROM struct with SSB as long as we do not need
* any hacks for BCMA. This simplifies drivers code. */
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index c8b4cf7..03cde8d 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -24,6 +24,7 @@
#define BCMA_CC_FLASHT_NONE 0x00000000 /* No flash */
#define BCMA_CC_FLASHT_STSER 0x00000100 /* ST serial flash */
#define BCMA_CC_FLASHT_ATSER 0x00000200 /* Atmel serial flash */
+#define BCMA_CC_FLASHT_NFLASH 0x00000200
#define BCMA_CC_FLASHT_PARA 0x00000700 /* Parallel flash */
#define BCMA_CC_CAP_PLLT 0x00038000 /* PLL Type */
#define BCMA_PLLTYPE_NONE 0x00000000
@@ -178,6 +179,7 @@
#define BCMA_CC_PROG_CFG 0x0120
#define BCMA_CC_PROG_WAITCNT 0x0124
#define BCMA_CC_FLASH_CFG 0x0128
+#define BCMA_CC_FLASH_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */
#define BCMA_CC_FLASH_WAITCNT 0x012C
/* 0x1E0 is defined as shared BCMA_CLKCTLST */
#define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */
@@ -247,6 +249,14 @@ struct bcma_chipcommon_pmu {
u32 crystalfreq; /* The active crystal frequency (in kHz) */
};
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+struct bcma_pflash {
+ u8 buswidth;
+ u32 window;
+ u32 window_size;
+};
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
+
struct bcma_drv_cc {
struct bcma_device *core;
u32 status;
@@ -256,6 +266,9 @@ struct bcma_drv_cc {
/* Fast Powerup Delay constant */
u16 fast_pwrup_delay;
struct bcma_chipcommon_pmu pmu;
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+ struct bcma_pflash pflash;
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
};
/* Register access */
diff --git a/include/linux/bcma/bcma_driver_mips.h b/include/linux/bcma/bcma_driver_mips.h
new file mode 100644
index 0000000..82b3bfd
--- /dev/null
+++ b/include/linux/bcma/bcma_driver_mips.h
@@ -0,0 +1,49 @@
+#ifndef LINUX_BCMA_DRIVER_MIPS_H_
+#define LINUX_BCMA_DRIVER_MIPS_H_
+
+#define BCMA_MIPS_IPSFLAG 0x0F08
+/* which sbflags get routed to mips interrupt 1 */
+#define BCMA_MIPS_IPSFLAG_IRQ1 0x0000003F
+#define BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
+/* which sbflags get routed to mips interrupt 2 */
+#define BCMA_MIPS_IPSFLAG_IRQ2 0x00003F00
+#define BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
+/* which sbflags get routed to mips interrupt 3 */
+#define BCMA_MIPS_IPSFLAG_IRQ3 0x003F0000
+#define BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
+/* which sbflags get routed to mips interrupt 4 */
+#define BCMA_MIPS_IPSFLAG_IRQ4 0x3F000000
+#define BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
+
+/* MIPS 74K core registers */
+#define BCMA_MIPS_MIPS74K_CORECTL 0x0000
+#define BCMA_MIPS_MIPS74K_EXCEPTBASE 0x0004
+#define BCMA_MIPS_MIPS74K_BIST 0x000C
+#define BCMA_MIPS_MIPS74K_INTMASK_INT0 0x0014
+#define BCMA_MIPS_MIPS74K_INTMASK(int) \
+ ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
+#define BCMA_MIPS_MIPS74K_NMIMASK 0x002C
+#define BCMA_MIPS_MIPS74K_GPIOSEL 0x0040
+#define BCMA_MIPS_MIPS74K_GPIOOUT 0x0044
+#define BCMA_MIPS_MIPS74K_GPIOEN 0x0048
+#define BCMA_MIPS_MIPS74K_CLKCTLST 0x01E0
+
+#define BCMA_MIPS_OOBSELOUTA30 0x100
+
+struct bcma_device;
+
+struct bcma_drv_mips {
+ struct bcma_device *core;
+ u8 setup_done:1;
+ unsigned int assigned_irqs;
+};
+
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
+#else
+static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
+#endif
+
+extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
+
+#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
--
1.7.4.1
Move the parsing of the EEPROM data in scan function for one core into
an own function. Now we are able to use it in some other scan function
as well.
Acked-by: Rafał Miłecki <[email protected]>
Signed-off-by: Hauke Mehrtens <[email protected]>
---
drivers/bcma/scan.c | 230 ++++++++++++++++++++++++++-------------------------
1 files changed, 118 insertions(+), 112 deletions(-)
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 40d7dcc..4012d8d 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -200,16 +200,124 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
return addrl;
}
+static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
+ 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;
+ }
+
+ /* 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)
+ 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;
+ }
+ }
+ }
+ return 0;
+}
+
int bcma_bus_scan(struct bcma_bus *bus)
{
u32 erombase;
u32 __iomem *eromptr, *eromend;
- s32 cia, cib;
- u8 ports[2], wrappers[2];
-
s32 tmp;
- u8 i, j;
int err;
@@ -236,112 +344,13 @@ 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);
- 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);
- continue;
- }
-
- if (bcma_erom_is_bridge(bus, &eromptr)) {
- bcma_erom_skip_component(bus, &eromptr);
+ err = bcma_get_next_core(bus, &eromptr, core);
+ if (err == -ENXIO)
continue;
- }
-
- /* 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;
- }
- }
-
- /* 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;
- }
- }
- }
+ else if (err == -ESPIPE)
+ break;
+ else if (err < 0)
+ return err;
pr_info("Core %d found: %s "
"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
@@ -351,9 +360,6 @@ int bcma_bus_scan(struct bcma_bus *bus)
core->core_index = bus->nr_cores++;
list_add(&core->list, &bus->cores);
- continue;
-out:
- return err;
}
return 0;
--
1.7.4.1
Add method to return the clock of the CPU. This is needed by the arch
code to calculate the mips_hpt_frequency.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
drivers/bcma/bcma_private.h | 1 +
drivers/bcma/driver_chipcommon_pmu.c | 107 +++++++++++++++++++++++++++
drivers/bcma/driver_mips.c | 12 +++
include/linux/bcma/bcma_driver_chipcommon.h | 39 ++++++++++
include/linux/bcma/bcma_driver_mips.h | 2 +
5 files changed, 161 insertions(+), 0 deletions(-)
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 22d3052..30a3085 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -36,6 +36,7 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
/* 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 */
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index 59d2b26..ecac255 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)
{
@@ -162,3 +169,103 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
}
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
index b17233c..c3e9dff 100644
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -166,6 +166,18 @@ static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
}
}
+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;
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index b9a930e..6083725 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -241,8 +241,47 @@
#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
#define BCMA_CC_SPROM_PCIE6 0x0830 /* SPROM beginning on PCIe rev >= 6 */
+/* Divider allocation in 4716/47162/5356 */
+#define BCMA_CC_PMU5_MAINPLL_CPU 1
+#define BCMA_CC_PMU5_MAINPLL_MEM 2
+#define BCMA_CC_PMU5_MAINPLL_SSB 3
+
+/* PLL usage in 4716/47162 */
+#define BCMA_CC_PMU4716_MAINPLL_PLL0 12
+
+/* PLL usage in 5356/5357 */
+#define BCMA_CC_PMU5356_MAINPLL_PLL0 0
+#define BCMA_CC_PMU5357_MAINPLL_PLL0 0
+
+/* 4706 PMU */
+#define BCMA_CC_PMU4706_MAINPLL_PLL0 0
+
/* ALP clock on pre-PMU chips */
#define BCMA_CC_PMU_ALP_CLOCK 20000000
+/* HT clock for systems with PMU-enabled chipcommon */
+#define BCMA_CC_PMU_HT_CLOCK 80000000
+
+/* PMU rev 5 (& 6) */
+#define BCMA_CC_PPL_P1P2_OFF 0
+#define BCMA_CC_PPL_P1_MASK 0x0f000000
+#define BCMA_CC_PPL_P1_SHIFT 24
+#define BCMA_CC_PPL_P2_MASK 0x00f00000
+#define BCMA_CC_PPL_P2_SHIFT 20
+#define BCMA_CC_PPL_M14_OFF 1
+#define BCMA_CC_PPL_MDIV_MASK 0x000000ff
+#define BCMA_CC_PPL_MDIV_WIDTH 8
+#define BCMA_CC_PPL_NM5_OFF 2
+#define BCMA_CC_PPL_NDIV_MASK 0xfff00000
+#define BCMA_CC_PPL_NDIV_SHIFT 20
+#define BCMA_CC_PPL_FMAB_OFF 3
+#define BCMA_CC_PPL_MRAT_MASK 0xf0000000
+#define BCMA_CC_PPL_MRAT_SHIFT 28
+#define BCMA_CC_PPL_ABRAT_MASK 0x08000000
+#define BCMA_CC_PPL_ABRAT_SHIFT 27
+#define BCMA_CC_PPL_FDIV_MASK 0x07ffffff
+#define BCMA_CC_PPL_PLLCTL_OFF 4
+#define BCMA_CC_PPL_PCHI_OFF 5
+#define BCMA_CC_PPL_PCHI_MASK 0x0000003f
/* Data for the PMU, if available.
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
diff --git a/include/linux/bcma/bcma_driver_mips.h b/include/linux/bcma/bcma_driver_mips.h
index 82b3bfd..c004364 100644
--- a/include/linux/bcma/bcma_driver_mips.h
+++ b/include/linux/bcma/bcma_driver_mips.h
@@ -44,6 +44,8 @@ extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
#endif
+extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
+
extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
--
1.7.4.1
The chip common and mips core have to be setup early in the boot
process to get the cpu clock.
bcma_bus_early_register() gets pointers to some space to store the core
data and searches for the chip common and mips core and initializes
chip common. After that was done and the kernel is out of early boot we
just have to run bcma_bus_register() and it will search for the other
cores, initialize and register them.
The cores are getting the same numbers as before.
Acked-by: Rafał Miłecki <[email protected]>
Signed-off-by: Hauke Mehrtens <[email protected]>
---
drivers/bcma/bcma_private.h | 7 ++
drivers/bcma/driver_chipcommon.c | 5 ++
drivers/bcma/driver_pci.c | 5 ++
drivers/bcma/main.c | 46 +++++++++++++
drivers/bcma/scan.c | 95 +++++++++++++++++++++++++--
include/linux/bcma/bcma.h | 1 +
include/linux/bcma/bcma_driver_chipcommon.h | 1 +
7 files changed, 154 insertions(+), 6 deletions(-)
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index e02ff21..b97633d 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -15,9 +15,16 @@ 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);
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index fb54302..75f1ad7 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 */
diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c
index dc6f34a..bdd3bc9 100644
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -187,6 +187,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);
@@ -196,6 +199,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,
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 873e2e4..360a289 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -169,6 +169,52 @@ 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);
+ }
+
+ pr_info("Early bus registered\n");
+
+ return 0;
+}
+
int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
{
drv->drv.name = drv->name;
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 7970553..bf9f806 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -200,7 +200,20 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
return addrl;
}
+static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
+ u16 index)
+{
+ 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;
@@ -251,6 +264,21 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **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++) {
u32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
@@ -312,10 +340,13 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
return 0;
}
-static void bcma_init_bus(struct bcma_bus *bus)
+void bcma_init_bus(struct bcma_bus *bus)
{
s32 tmp;
+ if (bus->init_done)
+ return;
+
INIT_LIST_HEAD(&bus->cores);
bus->nr_cores = 0;
@@ -325,6 +356,7 @@ static void bcma_init_bus(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)
@@ -332,7 +364,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
u32 erombase;
u32 __iomem *eromptr, *eromend;
- int err;
+ int err, core_num = 0;
bcma_init_bus(bus);
@@ -349,23 +381,74 @@ int bcma_bus_scan(struct bcma_bus *bus)
INIT_LIST_HEAD(&core->list);
core->bus = bus;
- err = bcma_get_next_core(bus, &eromptr, core);
- if (err == -ENXIO)
+ err = bcma_get_next_core(bus, &eromptr, NULL, 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);
}
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, core_num = 0;
+
+ erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
+ 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",
+ core->core_index, bcma_device_name(&core->id),
+ core->id.manuf, core->id.id, core->id.rev,
+ core->id.class);
+
+ list_add(&core->list, &bus->cores);
+ return 0;
+ }
+
+ return -ENODEV;
+}
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 8c96654..e31c9b4 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -190,6 +190,7 @@ struct bcma_bus {
struct bcma_device *mapped_core;
struct list_head cores;
u8 nr_cores;
+ u8 init_done:1;
struct bcma_drv_cc drv_cc;
struct bcma_drv_pci drv_pci;
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index a0f6846..c8b4cf7 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -252,6 +252,7 @@ struct bcma_drv_cc {
u32 status;
u32 capabilities;
u32 capabilities_ext;
+ u8 setup_done:1;
/* Fast Powerup Delay constant */
u16 fast_pwrup_delay;
struct bcma_chipcommon_pmu pmu;
--
1.7.4.1
SGksCgpzb21lIG1pbm9yIHRoaW5ncyBJIHNhdzoKCk9uIDkgSnVseSAyMDExIDEzOjA1LCBIYXVr
ZSBNZWhydGVucyA8aGF1a2VAaGF1a2UtbS5kZT4gd3JvdGU6Cj4gVGhpcyBwYXRjaCBhZGRzIHN1
cHBvcnQgZm9yIHVzaW5nIGJjbWEgb24gYSBCcm9hZGNvbSBTb0MgYXMgdGhlIHN5c3RlbQo+IGJ1
cy4gQW4gU29DIGxpa2UgdGhlIGJjbTQ3MTYgY291bGQgcmVnaXN0ZXIgdGhpcyBidXMgYW5kIHVz
ZSBpdCB0bwo+IHNlYXJjaGVzIGZvciB0aGUgYmNtYSBjb3JlcyBhbmQgcmVnaXN0ZXIgdGhlIGRl
dmljZXMgb24gdGhpcyBidXMuCj4KPiBTaWduZWQtb2ZmLWJ5OiBIYXVrZSBNZWhydGVucyA8aGF1
a2VAaGF1a2UtbS5kZT4KPiAtLS0KPiDCoGRyaXZlcnMvYmNtYS9LY29uZmlnIMKgIMKgIMKgIMKg
IMKgfCDCoCDCoDUgKwo+IMKgZHJpdmVycy9iY21hL01ha2VmaWxlIMKgIMKgIMKgIMKgIHwgwqAg
wqAxICsKPiDCoGRyaXZlcnMvYmNtYS9ob3N0X3NvYy5jIMKgIMKgIMKgIHwgwqAxNzggKysrKysr
KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKPiDCoGRyaXZlcnMvYmNtYS9tYWlu
LmMgwqAgwqAgwqAgwqAgwqAgfCDCoCDCoDEgKwo+IMKgZHJpdmVycy9iY21hL3NjYW4uYyDCoCDC
oCDCoCDCoCDCoCB8IMKgIDI0ICsrKysrLQo+IMKgaW5jbHVkZS9saW51eC9iY21hL2JjbWEuaCDC
oCDCoCB8IMKgIMKgNCArCj4gwqBpbmNsdWRlL2xpbnV4L2JjbWEvYmNtYV9zb2MuaCB8IMKgIDE2
ICsrKysKPiDCoDcgZmlsZXMgY2hhbmdlZCwgMjI3IGluc2VydGlvbnMoKyksIDIgZGVsZXRpb25z
KC0pCj4gwqBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9iY21hL2hvc3Rfc29jLmMKPiDCoGNy
ZWF0ZSBtb2RlIDEwMDY0NCBpbmNsdWRlL2xpbnV4L2JjbWEvYmNtYV9zb2MuaAo+Cj4gZGlmZiAt
LWdpdCBhL2RyaXZlcnMvYmNtYS9LY29uZmlnIGIvZHJpdmVycy9iY21hL0tjb25maWcKPiBpbmRl
eCAzNTM3ODFiLi44ZDgyZjQyIDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMvYmNtYS9LY29uZmlnCj4g
KysrIGIvZHJpdmVycy9iY21hL0tjb25maWcKPiBAQCAtMjIsNiArMjIsMTEgQEAgY29uZmlnIEJD
TUFfSE9TVF9QQ0kKPiDCoCDCoCDCoCDCoGJvb2wgIlN1cHBvcnQgZm9yIEJDTUEgb24gUENJLWhv
c3QgYnVzIgo+IMKgIMKgIMKgIMKgZGVwZW5kcyBvbiBCQ01BX0hPU1RfUENJX1BPU1NJQkxFCj4K
PiArY29uZmlnIEJDTUFfSE9TVF9TT0MKPiArIMKgIMKgIMKgIGJvb2wKPiArIMKgIMKgIMKgIGRl
cGVuZHMgb24gQkNNQSAmJiBNSVBTCj4gKyDCoCDCoCDCoCBkZWZhdWx0IG4KCkRlZmF1bHQgZGVm
YXVsdCBpcyBhbHJlYWR5ICJuIiwgc28gdGhpcyBsaW5lIGlzIHN1cGVyZmx1b3VzLgoKPiArCj4g
wqBjb25maWcgQkNNQV9ERUJVRwo+IMKgIMKgIMKgIMKgYm9vbCAiQkNNQSBkZWJ1Z2dpbmciCj4g
wqAgwqAgwqAgwqBkZXBlbmRzIG9uIEJDTUEKPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9iY21hL01h
a2VmaWxlIGIvZHJpdmVycy9iY21hL01ha2VmaWxlCj4gaW5kZXggMGQ1NjI0NS4uNDJkNjFkZCAx
MDA2NDQKPiAtLS0gYS9kcml2ZXJzL2JjbWEvTWFrZWZpbGUKPiArKysgYi9kcml2ZXJzL2JjbWEv
TWFrZWZpbGUKPiBAQCAtMiw2ICsyLDcgQEAgYmNtYS15IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKz0gbWFpbi5vIHNjYW4ubyBjb3JlLm8KPiDCoGJj
bWEteSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCArPSBk
cml2ZXJfY2hpcGNvbW1vbi5vIGRyaXZlcl9jaGlwY29tbW9uX3BtdS5vCj4gwqBiY21hLXkgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgKz0gZHJpdmVyX3Bj
aS5vCj4gwqBiY21hLSQoQ09ORklHX0JDTUFfSE9TVF9QQ0kpIMKgIMKgIMKgIMKgIMKgICs9IGhv
c3RfcGNpLm8KPiArYmNtYS0kKENPTkZJR19CQ01BX0hPU1RfU09DKSDCoCDCoCDCoCDCoCDCoCAr
PSBob3N0X3NvYy5vCj4gwqBvYmotJChDT05GSUdfQkNNQSkgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgKz0gYmNtYS5vCj4KPiDCoGNjZmxhZ3MtJChDT05GSUdfQkNNQV9ERUJVRykgwqAg
wqAgwqAgwqAgwqAgOj0gLURERUJVRwo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2JjbWEvaG9zdF9z
b2MuYyBiL2RyaXZlcnMvYmNtYS9ob3N0X3NvYy5jCj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiBp
bmRleCAwMDAwMDAwLi5hNmZlNzI0Cj4gLS0tIC9kZXYvbnVsbAo+ICsrKyBiL2RyaXZlcnMvYmNt
YS9ob3N0X3NvYy5jCj4gQEAgLTAsMCArMSwxNzggQEAKPiArLyoKPiArICogQnJvYWRjb20gc3Bl
Y2lmaWMgQU1CQQo+ICsgKiBTeXN0ZW0gb24gQ2hpcCAoU29DKSBIb3N0Cj4gKyAqCj4gKyAqIExp
Y2Vuc2VkIHVuZGVyIHRoZSBHTlUvR1BMLiBTZWUgQ09QWUlORyBmb3IgZGV0YWlscy4KPiArICov
Cj4gKwo+ICsjaW5jbHVkZSAiYmNtYV9wcml2YXRlLmgiCj4gKyNpbmNsdWRlICJzY2FuLmgiCj4g
KyNpbmNsdWRlIDxsaW51eC9iY21hL2JjbWEuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2JjbWEvYmNt
YV9zb2MuaD4KPiArCj4gK3N0YXRpYyB1OCBiY21hX2hvc3Rfc29jX3JlYWQ4KHN0cnVjdCBiY21h
X2RldmljZSAqY29yZSwgdTE2IG9mZnNldCkKPiArewo+ICsgwqAgwqAgwqAgcmV0dXJuIHJlYWRi
KGNvcmUtPmlvX2FkZHIgKyBvZmZzZXQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdTE2IGJjbWFfaG9z
dF9zb2NfcmVhZDE2KHN0cnVjdCBiY21hX2RldmljZSAqY29yZSwgdTE2IG9mZnNldCkKPiArewo+
ICsgwqAgwqAgwqAgcmV0dXJuIHJlYWR3KGNvcmUtPmlvX2FkZHIgKyBvZmZzZXQpOwo+ICt9Cj4g
Kwo+ICtzdGF0aWMgdTMyIGJjbWFfaG9zdF9zb2NfcmVhZDMyKHN0cnVjdCBiY21hX2RldmljZSAq
Y29yZSwgdTE2IG9mZnNldCkKPiArewo+ICsgwqAgwqAgwqAgcmV0dXJuIHJlYWRsKGNvcmUtPmlv
X2FkZHIgKyBvZmZzZXQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBiY21hX2hvc3Rfc29jX3dy
aXRlOChzdHJ1Y3QgYmNtYV9kZXZpY2UgKmNvcmUsIHUxNiBvZmZzZXQsCj4gKyDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHU4IHZhbHVlKQo+ICt7Cj4gKyDC
oCDCoCDCoCB3cml0ZWIodmFsdWUsIGNvcmUtPmlvX2FkZHIgKyBvZmZzZXQpOwo+ICt9Cj4gKwo+
ICtzdGF0aWMgdm9pZCBiY21hX2hvc3Rfc29jX3dyaXRlMTYoc3RydWN0IGJjbWFfZGV2aWNlICpj
b3JlLCB1MTYgb2Zmc2V0LAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqB1MTYgdmFsdWUpCj4gK3sKPiArIMKgIMKgIMKgIHdyaXRldyh2YWx1ZSwgY29y
ZS0+aW9fYWRkciArIG9mZnNldCk7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIGJjbWFfaG9zdF9z
b2Nfd3JpdGUzMihzdHJ1Y3QgYmNtYV9kZXZpY2UgKmNvcmUsIHUxNiBvZmZzZXQsCj4gKyDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHUzMiB2YWx1ZSkKPiAr
ewo+ICsgwqAgwqAgwqAgd3JpdGVsKHZhbHVlLCBjb3JlLT5pb19hZGRyICsgb2Zmc2V0KTsKPiAr
fQo+ICsKPiArI2lmZGVmIENPTkZJR19CQ01BX0JMT0NLSU8KPiArc3RhdGljIHZvaWQgYmNtYV9o
b3N0X3NvY19ibG9ja19yZWFkKHN0cnVjdCBiY21hX2RldmljZSAqY29yZSwgdm9pZCAqYnVmZmVy
LAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqBzaXplX3QgY291bnQsIHUxNiBvZmZzZXQsIHU4IHJlZ193aWR0aCkKPiArewo+ICsgwqAgwqAg
wqAgdm9pZCBfX2lvbWVtICphZGRyID0gY29yZS0+aW9fYWRkciArIG9mZnNldDsKPiArCj4gKyDC
oCDCoCDCoCBzd2l0Y2ggKHJlZ193aWR0aCkgewo+ICsgwqAgwqAgwqAgY2FzZSBzaXplb2YodTgp
OiB7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCB1OCAqYnVmID0gYnVmZmVyOwo+ICsKPiArIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIHdoaWxlIChjb3VudCkgewo+ICsgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgKmJ1ZiA9IF9fcmF3X3JlYWRiKGFkZHIpOwo+ICsgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgYnVmKys7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCBjb3VudC0tOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgfQo+ICsgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgYnJlYWs7Cj4gKyDCoCDCoCDCoCB9Cj4gKyDCoCDCoCDCoCBjYXNlIHNpemVv
Zih1MTYpOiB7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBfX2xlMTYgKmJ1ZiA9IGJ1ZmZlcjsK
PiArCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBXQVJOX09OKGNvdW50ICYgMSk7Cj4gKyDCoCDC
oCDCoCDCoCDCoCDCoCDCoCB3aGlsZSAoY291bnQpIHsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgICpidWYgPSAoX19mb3JjZSBfX2xlMTYpX19yYXdfcmVhZHcoYWRkcik7Cj4g
KyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBidWYrKzsKPiArIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIGNvdW50IC09IDI7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDC
oCB9Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBicmVhazsKPiArIMKgIMKgIMKgIH0KPiArIMKg
IMKgIMKgIGNhc2Ugc2l6ZW9mKHUzMik6IHsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIF9fbGUz
MiAqYnVmID0gYnVmZmVyOwo+ICsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIFdBUk5fT04oY291
bnQgJiAzKTsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHdoaWxlIChjb3VudCkgewo+ICsgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgKmJ1ZiA9IChfX2ZvcmNlIF9fbGUzMilfX3Jh
d19yZWFkbChhZGRyKTsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGJ1Zisr
Owo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY291bnQgLT0gNDsKPiArIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIH0KPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGJyZWFrOwo+ICsg
wqAgwqAgwqAgfQo+ICsgwqAgwqAgwqAgZGVmYXVsdDoKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IFdBUk5fT04oMSk7Cj4gKyDCoCDCoCDCoCB9Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIGJjbWFf
aG9zdF9zb2NfYmxvY2tfd3JpdGUoc3RydWN0IGJjbWFfZGV2aWNlICpjb3JlLAo+ICsgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29uc3Qgdm9p
ZCAqYnVmZmVyLAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgc2l6ZV90IGNvdW50LCB1MTYgb2Zmc2V0LCB1OCByZWdfd2lkdGgpCj4gK3sK
PiArIMKgIMKgIMKgIHZvaWQgX19pb21lbSAqYWRkciA9IGNvcmUtPmlvX2FkZHIgKyBvZmZzZXQ7
Cj4gKwo+ICsgwqAgwqAgwqAgc3dpdGNoIChyZWdfd2lkdGgpIHsKPiArIMKgIMKgIMKgIGNhc2Ug
c2l6ZW9mKHU4KTogewo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29uc3QgdTggKmJ1ZiA9IGJ1
ZmZlcjsKPiArCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCB3aGlsZSAoY291bnQpIHsKPiArIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIF9fcmF3X3dyaXRlYigqYnVmLCBhZGRyKTsK
PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGJ1ZisrOwo+ICsgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY291bnQtLTsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IH0KPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGJyZWFrOwo+ICsgwqAgwqAgwqAgfQo+ICsgwqAg
wqAgwqAgY2FzZSBzaXplb2YodTE2KTogewo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29uc3Qg
X19sZTE2ICpidWYgPSBidWZmZXI7Cj4gKwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgV0FSTl9P
Tihjb3VudCAmIDEpOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgd2hpbGUgKGNvdW50KSB7Cj4g
KyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBfX3Jhd193cml0ZXcoKF9fZm9yY2Ug
dTE2KSgqYnVmKSwgYWRkcik7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBi
dWYrKzsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGNvdW50IC09IDI7Cj4g
KyDCoCDCoCDCoCDCoCDCoCDCoCDCoCB9Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBicmVhazsK
PiArIMKgIMKgIMKgIH0KPiArIMKgIMKgIMKgIGNhc2Ugc2l6ZW9mKHUzMik6IHsKPiArIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIGNvbnN0IF9fbGUzMiAqYnVmID0gYnVmZmVyOwo+ICsKPiArIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIFdBUk5fT04oY291bnQgJiAzKTsKPiArIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIHdoaWxlIChjb3VudCkgewo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
X19yYXdfd3JpdGVsKChfX2ZvcmNlIHUzMikoKmJ1ZiksIGFkZHIpOwo+ICsgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgYnVmKys7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCBjb3VudCAtPSA0Owo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgfQo+ICsgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgYnJlYWs7Cj4gKyDCoCDCoCDCoCB9Cj4gKyDCoCDCoCDCoCBkZWZhdWx0
Ogo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgV0FSTl9PTigxKTsKPiArIMKgIMKgIMKgIH0KPiAr
fQo+ICsjZW5kaWYgLyogQ09ORklHX0JDTUFfQkxPQ0tJTyAqLwo+ICsKPiArc3RhdGljIHUzMiBi
Y21hX2hvc3Rfc29jX2FyZWFkMzIoc3RydWN0IGJjbWFfZGV2aWNlICpjb3JlLCB1MTYgb2Zmc2V0
KQo+ICt7Cj4gKyDCoCDCoCDCoCByZXR1cm4gcmVhZGwoY29yZS0+aW9fd3JhcCArIG9mZnNldCk7
Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIGJjbWFfaG9zdF9zb2NfYXdyaXRlMzIoc3RydWN0IGJj
bWFfZGV2aWNlICpjb3JlLCB1MTYgb2Zmc2V0LAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgdTMyIHZhbHVlKQo+ICt7Cj4gKyDCoCDCoCDCoCB3cml0
ZWwodmFsdWUsIGNvcmUtPmlvX3dyYXAgKyBvZmZzZXQpOwo+ICt9Cj4gKwo+ICtjb25zdCBzdHJ1
Y3QgYmNtYV9ob3N0X29wcyBiY21hX2hvc3Rfc29jX29wcyA9IHsKPiArIMKgIMKgIMKgIC5yZWFk
OCDCoCDCoCDCoCDCoCDCoD0gYmNtYV9ob3N0X3NvY19yZWFkOCwKPiArIMKgIMKgIMKgIC5yZWFk
MTYgwqAgwqAgwqAgwqAgPSBiY21hX2hvc3Rfc29jX3JlYWQxNiwKPiArIMKgIMKgIMKgIC5yZWFk
MzIgwqAgwqAgwqAgwqAgPSBiY21hX2hvc3Rfc29jX3JlYWQzMiwKPiArIMKgIMKgIMKgIC53cml0
ZTggwqAgwqAgwqAgwqAgPSBiY21hX2hvc3Rfc29jX3dyaXRlOCwKPiArIMKgIMKgIMKgIC53cml0
ZTE2IMKgIMKgIMKgIMKgPSBiY21hX2hvc3Rfc29jX3dyaXRlMTYsCj4gKyDCoCDCoCDCoCAud3Jp
dGUzMiDCoCDCoCDCoCDCoD0gYmNtYV9ob3N0X3NvY193cml0ZTMyLAo+ICsjaWZkZWYgQ09ORklH
X0JDTUFfQkxPQ0tJTwo+ICsgwqAgwqAgwqAgLmJsb2NrX3JlYWQgwqAgwqAgPSBiY21hX2hvc3Rf
c29jX2Jsb2NrX3JlYWQsCj4gKyDCoCDCoCDCoCAuYmxvY2tfd3JpdGUgwqAgwqA9IGJjbWFfaG9z
dF9zb2NfYmxvY2tfd3JpdGUsCj4gKyNlbmRpZgo+ICsgwqAgwqAgwqAgLmFyZWFkMzIgwqAgwqAg
wqAgwqA9IGJjbWFfaG9zdF9zb2NfYXJlYWQzMiwKPiArIMKgIMKgIMKgIC5hd3JpdGUzMiDCoCDC
oCDCoCA9IGJjbWFfaG9zdF9zb2NfYXdyaXRlMzIsCj4gK307Cj4gKwo+ICtpbnQgX19pbml0IGJj
bWFfaG9zdF9zb2NfcmVnaXN0ZXIoc3RydWN0IGJjbWFfc29jICpzb2MpCj4gK3sKPiArIMKgIMKg
IMKgIHN0cnVjdCBiY21hX2J1cyAqYnVzID0gJnNvYy0+YnVzOwo+ICsKPiArIMKgIMKgIMKgIC8q
IGlvbWFwIG9ubHkgZmlyc3QgY29yZS4gV2UgaGF2ZSB0byByZWFkIHNvbWUgcmVnaXN0ZXIgb24g
dGhpcyBjb3JlCj4gKyDCoCDCoCDCoCDCoCogdG8gc2NhbiB0aGUgYnVzLgo+ICsgwqAgwqAgwqAg
wqAqLwo+ICsgwqAgwqAgwqAgYnVzLT5tbWlvID0gaW9yZW1hcChCQ01BX0FERFJfQkFTRSwgQkNN
QV9DT1JFX1NJWkUgKiAxKTsKPiArIMKgIMKgIMKgIGlmICghYnVzLT5tbWlvKQo+ICsgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgcmV0dXJuIC1FTk9NRU07Cj4gKwo+ICsgwqAgwqAgwqAgLyogSG9zdCBz
cGVjaWZpYyAqLwo+ICsgwqAgwqAgwqAgYnVzLT5ob3N0dHlwZSA9IEJDTUFfSE9TVFRZUEVfU09D
Owo+ICsgwqAgwqAgwqAgYnVzLT5vcHMgPSAmYmNtYV9ob3N0X3NvY19vcHM7Cj4gKwo+ICsgwqAg
wqAgwqAgLyogUmVnaXN0ZXIgKi8KPiArIMKgIMKgIMKgIHJldHVybiBiY21hX2J1c19lYXJseV9y
ZWdpc3RlcihidXMsICZzb2MtPmNvcmVfY2MsICZzb2MtPmNvcmVfbWlwcyk7Cj4gK30KPiBkaWZm
IC0tZ2l0IGEvZHJpdmVycy9iY21hL21haW4uYyBiL2RyaXZlcnMvYmNtYS9tYWluLmMKPiBpbmRl
eCBlNmMzMDhjLi4yY2E1ZWViIDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMvYmNtYS9tYWluLmMKPiAr
KysgYi9kcml2ZXJzL2JjbWEvbWFpbi5jCj4gQEAgLTkyLDYgKzkyLDcgQEAgc3RhdGljIGludCBi
Y21hX3JlZ2lzdGVyX2NvcmVzKHN0cnVjdCBiY21hX2J1cyAqYnVzKQo+IMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgYnJlYWs7Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBjYXNl
IEJDTUFfSE9TVFRZUEVfTk9ORToKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGNhc2UgQkNNQV9I
T1NUVFlQRV9TRElPOgo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY2FzZSBCQ01BX0hPU1RUWVBF
X1NPQzoKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGJyZWFrOwo+IMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgfQo+Cj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvYmNtYS9zY2FuLmMg
Yi9kcml2ZXJzL2JjbWEvc2Nhbi5jCj4gaW5kZXggYmY5ZjgwNi4uMjAyZWRjOCAxMDA2NDQKPiAt
LS0gYS9kcml2ZXJzL2JjbWEvc2Nhbi5jCj4gKysrIGIvZHJpdmVycy9iY21hL3NjYW4uYwo+IEBA
IC0zMzcsNiArMzM3LDE0IEBAIHN0YXRpYyBpbnQgYmNtYV9nZXRfbmV4dF9jb3JlKHN0cnVjdCBi
Y21hX2J1cyAqYnVzLCB1MzIgX19pb21lbSAqKmVyb21wdHIsCj4gwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqB9Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9Cj4gwqAgwqAgwqAg
wqB9Cj4gKyDCoCDCoCDCoCBpZiAoYnVzLT5ob3N0dHlwZSA9PSBCQ01BX0hPU1RUWVBFX1NPQykg
ewo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29yZS0+aW9fYWRkciA9IGlvcmVtYXAoY29yZS0+
YWRkciwgQkNNQV9DT1JFX1NJWkUpOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgaWYgKCFjb3Jl
LT5pb19hZGRyKQo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgcmV0dXJuIC1F
Tk9NRU07Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBjb3JlLT5pb193cmFwID0gaW9yZW1hcChj
b3JlLT53cmFwLCBCQ01BX0NPUkVfU0laRSk7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBpZiAo
IWNvcmUtPmlvX3dyYXApCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCByZXR1
cm4gLUVOT01FTTsKClNob3VsZG4ndCB5b3UgdW5tYXAgY29yZS0+aW9fYWRkciBpZiByZW1hcHBp
bmcgaW9fd3JhcCBmYWlscz8KCj4gKyDCoCDCoCDCoCB9Cj4gwqAgwqAgwqAgwqByZXR1cm4gMDsK
PiDCoH0KPgo+IEBAIC0zNjksNyArMzc3LDEzIEBAIGludCBiY21hX2J1c19zY2FuKHN0cnVjdCBi
Y21hX2J1cyAqYnVzKQo+IMKgIMKgIMKgIMKgYmNtYV9pbml0X2J1cyhidXMpOwo+Cj4gwqAgwqAg
wqAgwqBlcm9tYmFzZSA9IGJjbWFfc2Nhbl9yZWFkMzIoYnVzLCAwLCBCQ01BX0NDX0VST00pOwo+
IC0gwqAgwqAgwqAgZXJvbXB0ciA9IGJ1cy0+bW1pbzsKPiArIMKgIMKgIMKgIGlmIChidXMtPmhv
c3R0eXBlID09IEJDTUFfSE9TVFRZUEVfU09DKSB7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBl
cm9tcHRyID0gaW9yZW1hcChlcm9tYmFzZSwgQkNNQV9DT1JFX1NJWkUpOwo+ICsgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgaWYgKCFlcm9tcHRyKQo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgcmV0dXJuIC1FTk9NRU07Cj4gKyDCoCDCoCDCoCB9IGVsc2UKPiArIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIGVyb21wdHIgPSBidXMtPm1taW87CgpEb2N1bWVudGF0aW9uL0NvZGluZ1N0eWxl
IHNheXMgdXNlIGJyYWNlcyBpbiBib3RoIGJyYW5jaGVzIGlmIG9uZSBuZWVkcyB0aGVtLgoKPiAr
Cj4gwqAgwqAgwqAgwqBlcm9tZW5kID0gZXJvbXB0ciArIEJDTUFfQ09SRV9TSVpFIC8gc2l6ZW9m
KHUzMik7Cj4KPiDCoCDCoCDCoCDCoGJjbWFfc2Nhbl9zd2l0Y2hfY29yZShidXMsIGVyb21iYXNl
KTsKPiBAQCAtNDE3LDcgKzQzMSwxMyBAQCBpbnQgX19pbml0IGJjbWFfYnVzX3NjYW5fZWFybHko
c3RydWN0IGJjbWFfYnVzICpidXMsCj4gwqAgwqAgwqAgwqBpbnQgZXJyLCBjb3JlX251bSA9IDA7
Cj4KPiDCoCDCoCDCoCDCoGVyb21iYXNlID0gYmNtYV9zY2FuX3JlYWQzMihidXMsIDAsIEJDTUFf
Q0NfRVJPTSk7Cj4gLSDCoCDCoCDCoCBlcm9tcHRyID0gYnVzLT5tbWlvOwo+ICsgwqAgwqAgwqAg
aWYgKGJ1cy0+aG9zdHR5cGUgPT0gQkNNQV9IT1NUVFlQRV9TT0MpIHsKPiArIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIGVyb21wdHIgPSBpb3JlbWFwKGVyb21iYXNlLCBCQ01BX0NPUkVfU0laRSk7Cj4g
KyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBpZiAoIWVyb21wdHIpCj4gKyDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCByZXR1cm4gLUVOT01FTTsKPiArIMKgIMKgIMKgIH0gZWxzZQo+ICsg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgZXJvbXB0ciA9IGJ1cy0+bW1pbzsKCkRpdHRvLgoKPiArCj4g
wqAgwqAgwqAgwqBlcm9tZW5kID0gZXJvbXB0ciArIEJDTUFfQ09SRV9TSVpFIC8gc2l6ZW9mKHUz
Mik7Cj4KPiDCoCDCoCDCoCDCoGJjbWFfc2Nhbl9zd2l0Y2hfY29yZShidXMsIGVyb21iYXNlKTsK
PiBkaWZmIC0tZ2l0IGEvaW5jbHVkZS9saW51eC9iY21hL2JjbWEuaCBiL2luY2x1ZGUvbGludXgv
YmNtYS9iY21hLmgKPiBpbmRleCA2YmQ3YjdmLi43M2ZkYTFjIDEwMDY0NAo+IC0tLSBhL2luY2x1
ZGUvbGludXgvYmNtYS9iY21hLmgKPiArKysgYi9pbmNsdWRlL2xpbnV4L2JjbWEvYmNtYS5oCj4g
QEAgLTE2LDYgKzE2LDcgQEAgZW51bSBiY21hX2hvc3R0eXBlIHsKPiDCoCDCoCDCoCDCoEJDTUFf
SE9TVFRZUEVfTk9ORSwKPiDCoCDCoCDCoCDCoEJDTUFfSE9TVFRZUEVfUENJLAo+IMKgIMKgIMKg
IMKgQkNNQV9IT1NUVFlQRV9TRElPLAo+ICsgwqAgwqAgwqAgQkNNQV9IT1NUVFlQRV9TT0MsCj4g
wqB9Owo+Cj4gwqBzdHJ1Y3QgYmNtYV9jaGlwaW5mbyB7Cj4gQEAgLTEyNCw2ICsxMjUsOSBAQCBz
dHJ1Y3QgYmNtYV9kZXZpY2Ugewo+IMKgIMKgIMKgIMKgdTMyIGFkZHI7Cj4gwqAgwqAgwqAgwqB1
MzIgd3JhcDsKPgo+ICsgwqAgwqAgwqAgdm9pZCBfX2lvbWVtICppb19hZGRyOwo+ICsgwqAgwqAg
wqAgdm9pZCBfX2lvbWVtICppb193cmFwOwo+ICsKPiDCoCDCoCDCoCDCoHZvaWQgKmRydmRhdGE7
Cj4gwqAgwqAgwqAgwqBzdHJ1Y3QgbGlzdF9oZWFkIGxpc3Q7Cj4gwqB9Owo+IGRpZmYgLS1naXQg
YS9pbmNsdWRlL2xpbnV4L2JjbWEvYmNtYV9zb2MuaCBiL2luY2x1ZGUvbGludXgvYmNtYS9iY21h
X3NvYy5oCj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiBpbmRleCAwMDAwMDAwLi40MjAzYzU1Cj4g
LS0tIC9kZXYvbnVsbAo+ICsrKyBiL2luY2x1ZGUvbGludXgvYmNtYS9iY21hX3NvYy5oCj4gQEAg
LTAsMCArMSwxNiBAQAo+ICsjaWZuZGVmIExJTlVYX0JDTUFfU09DX0hfCj4gKyNkZWZpbmUgTElO
VVhfQkNNQV9TT0NfSF8KPiArCj4gKyNpbmNsdWRlIDxsaW51eC9iY21hL2JjbWEuaD4KPiArCj4g
K3N0cnVjdCBiY21hX3NvYyB7Cj4gKyDCoCDCoCDCoCBzdHJ1Y3QgYmNtYV9idXMgYnVzOwo+ICsg
wqAgwqAgwqAgc3RydWN0IGJjbWFfZGV2aWNlIGNvcmVfY2M7Cj4gKyDCoCDCoCDCoCBzdHJ1Y3Qg
YmNtYV9kZXZpY2UgY29yZV9taXBzOwo+ICt9Owo+ICsKPiAraW50IF9faW5pdCBiY21hX2hvc3Rf
c29jX3JlZ2lzdGVyKHN0cnVjdCBiY21hX3NvYyAqc29jKTsKPiArCj4gK2ludCBiY21hX2J1c19y
ZWdpc3RlcihzdHJ1Y3QgYmNtYV9idXMgKmJ1cyk7Cj4gKwo+ICsjZW5kaWYgLyogTElOVVhfQkNN
QV9TT0NfSF8gKi8KPiAtLQo+IDEuNy40LjEK
Prepare bcm47xx to support different System buses. Before adding
support for bcma it should be possible to build bcm47xx without the
need of ssb. With this patch bcm47xx does not directly contain a
ssb_bus, but a union contain all the supported system buses. As a SoC
just uses one system bus a union is a good choice.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
arch/mips/bcm47xx/gpio.c | 56 ++++++++++++++++----------
arch/mips/bcm47xx/nvram.c | 15 +++++--
arch/mips/bcm47xx/serial.c | 13 +++++-
arch/mips/bcm47xx/setup.c | 33 ++++++++++++---
arch/mips/bcm47xx/time.c | 9 +++-
arch/mips/bcm47xx/wgt634u.c | 14 ++++--
arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 14 ++++++-
arch/mips/include/asm/mach-bcm47xx/gpio.h | 55 ++++++++++++++++++-------
drivers/watchdog/bcm47xx_wdt.c | 12 +++++-
9 files changed, 160 insertions(+), 61 deletions(-)
diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
index e4a5ee9..99e1c50 100644
--- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c
@@ -20,42 +20,54 @@ static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES);
int gpio_request(unsigned gpio, const char *tag)
{
- if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
- return -EINVAL;
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
+ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+ return -EINVAL;
- if (ssb_extif_available(&ssb_bcm47xx.extif) &&
- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
- return -EINVAL;
+ if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
+ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+ return -EINVAL;
- if (test_and_set_bit(gpio, gpio_in_use))
- return -EBUSY;
+ if (test_and_set_bit(gpio, gpio_in_use))
+ return -EBUSY;
- return 0;
+ return 0;
+ }
+ return -EINVAL;
}
EXPORT_SYMBOL(gpio_request);
void gpio_free(unsigned gpio)
{
- if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
- return;
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
+ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+ return;
- if (ssb_extif_available(&ssb_bcm47xx.extif) &&
- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
- return;
+ if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
+ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+ return;
- clear_bit(gpio, gpio_in_use);
+ clear_bit(gpio, gpio_in_use);
+ return;
+ }
}
EXPORT_SYMBOL(gpio_free);
int gpio_to_irq(unsigned gpio)
{
- if (ssb_chipco_available(&ssb_bcm47xx.chipco))
- return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2;
- else if (ssb_extif_available(&ssb_bcm47xx.extif))
- return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
- else
- return -EINVAL;
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
+ return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
+ else if (ssb_extif_available(&bcm47xx_bus.ssb.extif))
+ return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
+ else
+ return -EINVAL;
+ }
+ return -EINVAL;
}
EXPORT_SYMBOL_GPL(gpio_to_irq);
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index 54db815..bcac2ff 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -26,14 +26,21 @@ static char nvram_buf[NVRAM_SPACE];
/* Probe for NVRAM header */
static void early_nvram_init(void)
{
- struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+ struct ssb_mipscore *mcore_ssb;
struct nvram_header *header;
int i;
- u32 base, lim, off;
+ u32 base = 0;
+ u32 lim = 0;
+ u32 off;
u32 *src, *dst;
- base = mcore->flash_window;
- lim = mcore->flash_window_size;
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ mcore_ssb = &bcm47xx_bus.ssb.mipscore;
+ base = mcore_ssb->flash_window;
+ lim = mcore_ssb->flash_window_size;
+ break;
+ }
off = FLASH_MIN;
while (off <= lim) {
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index 59c11af..17c67e2 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -23,10 +23,10 @@ static struct platform_device uart8250_device = {
},
};
-static int __init uart8250_init(void)
+static int __init uart8250_init_ssb(void)
{
int i;
- struct ssb_mipscore *mcore = &(ssb_bcm47xx.mipscore);
+ struct ssb_mipscore *mcore = &(bcm47xx_bus.ssb.mipscore);
memset(&uart8250_data, 0, sizeof(uart8250_data));
@@ -45,6 +45,15 @@ static int __init uart8250_init(void)
return platform_device_register(&uart8250_device);
}
+static int __init uart8250_init(void)
+{
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ return uart8250_init_ssb();
+ }
+ return -EINVAL;
+}
+
module_init(uart8250_init);
MODULE_AUTHOR("Aurelien Jarno <[email protected]>");
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 73b529b..9828b60 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -35,15 +35,22 @@
#include <bcm47xx.h>
#include <asm/mach-bcm47xx/nvram.h>
-struct ssb_bus ssb_bcm47xx;
-EXPORT_SYMBOL(ssb_bcm47xx);
+union bcm47xx_bus bcm47xx_bus;
+EXPORT_SYMBOL(bcm47xx_bus);
+
+enum bcm47xx_bus_type bcm47xx_bus_type;
+EXPORT_SYMBOL(bcm47xx_bus_type);
static void bcm47xx_machine_restart(char *command)
{
printk(KERN_ALERT "Please stand by while rebooting the system...\n");
local_irq_disable();
/* Set the watchdog timer to reset immediately */
- ssb_watchdog_timer_set(&ssb_bcm47xx, 1);
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
+ break;
+ }
while (1)
cpu_relax();
}
@@ -52,7 +59,11 @@ static void bcm47xx_machine_halt(void)
{
/* Disable interrupts and watchdog and spin forever */
local_irq_disable();
- ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+ break;
+ }
while (1)
cpu_relax();
}
@@ -247,7 +258,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
return 0;
}
-void __init plat_mem_setup(void)
+static void __init bcm47xx_register_ssb(void)
{
int err;
char buf[100];
@@ -258,12 +269,12 @@ void __init plat_mem_setup(void)
printk(KERN_WARNING "bcm47xx: someone else already registered"
" a ssb SPROM callback handler (err %d)\n", err);
- err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
+ err = ssb_bus_ssbbus_register(&(bcm47xx_bus.ssb), SSB_ENUM_BASE,
bcm47xx_get_invariants);
if (err)
panic("Failed to initialize SSB bus (err %d)\n", err);
- mcore = &ssb_bcm47xx.mipscore;
+ mcore = &bcm47xx_bus.ssb.mipscore;
if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
if (strstr(buf, "console=ttyS1")) {
struct ssb_serial_port port;
@@ -276,6 +287,14 @@ void __init plat_mem_setup(void)
memcpy(&mcore->serial_ports[1], &port, sizeof(port));
}
}
+}
+
+void __init plat_mem_setup(void)
+{
+ struct cpuinfo_mips *c = ¤t_cpu_data;
+
+ bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB;
+ bcm47xx_register_ssb();
_machine_restart = bcm47xx_machine_restart;
_machine_halt = bcm47xx_machine_halt;
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index 0c6f47b..50aea2e 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -30,7 +30,7 @@
void __init plat_time_init(void)
{
- unsigned long hz;
+ unsigned long hz = 0;
/*
* Use deterministic values for initial counter interrupt
@@ -39,7 +39,12 @@ void __init plat_time_init(void)
write_c0_count(0);
write_c0_compare(0xffff);
- hz = ssb_cpu_clock(&ssb_bcm47xx.mipscore) / 2;
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
+ break;
+ }
+
if (!hz)
hz = 100000000;
diff --git a/arch/mips/bcm47xx/wgt634u.c b/arch/mips/bcm47xx/wgt634u.c
index 74d0696..e9f9ec8 100644
--- a/arch/mips/bcm47xx/wgt634u.c
+++ b/arch/mips/bcm47xx/wgt634u.c
@@ -108,7 +108,7 @@ static irqreturn_t gpio_interrupt(int irq, void *ignored)
/* Interrupts are shared, check if the current one is
a GPIO interrupt. */
- if (!ssb_chipco_irq_status(&ssb_bcm47xx.chipco,
+ if (!ssb_chipco_irq_status(&bcm47xx_bus.ssb.chipco,
SSB_CHIPCO_IRQ_GPIO))
return IRQ_NONE;
@@ -132,22 +132,26 @@ static int __init wgt634u_init(void)
* machine. Use the MAC address as an heuristic. Netgear Inc. has
* been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
*/
+ u8 *et0mac;
- u8 *et0mac = ssb_bcm47xx.sprom.et0mac;
+ if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB)
+ return -ENODEV;
+
+ et0mac = bcm47xx_bus.ssb.sprom.et0mac;
if (et0mac[0] == 0x00 &&
((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
(et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
- struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+ struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
printk(KERN_INFO "WGT634U machine detected.\n");
if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
gpio_interrupt, IRQF_SHARED,
- "WGT634U GPIO", &ssb_bcm47xx.chipco)) {
+ "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
gpio_direction_input(WGT634U_GPIO_RESET);
gpio_intmask(WGT634U_GPIO_RESET, 1);
- ssb_chipco_irq_mask(&ssb_bcm47xx.chipco,
+ ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco,
SSB_CHIPCO_IRQ_GPIO,
SSB_CHIPCO_IRQ_GPIO);
}
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index d008f47..7cf481b 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -19,7 +19,17 @@
#ifndef __ASM_BCM47XX_H
#define __ASM_BCM47XX_H
-/* SSB bus */
-extern struct ssb_bus ssb_bcm47xx;
+#include <linux/ssb/ssb.h>
+
+enum bcm47xx_bus_type {
+ BCM47XX_BUS_TYPE_SSB,
+};
+
+union bcm47xx_bus {
+ struct ssb_bus ssb;
+};
+
+extern union bcm47xx_bus bcm47xx_bus;
+extern enum bcm47xx_bus_type bcm47xx_bus_type;
#endif /* __ASM_BCM47XX_H */
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 9850414..6b78827 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -21,41 +21,66 @@ extern int gpio_to_irq(unsigned gpio);
static inline int gpio_get_value(unsigned gpio)
{
- return ssb_gpio_in(&ssb_bcm47xx, 1 << gpio);
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
+ }
+ return -EINVAL;
}
static inline void gpio_set_value(unsigned gpio, int value)
{
- ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
+ }
}
static inline int gpio_direction_input(unsigned gpio)
{
- ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
- return 0;
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
+ return 0;
+ }
+ return -EINVAL;
}
static inline int gpio_direction_output(unsigned gpio, int value)
{
- /* first set the gpio out value */
- ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
- /* then set the gpio mode */
- ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
- return 0;
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ /* first set the gpio out value */
+ ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
+ /* then set the gpio mode */
+ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
+ return 0;
+ }
+ return -EINVAL;
}
static inline int gpio_intmask(unsigned gpio, int value)
{
- ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
- value ? 1 << gpio : 0);
- return 0;
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
+ return 0;
+ }
+ return -EINVAL;
}
static inline int gpio_polarity(unsigned gpio, int value)
{
- ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
- value ? 1 << gpio : 0);
- return 0;
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
+ return 0;
+ }
+ return -EINVAL;
}
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index bd44417..c43406c 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -54,12 +54,20 @@ static atomic_t ticks;
static inline void bcm47xx_wdt_hw_start(void)
{
/* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */
- ssb_watchdog_timer_set(&ssb_bcm47xx, 0xfffffff);
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
+ break;
+ }
}
static inline int bcm47xx_wdt_hw_stop(void)
{
- return ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
+ switch (bcm47xx_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+ }
+ return -EINVAL;
}
static void bcm47xx_timer_tick(unsigned long unused)
--
1.7.4.1
This patch add support for the bcma bus. Broadcom uses only Mips 74K
CPUs on the new SoC and on the old ons using ssb bus there are no Mips
74K CPUs.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
arch/mips/bcm47xx/Kconfig | 13 ++++++
arch/mips/bcm47xx/gpio.c | 22 +++++++++++
arch/mips/bcm47xx/nvram.c | 10 +++++
arch/mips/bcm47xx/serial.c | 29 ++++++++++++++
arch/mips/bcm47xx/setup.c | 53 +++++++++++++++++++++++++-
arch/mips/bcm47xx/time.c | 5 ++
arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 8 ++++
arch/mips/include/asm/mach-bcm47xx/gpio.h | 41 ++++++++++++++++++++
drivers/watchdog/bcm47xx_wdt.c | 11 +++++
9 files changed, 190 insertions(+), 2 deletions(-)
diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
index 0346f92..6210b8d 100644
--- a/arch/mips/bcm47xx/Kconfig
+++ b/arch/mips/bcm47xx/Kconfig
@@ -15,4 +15,17 @@ config BCM47XX_SSB
This will generate an image with support for SSB and MIPS32 R1 instruction set.
+config BCM47XX_BCMA
+ bool "BCMA Support for Broadcom BCM47XX"
+ select SYS_HAS_CPU_MIPS32_R2
+ select BCMA
+ select BCMA_HOST_SOC
+ select BCMA_DRIVER_MIPS
+ select BCMA_DRIVER_PCI_HOSTMODE if PCI
+ default y
+ help
+ Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
+
+ This will generate an image with support for BCMA and MIPS32 R2 instruction set.
+
endif
diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
index 2b804c3..57b425f 100644
--- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c
@@ -36,6 +36,16 @@ int gpio_request(unsigned gpio, const char *tag)
return 0;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
+ return -EINVAL;
+
+ if (test_and_set_bit(gpio, gpio_in_use))
+ return -EBUSY;
+
+ return 0;
+#endif
}
return -EINVAL;
}
@@ -57,6 +67,14 @@ void gpio_free(unsigned gpio)
clear_bit(gpio, gpio_in_use);
return;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
+ return;
+
+ clear_bit(gpio, gpio_in_use);
+ return;
+#endif
}
}
EXPORT_SYMBOL(gpio_free);
@@ -73,6 +91,10 @@ int gpio_to_irq(unsigned gpio)
else
return -EINVAL;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ return bcma_core_mips_irq(bcm47xx_bus.bcma.bus.drv_cc.core) + 2;
+#endif
}
return -EINVAL;
}
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index 4e994ed..a84e3bb 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -29,6 +29,9 @@ static void early_nvram_init(void)
#ifdef CONFIG_BCM47XX_SSB
struct ssb_mipscore *mcore_ssb;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ struct bcma_drv_cc *bcma_cc;
+#endif
struct nvram_header *header;
int i;
u32 base = 0;
@@ -44,6 +47,13 @@ static void early_nvram_init(void)
lim = mcore_ssb->flash_window_size;
break;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
+ base = bcma_cc->pflash.window;
+ lim = bcma_cc->pflash.window_size;
+ break;
+#endif
}
off = FLASH_MIN;
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index fcef688..57981e4 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -47,6 +47,31 @@ static int __init uart8250_init_ssb(void)
}
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+static int __init uart8250_init_bcma(void)
+{
+ int i;
+ struct bcma_drv_cc *cc = &(bcm47xx_bus.bcma.bus.drv_cc);
+
+ memset(&uart8250_data, 0, sizeof(uart8250_data));
+
+ for (i = 0; i < cc->nr_serial_ports; i++) {
+ struct plat_serial8250_port *p = &(uart8250_data[i]);
+ struct bcma_serial_port *bcma_port;
+ bcma_port = &(cc->serial_ports[i]);
+
+ p->mapbase = (unsigned int) bcma_port->regs;
+ p->membase = (void *) bcma_port->regs;
+ p->irq = bcma_port->irq + 2;
+ p->uartclk = bcma_port->baud_base;
+ p->regshift = bcma_port->reg_shift;
+ p->iotype = UPIO_MEM;
+ p->flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+ }
+ return platform_device_register(&uart8250_device);
+}
+#endif
+
static int __init uart8250_init(void)
{
switch (bcm47xx_bus_type) {
@@ -54,6 +79,10 @@ static int __init uart8250_init(void)
case BCM47XX_BUS_TYPE_SSB:
return uart8250_init_ssb();
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ return uart8250_init_bcma();
+#endif
}
return -EINVAL;
}
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 39e8465..ab45b08 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -29,6 +29,7 @@
#include <linux/types.h>
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_embedded.h>
+#include <linux/bcma/bcma_soc.h>
#include <asm/bootinfo.h>
#include <asm/reboot.h>
#include <asm/time.h>
@@ -52,6 +53,11 @@ static void bcm47xx_machine_restart(char *command)
ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
break;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 1);
+ break;
+#endif
}
while (1)
cpu_relax();
@@ -67,6 +73,11 @@ static void bcm47xx_machine_halt(void)
ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
break;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
+ break;
+#endif
}
while (1)
cpu_relax();
@@ -295,16 +306,54 @@ static void __init bcm47xx_register_ssb(void)
}
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+static void __init bcm47xx_register_bcma(void)
+{
+ int err;
+
+ err = bcma_host_soc_register(&bcm47xx_bus.bcma);
+ if (err)
+ panic("Failed to initialize BCMA bus (err %d)\n", err);
+}
+#endif
+
void __init plat_mem_setup(void)
{
struct cpuinfo_mips *c = ¤t_cpu_data;
+ if (c->cputype == CPU_74K) {
+ printk(KERN_INFO "bcm47xx: using bcma bus\n");
+#ifdef CONFIG_BCM47XX_BCMA
+ bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA;
+ bcm47xx_register_bcma();
+#endif
+ } else {
+ printk(KERN_INFO "bcm47xx: using ssb bus\n");
#ifdef CONFIG_BCM47XX_SSB
- bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB;
- bcm47xx_register_ssb();
+ bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB;
+ bcm47xx_register_ssb();
#endif
+ }
_machine_restart = bcm47xx_machine_restart;
_machine_halt = bcm47xx_machine_halt;
pm_power_off = bcm47xx_machine_halt;
}
+
+static int __init bcm47xx_register_bus_complete(void)
+{
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ /* Nothing to do */
+ break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_bus_register(&bcm47xx_bus.bcma.bus);
+ break;
+#endif
+ }
+ return 0;
+}
+device_initcall(bcm47xx_register_bus_complete);
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index 03dfc65..536374d 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -45,6 +45,11 @@ void __init plat_time_init(void)
hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
break;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ hz = bcma_cpu_clock(&bcm47xx_bus.bcma.bus.drv_mips) / 2;
+ break;
+#endif
}
if (!hz)
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index d037afb..de95e07 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -20,17 +20,25 @@
#define __ASM_BCM47XX_H
#include <linux/ssb/ssb.h>
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_soc.h>
enum bcm47xx_bus_type {
#ifdef CONFIG_BCM47XX_SSB
BCM47XX_BUS_TYPE_SSB,
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ BCM47XX_BUS_TYPE_BCMA,
+#endif
};
union bcm47xx_bus {
#ifdef CONFIG_BCM47XX_SSB
struct ssb_bus ssb;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ struct bcma_soc bcma;
+#endif
};
extern union bcm47xx_bus bcm47xx_bus;
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 1d5f5af..76961ca 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -10,6 +10,7 @@
#define __BCM47XX_GPIO_H
#include <linux/ssb/ssb_embedded.h>
+#include <linux/bcma/bcma.h>
#include <asm/mach-bcm47xx/bcm47xx.h>
#define BCM47XX_EXTIF_GPIO_LINES 5
@@ -26,6 +27,11 @@ static inline int gpio_get_value(unsigned gpio)
case BCM47XX_BUS_TYPE_SSB:
return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ return bcma_chipco_gpio_in(&bcm47xx_bus.bcma.bus.drv_cc,
+ 1 << gpio);
+#endif
}
return -EINVAL;
}
@@ -37,6 +43,13 @@ static inline void gpio_set_value(unsigned gpio, int value)
case BCM47XX_BUS_TYPE_SSB:
ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
value ? 1 << gpio : 0);
+ return;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+ value ? 1 << gpio : 0);
+ return;
#endif
}
}
@@ -49,6 +62,12 @@ static inline int gpio_direction_input(unsigned gpio)
ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
return 0;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+ 0);
+ return 0;
+#endif
}
return -EINVAL;
}
@@ -65,6 +84,16 @@ static inline int gpio_direction_output(unsigned gpio, int value)
ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
return 0;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ /* first set the gpio out value */
+ bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+ value ? 1 << gpio : 0);
+ /* then set the gpio mode */
+ bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+ 1 << gpio);
+ return 0;
+#endif
}
return -EINVAL;
}
@@ -78,6 +107,12 @@ static inline int gpio_intmask(unsigned gpio, int value)
value ? 1 << gpio : 0);
return 0;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_gpio_intmask(&bcm47xx_bus.bcma.bus.drv_cc,
+ 1 << gpio, value ? 1 << gpio : 0);
+ return 0;
+#endif
}
return -EINVAL;
}
@@ -91,6 +126,12 @@ static inline int gpio_polarity(unsigned gpio, int value)
value ? 1 << gpio : 0);
return 0;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_gpio_polarity(&bcm47xx_bus.bcma.bus.drv_cc,
+ 1 << gpio, value ? 1 << gpio : 0);
+ return 0;
+#endif
}
return -EINVAL;
}
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index 6b03702..5c5f4b1 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -60,6 +60,12 @@ static inline void bcm47xx_wdt_hw_start(void)
ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
break;
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc,
+ 0xfffffff);
+ break;
+#endif
}
}
@@ -70,6 +76,11 @@ static inline int bcm47xx_wdt_hw_stop(void)
case BCM47XX_BUS_TYPE_SSB:
return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
+ return 0;
+#endif
}
return -EINVAL;
}
--
1.7.4.1
This adds support for serial console to bcma, when operating on an SoC.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
drivers/bcma/bcma_private.h | 8 ++++
drivers/bcma/driver_chipcommon.c | 48 +++++++++++++++++++++++++++
drivers/bcma/driver_chipcommon_pmu.c | 26 ++++++++++++++
drivers/bcma/driver_mips.c | 1 +
include/linux/bcma/bcma_driver_chipcommon.h | 14 ++++++++
5 files changed, 97 insertions(+), 0 deletions(-)
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index b97633d..22d3052 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -29,6 +29,14 @@ 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);
+
#ifdef CONFIG_BCMA_HOST_PCI
/* host_pci.c */
extern int __init bcma_host_pci_init(void);
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index 75f1ad7..12b42ea 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -106,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 dd5846b..59d2b26 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -136,3 +136,29 @@ 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;
+}
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
index 4b60c9f9..b17233c 100644
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -238,6 +238,7 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore)
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/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 03cde8d..b9a930e 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -241,6 +241,9 @@
#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
#define BCMA_CC_SPROM_PCIE6 0x0830 /* SPROM beginning on PCIe rev >= 6 */
+/* ALP clock on pre-PMU chips */
+#define BCMA_CC_PMU_ALP_CLOCK 20000000
+
/* Data for the PMU, if available.
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
*/
@@ -255,6 +258,14 @@ struct bcma_pflash {
u32 window;
u32 window_size;
};
+
+struct bcma_serial_port {
+ void *regs;
+ unsigned long clockspeed;
+ unsigned int irq;
+ unsigned int baud_base;
+ unsigned int reg_shift;
+};
#endif /* CONFIG_BCMA_DRIVER_MIPS */
struct bcma_drv_cc {
@@ -268,6 +279,9 @@ struct bcma_drv_cc {
struct bcma_chipcommon_pmu pmu;
#ifdef CONFIG_BCMA_DRIVER_MIPS
struct bcma_pflash pflash;
+
+ int nr_serial_ports;
+ struct bcma_serial_port serial_ports[4];
#endif /* CONFIG_BCMA_DRIVER_MIPS */
};
--
1.7.4.1