aboutsummaryrefslogtreecommitdiff
path: root/drivers/bcma
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bcma')
-rw-r--r--drivers/bcma/bcma_private.h2
-rw-r--r--drivers/bcma/driver_chipcommon.c114
-rw-r--r--drivers/bcma/driver_pci_host.c10
-rw-r--r--drivers/bcma/main.c8
4 files changed, 126 insertions, 8 deletions
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 169fc58427d3..bcb830ec4bb4 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -84,6 +84,8 @@ extern void __exit bcma_host_pci_exit(void);
/* driver_pci.c */
u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
+extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc);
+
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index ffd74e51f02d..d017f2512275 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -4,12 +4,15 @@
*
* Copyright 2005, Broadcom Corporation
* Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+ * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include "bcma_private.h"
+#include <linux/bcm47xx_wdt.h>
#include <linux/export.h>
+#include <linux/platform_device.h>
#include <linux/bcma/bcma.h>
static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
@@ -22,6 +25,90 @@ static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
return value;
}
+static u32 bcma_chipco_alp_clock(struct bcma_drv_cc *cc)
+{
+ if (cc->capabilities & BCMA_CC_CAP_PMU)
+ return bcma_pmu_alp_clock(cc);
+
+ return 20000000;
+}
+
+static u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+ u32 nb;
+
+ if (cc->capabilities & BCMA_CC_CAP_PMU) {
+ if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
+ nb = 32;
+ else if (cc->core->id.rev < 26)
+ nb = 16;
+ else
+ nb = (cc->core->id.rev >= 37) ? 32 : 24;
+ } else {
+ nb = 28;
+ }
+ if (nb == 32)
+ return 0xffffffff;
+ else
+ return (1 << nb) - 1;
+}
+
+static u32 bcma_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt,
+ u32 ticks)
+{
+ struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt);
+
+ return bcma_chipco_watchdog_timer_set(cc, ticks);
+}
+
+static u32 bcma_chipco_watchdog_timer_set_ms_wdt(struct bcm47xx_wdt *wdt,
+ u32 ms)
+{
+ struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt);
+ u32 ticks;
+
+ ticks = bcma_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms);
+ return ticks / cc->ticks_per_ms;
+}
+
+static int bcma_chipco_watchdog_ticks_per_ms(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ if (cc->capabilities & BCMA_CC_CAP_PMU) {
+ if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
+ /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP clock */
+ return bcma_chipco_alp_clock(cc) / 4000;
+ else
+ /* based on 32KHz ILP clock */
+ return 32;
+ } else {
+ return bcma_chipco_alp_clock(cc) / 1000;
+ }
+}
+
+int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc)
+{
+ struct bcm47xx_wdt wdt = {};
+ struct platform_device *pdev;
+
+ wdt.driver_data = cc;
+ wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt;
+ wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt;
+ wdt.max_timer_ms = bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
+
+ pdev = platform_device_register_data(NULL, "bcm47xx-wdt",
+ cc->core->bus->num, &wdt,
+ sizeof(wdt));
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ cc->watchdog = pdev;
+
+ return 0;
+}
+
void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
{
if (cc->early_setup_done)
@@ -69,15 +156,33 @@ 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->ticks_per_ms = bcma_chipco_watchdog_ticks_per_ms(cc);
cc->setup_done = true;
}
/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
-void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
+u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
{
- /* instant NMI */
- bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks);
+ u32 maxt;
+ enum bcma_clkmode clkmode;
+
+ maxt = bcma_chipco_watchdog_get_max_timer(cc);
+ if (cc->capabilities & BCMA_CC_CAP_PMU) {
+ if (ticks == 1)
+ ticks = 2;
+ else if (ticks > maxt)
+ ticks = maxt;
+ bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
+ } else {
+ clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC;
+ bcma_core_set_clockmode(cc->core, clkmode);
+ if (ticks > maxt)
+ ticks = maxt;
+ /* instant NMI */
+ bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks);
+ }
+ return ticks;
}
void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value)
@@ -131,8 +236,7 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
struct bcma_serial_port *ports = cc->serial_ports;
if (ccrev >= 11 && ccrev != 15) {
- /* Fixed ALP clock */
- baud_base = bcma_pmu_alp_clock(cc);
+ baud_base = bcma_chipco_alp_clock(cc);
if (ccrev >= 21) {
/* Turn off UART clock before switching clocksource. */
bcma_cc_write32(cc, BCMA_CC_CORECTL,
diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c
index e56449506695..e6b5c89469dc 100644
--- a/drivers/bcma/driver_pci_host.c
+++ b/drivers/bcma/driver_pci_host.c
@@ -538,7 +538,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_pcibridge);
static void bcma_core_pci_fixup_addresses(struct pci_dev *dev)
{
struct resource *res;
- int pos;
+ int pos, err;
if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
/* This is not a device on the PCI-core bridge. */
@@ -551,8 +551,12 @@ static void bcma_core_pci_fixup_addresses(struct pci_dev *dev)
for (pos = 0; pos < 6; pos++) {
res = &dev->resource[pos];
- if (res->flags & (IORESOURCE_IO | IORESOURCE_MEM))
- pci_assign_resource(dev, pos);
+ if (res->flags & (IORESOURCE_IO | IORESOURCE_MEM)) {
+ err = pci_assign_resource(dev, pos);
+ if (err)
+ pr_err("PCI: Problem fixing up the addresses on %s\n",
+ pci_name(dev));
+ }
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_addresses);
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index a9718893000b..debd4f142f93 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -165,6 +165,12 @@ static int bcma_register_cores(struct bcma_bus *bus)
}
#endif
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+ err = bcma_chipco_watchdog_register(&bus->drv_cc);
+ if (err)
+ bcma_err(bus, "Error registering watchdog driver\n");
+ }
+
return 0;
}
@@ -177,6 +183,8 @@ static void bcma_unregister_cores(struct bcma_bus *bus)
if (core->dev_registered)
device_unregister(&core->dev);
}
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+ platform_device_unregister(bus->drv_cc.watchdog);
}
int __devinit bcma_bus_register(struct bcma_bus *bus)