brcm47xx: update watchdog driver
authorHauke Mehrtens <hauke@hauke-m.de>
Sat, 24 Nov 2012 20:07:25 +0000 (20:07 +0000)
committerHauke Mehrtens <hauke@hauke-m.de>
Sat, 24 Nov 2012 20:07:25 +0000 (20:07 +0000)
This watchdog driver should work with SoC having a PMU.

This fixes #11720.

SVN-Revision: 34323

17 files changed:
target/linux/brcm47xx/config-3.6
target/linux/brcm47xx/patches-3.6/540-watchdog-bcm47xx_wdt.c-convert-to-watchdog-core-api.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/541-watchdog-bcm47xx_wdt.c-use-platform-device.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/542-watchdog-bcm47xx_wdt.c-rename-ops-methods.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/543-watchdog-bcm47xx_wdt.c-rename-wdt_timeout-to-timeout.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/544-watchdog-bcm47xx_wdt.c-add-hard-timer.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/545-bcma-add-bcma_chipco_alp_clock.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/546-bcma-set-the-pmu-watchdog-if-available.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/547-bcma-add-methods-for-watchdog-driver.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/548-bcma-register-watchdog-driver.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/549-ssb-get-alp-clock-from-devices-with-PMU.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/550-ssb-set-the-pmu-watchdog-if-available.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/551-ssb-add-methods-for-watchdog-driver.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/552-ssb-extif-add-check-for-max-value-in-watchdog.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/553-ssb-extif-add-methods-for-watchdog-driver.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/554-ssb-register-watchdog-driver.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.6/900-bcm47xx_wdt-noprescale.patch [deleted file]

index 278e58cf0fea0fe685475285f4fd366c7d5961d2..4859a5b6d1b329124a4af491466edc9b265f7e86 100644 (file)
@@ -144,5 +144,6 @@ CONFIG_USB_ARCH_HAS_XHCI=y
 # CONFIG_USB_HCD_BCMA is not set
 # CONFIG_USB_HCD_SSB is not set
 CONFIG_USB_SUPPORT=y
+CONFIG_WATCHDOG_CORE=y
 CONFIG_WATCHDOG_NOWAYOUT=y
 CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/brcm47xx/patches-3.6/540-watchdog-bcm47xx_wdt.c-convert-to-watchdog-core-api.patch b/target/linux/brcm47xx/patches-3.6/540-watchdog-bcm47xx_wdt.c-convert-to-watchdog-core-api.patch
new file mode 100644 (file)
index 0000000..7ac5638
--- /dev/null
@@ -0,0 +1,252 @@
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -959,6 +959,7 @@ config ATH79_WDT
+ config BCM47XX_WDT
+       tristate "Broadcom BCM47xx Watchdog Timer"
+       depends on BCM47XX
++      select WATCHDOG_CORE
+       help
+         Hardware driver for the Broadcom BCM47xx Watchdog Timer.
+--- a/drivers/watchdog/bcm47xx_wdt.c
++++ b/drivers/watchdog/bcm47xx_wdt.c
+@@ -14,15 +14,12 @@
+ #include <linux/bitops.h>
+ #include <linux/errno.h>
+-#include <linux/fs.h>
+ #include <linux/init.h>
+ #include <linux/kernel.h>
+-#include <linux/miscdevice.h>
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+ #include <linux/reboot.h>
+ #include <linux/types.h>
+-#include <linux/uaccess.h>
+ #include <linux/watchdog.h>
+ #include <linux/timer.h>
+ #include <linux/jiffies.h>
+@@ -48,8 +45,6 @@ MODULE_PARM_DESC(nowayout,
+                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+ #endif
+-static unsigned long bcm47xx_wdt_busy;
+-static char expect_release;
+ static struct timer_list wdt_timer;
+ static atomic_t ticks;
+@@ -97,29 +92,31 @@ static void bcm47xx_timer_tick(unsigned
+       }
+ }
+-static inline void bcm47xx_wdt_pet(void)
++static int bcm47xx_wdt_keepalive(struct watchdog_device *wdd)
+ {
+       atomic_set(&ticks, wdt_time);
++
++      return 0;
+ }
+-static void bcm47xx_wdt_start(void)
++static int bcm47xx_wdt_start(struct watchdog_device *wdd)
+ {
+       bcm47xx_wdt_pet();
+       bcm47xx_timer_tick(0);
++
++      return 0;
+ }
+-static void bcm47xx_wdt_pause(void)
++static int bcm47xx_wdt_stop(struct watchdog_device *wdd)
+ {
+       del_timer_sync(&wdt_timer);
+       bcm47xx_wdt_hw_stop();
+-}
+-static void bcm47xx_wdt_stop(void)
+-{
+-      bcm47xx_wdt_pause();
++      return 0;
+ }
+-static int bcm47xx_wdt_settimeout(int new_time)
++static int bcm47xx_wdt_set_timeout(struct watchdog_device *wdd,
++                                 unsigned int new_time)
+ {
+       if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
+               return -EINVAL;
+@@ -128,51 +125,6 @@ static int bcm47xx_wdt_settimeout(int ne
+       return 0;
+ }
+-static int bcm47xx_wdt_open(struct inode *inode, struct file *file)
+-{
+-      if (test_and_set_bit(0, &bcm47xx_wdt_busy))
+-              return -EBUSY;
+-
+-      bcm47xx_wdt_start();
+-      return nonseekable_open(inode, file);
+-}
+-
+-static int bcm47xx_wdt_release(struct inode *inode, struct file *file)
+-{
+-      if (expect_release == 42) {
+-              bcm47xx_wdt_stop();
+-      } else {
+-              pr_crit("Unexpected close, not stopping watchdog!\n");
+-              bcm47xx_wdt_start();
+-      }
+-
+-      clear_bit(0, &bcm47xx_wdt_busy);
+-      expect_release = 0;
+-      return 0;
+-}
+-
+-static ssize_t bcm47xx_wdt_write(struct file *file, const char __user *data,
+-                              size_t len, loff_t *ppos)
+-{
+-      if (len) {
+-              if (!nowayout) {
+-                      size_t i;
+-
+-                      expect_release = 0;
+-
+-                      for (i = 0; i != len; i++) {
+-                              char c;
+-                              if (get_user(c, data + i))
+-                                      return -EFAULT;
+-                              if (c == 'V')
+-                                      expect_release = 42;
+-                      }
+-              }
+-              bcm47xx_wdt_pet();
+-      }
+-      return len;
+-}
+-
+ static const struct watchdog_info bcm47xx_wdt_info = {
+       .identity       = DRV_NAME,
+       .options        = WDIOF_SETTIMEOUT |
+@@ -180,80 +132,25 @@ static const struct watchdog_info bcm47x
+                               WDIOF_MAGICCLOSE,
+ };
+-static long bcm47xx_wdt_ioctl(struct file *file,
+-                                      unsigned int cmd, unsigned long arg)
+-{
+-      void __user *argp = (void __user *)arg;
+-      int __user *p = argp;
+-      int new_value, retval = -EINVAL;
+-
+-      switch (cmd) {
+-      case WDIOC_GETSUPPORT:
+-              return copy_to_user(argp, &bcm47xx_wdt_info,
+-                              sizeof(bcm47xx_wdt_info)) ? -EFAULT : 0;
+-
+-      case WDIOC_GETSTATUS:
+-      case WDIOC_GETBOOTSTATUS:
+-              return put_user(0, p);
+-
+-      case WDIOC_SETOPTIONS:
+-              if (get_user(new_value, p))
+-                      return -EFAULT;
+-
+-              if (new_value & WDIOS_DISABLECARD) {
+-                      bcm47xx_wdt_stop();
+-                      retval = 0;
+-              }
+-
+-              if (new_value & WDIOS_ENABLECARD) {
+-                      bcm47xx_wdt_start();
+-                      retval = 0;
+-              }
+-
+-              return retval;
+-
+-      case WDIOC_KEEPALIVE:
+-              bcm47xx_wdt_pet();
+-              return 0;
+-
+-      case WDIOC_SETTIMEOUT:
+-              if (get_user(new_value, p))
+-                      return -EFAULT;
+-
+-              if (bcm47xx_wdt_settimeout(new_value))
+-                      return -EINVAL;
+-
+-              bcm47xx_wdt_pet();
+-
+-      case WDIOC_GETTIMEOUT:
+-              return put_user(wdt_time, p);
+-
+-      default:
+-              return -ENOTTY;
+-      }
+-}
+-
+ static int bcm47xx_wdt_notify_sys(struct notifier_block *this,
+-      unsigned long code, void *unused)
++                                unsigned long code, void *unused)
+ {
+       if (code == SYS_DOWN || code == SYS_HALT)
+               bcm47xx_wdt_stop();
+       return NOTIFY_DONE;
+ }
+-static const struct file_operations bcm47xx_wdt_fops = {
++static struct watchdog_ops bcm47xx_wdt_ops = {
+       .owner          = THIS_MODULE,
+-      .llseek         = no_llseek,
+-      .unlocked_ioctl = bcm47xx_wdt_ioctl,
+-      .open           = bcm47xx_wdt_open,
+-      .release        = bcm47xx_wdt_release,
+-      .write          = bcm47xx_wdt_write,
++      .start          = bcm47xx_wdt_start,
++      .stop           = bcm47xx_wdt_stop,
++      .ping           = bcm47xx_wdt_keepalive,
++      .set_timeout    = bcm47xx_wdt_set_timeout,
+ };
+-static struct miscdevice bcm47xx_wdt_miscdev = {
+-      .minor          = WATCHDOG_MINOR,
+-      .name           = "watchdog",
+-      .fops           = &bcm47xx_wdt_fops,
++static struct watchdog_device bcm47xx_wdt_wdd = {
++      .info           = &bcm47xx_wdt_info,
++      .ops            = &bcm47xx_wdt_ops,
+ };
+ static struct notifier_block bcm47xx_wdt_notifier = {
+@@ -274,12 +171,13 @@ static int __init bcm47xx_wdt_init(void)
+               pr_info("wdt_time value must be 0 < wdt_time < %d, using %d\n",
+                       (WDT_MAX_TIME + 1), wdt_time);
+       }
++      watchdog_set_nowayout(&bcm47xx_wdt_wdd, nowayout);
+       ret = register_reboot_notifier(&bcm47xx_wdt_notifier);
+       if (ret)
+               return ret;
+-      ret = misc_register(&bcm47xx_wdt_miscdev);
++      ret = watchdog_register_device(&bcm47xx_wdt_wdd);
+       if (ret) {
+               unregister_reboot_notifier(&bcm47xx_wdt_notifier);
+               return ret;
+@@ -292,10 +190,8 @@ static int __init bcm47xx_wdt_init(void)
+ static void __exit bcm47xx_wdt_exit(void)
+ {
+-      if (!nowayout)
+-              bcm47xx_wdt_stop();
+-
+-      misc_deregister(&bcm47xx_wdt_miscdev);
++      watchdog_stop(&bcm47xx_wdt_wdd);
++      watchdog_unregister_device(&bcm47xx_wdt_wdd);
+       unregister_reboot_notifier(&bcm47xx_wdt_notifier);
+ }
+@@ -306,4 +202,3 @@ module_exit(bcm47xx_wdt_exit);
+ MODULE_AUTHOR("Aleksandar Radovanovic");
+ MODULE_DESCRIPTION("Watchdog driver for Broadcom BCM47xx");
+ MODULE_LICENSE("GPL");
+-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/target/linux/brcm47xx/patches-3.6/541-watchdog-bcm47xx_wdt.c-use-platform-device.patch b/target/linux/brcm47xx/patches-3.6/541-watchdog-bcm47xx_wdt.c-use-platform-device.patch
new file mode 100644 (file)
index 0000000..79bb962
--- /dev/null
@@ -0,0 +1,288 @@
+--- a/drivers/watchdog/bcm47xx_wdt.c
++++ b/drivers/watchdog/bcm47xx_wdt.c
+@@ -3,6 +3,7 @@
+  *
+  *  Copyright (C) 2008 Aleksandar Radovanovic <biblbroks@sezampro.rs>
+  *  Copyright (C) 2009 Matthieu CASTET <castet.matthieu@free.fr>
++ *  Copyright (C) 2012 Hauke Mehrtens <hauke@hauke-m.de>
+  *
+  *  This program is free software; you can redistribute it and/or
+  *  modify it under the terms of the GNU General Public License
+@@ -12,19 +13,19 @@
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++#include <linux/bcm47xx_wdt.h>
+ #include <linux/bitops.h>
+ #include <linux/errno.h>
+ #include <linux/init.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
++#include <linux/platform_device.h>
+ #include <linux/reboot.h>
+ #include <linux/types.h>
+ #include <linux/watchdog.h>
+ #include <linux/timer.h>
+ #include <linux/jiffies.h>
+-#include <linux/ssb/ssb_embedded.h>
+-#include <asm/mach-bcm47xx/bcm47xx.h>
+ #define DRV_NAME              "bcm47xx_wdt"
+@@ -45,48 +46,19 @@ MODULE_PARM_DESC(nowayout,
+                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+ #endif
+-static struct timer_list wdt_timer;
+-static atomic_t ticks;
+-
+-static inline void bcm47xx_wdt_hw_start(void)
++static inline struct bcm47xx_wdt *bcm47xx_wdt_get(struct watchdog_device *wdd)
+ {
+-      /* 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
+-#ifdef CONFIG_BCM47XX_BCMA
+-      case BCM47XX_BUS_TYPE_BCMA:
+-              bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc,
+-                                             0xfffffff);
+-              break;
+-#endif
+-      }
++      return container_of(wdd, struct bcm47xx_wdt, wdd);
+ }
+-static inline int bcm47xx_wdt_hw_stop(void)
++static void bcm47xx_timer_tick(unsigned long data)
+ {
+-      switch (bcm47xx_bus_type) {
+-#ifdef CONFIG_BCM47XX_SSB
+-      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;
+-}
++      struct bcm47xx_wdt *wdt = (struct bcm47xx_wdt *)data;
++      u32 next_tick = min(wdt->wdd.timeout * 1000, wdt->max_timer_ms);
+-static void bcm47xx_timer_tick(unsigned long unused)
+-{
+-      if (!atomic_dec_and_test(&ticks)) {
+-              bcm47xx_wdt_hw_start();
+-              mod_timer(&wdt_timer, jiffies + HZ);
++      if (!atomic_dec_and_test(&wdt->soft_ticks)) {
++              wdt->timer_set_ms(wdt, next_tick);
++              mod_timer(&wdt->soft_timer, jiffies + HZ);
+       } else {
+               pr_crit("Watchdog will fire soon!!!\n");
+       }
+@@ -94,23 +66,29 @@ static void bcm47xx_timer_tick(unsigned
+ static int bcm47xx_wdt_keepalive(struct watchdog_device *wdd)
+ {
+-      atomic_set(&ticks, wdt_time);
++      struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
++
++      atomic_set(&wdt->soft_ticks, wdd->timeout);
+       return 0;
+ }
+ static int bcm47xx_wdt_start(struct watchdog_device *wdd)
+ {
+-      bcm47xx_wdt_pet();
+-      bcm47xx_timer_tick(0);
++      struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
++
++      bcm47xx_wdt_keepalive(wdd);
++      bcm47xx_timer_tick((unsigned long)wdt);
+       return 0;
+ }
+ static int bcm47xx_wdt_stop(struct watchdog_device *wdd)
+ {
+-      del_timer_sync(&wdt_timer);
+-      bcm47xx_wdt_hw_stop();
++      struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
++
++      del_timer_sync(&wdt->soft_timer);
++      wdt->timer_set(wdt, 0);
+       return 0;
+ }
+@@ -118,10 +96,13 @@ static int bcm47xx_wdt_stop(struct watch
+ static int bcm47xx_wdt_set_timeout(struct watchdog_device *wdd,
+                                  unsigned int new_time)
+ {
+-      if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
++      if (new_time < 1 || new_time > WDT_MAX_TIME) {
++              pr_warn("timeout value must be 1<=x<=%d, using %d\n",
++                      WDT_MAX_TIME, new_time);
+               return -EINVAL;
++      }
+-      wdt_time = new_time;
++      wdd->timeout = new_time;
+       return 0;
+ }
+@@ -135,8 +116,11 @@ static const struct watchdog_info bcm47x
+ static int bcm47xx_wdt_notify_sys(struct notifier_block *this,
+                                 unsigned long code, void *unused)
+ {
++      struct bcm47xx_wdt *wdt;
++
++      wdt = container_of(this, struct bcm47xx_wdt, notifier);
+       if (code == SYS_DOWN || code == SYS_HALT)
+-              bcm47xx_wdt_stop();
++              wdt->wdd.ops->stop(&wdt->wdd);
+       return NOTIFY_DONE;
+ }
+@@ -148,57 +132,72 @@ static struct watchdog_ops bcm47xx_wdt_o
+       .set_timeout    = bcm47xx_wdt_set_timeout,
+ };
+-static struct watchdog_device bcm47xx_wdt_wdd = {
+-      .info           = &bcm47xx_wdt_info,
+-      .ops            = &bcm47xx_wdt_ops,
+-};
+-
+-static struct notifier_block bcm47xx_wdt_notifier = {
+-      .notifier_call = bcm47xx_wdt_notify_sys,
+-};
+-
+-static int __init bcm47xx_wdt_init(void)
++static int __devinit bcm47xx_wdt_probe(struct platform_device *pdev)
+ {
+       int ret;
++      struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev);
+-      if (bcm47xx_wdt_hw_stop() < 0)
+-              return -ENODEV;
++      if (!wdt)
++              return -ENXIO;
+-      setup_timer(&wdt_timer, bcm47xx_timer_tick, 0L);
++      setup_timer(&wdt->soft_timer, bcm47xx_timer_tick,
++                  (long unsigned int)wdt);
+-      if (bcm47xx_wdt_settimeout(wdt_time)) {
+-              bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME);
+-              pr_info("wdt_time value must be 0 < wdt_time < %d, using %d\n",
+-                      (WDT_MAX_TIME + 1), wdt_time);
+-      }
+-      watchdog_set_nowayout(&bcm47xx_wdt_wdd, nowayout);
++      wdt->wdd.ops = &bcm47xx_wdt_ops;
++      wdt->wdd.info = &bcm47xx_wdt_info;
++      wdt->wdd.timeout = WDT_DEFAULT_TIME;
++      ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout);
++      if (ret)
++              goto err_timer;
++      watchdog_set_nowayout(&wdt->wdd, nowayout);
++
++      wdt->notifier.notifier_call = &bcm47xx_wdt_notify_sys;
+-      ret = register_reboot_notifier(&bcm47xx_wdt_notifier);
++      ret = register_reboot_notifier(&wdt->notifier);
+       if (ret)
+-              return ret;
++              goto err_timer;
+-      ret = watchdog_register_device(&bcm47xx_wdt_wdd);
+-      if (ret) {
+-              unregister_reboot_notifier(&bcm47xx_wdt_notifier);
+-              return ret;
+-      }
++      ret = watchdog_register_device(&wdt->wdd);
++      if (ret)
++              goto err_notifier;
+       pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
+               wdt_time, nowayout ? ", nowayout" : "");
+       return 0;
++
++err_notifier:
++      unregister_reboot_notifier(&wdt->notifier);
++err_timer:
++      del_timer_sync(&wdt->soft_timer);
++
++      return ret;
+ }
+-static void __exit bcm47xx_wdt_exit(void)
++static int __devexit bcm47xx_wdt_remove(struct platform_device *pdev)
+ {
+-      watchdog_stop(&bcm47xx_wdt_wdd);
+-      watchdog_unregister_device(&bcm47xx_wdt_wdd);
++      struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev);
++
++      if (!wdt)
++              return -ENXIO;
++
++      watchdog_unregister_device(&wdt->wdd);
++      unregister_reboot_notifier(&wdt->notifier);
+-      unregister_reboot_notifier(&bcm47xx_wdt_notifier);
++      return 0;
+ }
+-module_init(bcm47xx_wdt_init);
+-module_exit(bcm47xx_wdt_exit);
++static struct platform_driver bcm47xx_wdt_driver = {
++      .driver         = {
++              .owner  = THIS_MODULE,
++              .name   = "bcm47xx-wdt",
++      },
++      .probe          = bcm47xx_wdt_probe,
++      .remove         = __devexit_p(bcm47xx_wdt_remove),
++};
++
++module_platform_driver(bcm47xx_wdt_driver);
+ MODULE_AUTHOR("Aleksandar Radovanovic");
++MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+ MODULE_DESCRIPTION("Watchdog driver for Broadcom BCM47xx");
+ MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/include/linux/bcm47xx_wdt.h
+@@ -0,0 +1,27 @@
++#ifndef LINUX_BCM47XX_WDT_H_
++#define LINUX_BCM47XX_WDT_H_
++
++#include <linux/notifier.h>
++#include <linux/timer.h>
++#include <linux/types.h>
++#include <linux/watchdog.h>
++
++
++struct bcm47xx_wdt {
++      u32 (*timer_set)(struct bcm47xx_wdt *, u32);
++      u32 (*timer_set_ms)(struct bcm47xx_wdt *, u32);
++
++      void *driver_data;
++
++      struct watchdog_device wdd;
++      struct notifier_block notifier;
++
++      struct timer_list soft_timer;
++      atomic_t soft_ticks;
++};
++
++static inline void *bcm47xx_wdt_get_drvdata(struct bcm47xx_wdt *wdt)
++{
++      return wdt->driver_data;
++}
++#endif /* LINUX_BCM47XX_WDT_H_ */
diff --git a/target/linux/brcm47xx/patches-3.6/542-watchdog-bcm47xx_wdt.c-rename-ops-methods.patch b/target/linux/brcm47xx/patches-3.6/542-watchdog-bcm47xx_wdt.c-rename-ops-methods.patch
new file mode 100644 (file)
index 0000000..54956fd
--- /dev/null
@@ -0,0 +1,90 @@
+--- a/drivers/watchdog/bcm47xx_wdt.c
++++ b/drivers/watchdog/bcm47xx_wdt.c
+@@ -46,12 +46,13 @@ MODULE_PARM_DESC(nowayout,
+                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+ #endif
++
+ static inline struct bcm47xx_wdt *bcm47xx_wdt_get(struct watchdog_device *wdd)
+ {
+       return container_of(wdd, struct bcm47xx_wdt, wdd);
+ }
+-static void bcm47xx_timer_tick(unsigned long data)
++static void bcm47xx_wdt_soft_timer_tick(unsigned long data)
+ {
+       struct bcm47xx_wdt *wdt = (struct bcm47xx_wdt *)data;
+       u32 next_tick = min(wdt->wdd.timeout * 1000, wdt->max_timer_ms);
+@@ -64,7 +65,7 @@ static void bcm47xx_timer_tick(unsigned
+       }
+ }
+-static int bcm47xx_wdt_keepalive(struct watchdog_device *wdd)
++static int bcm47xx_wdt_soft_keepalive(struct watchdog_device *wdd)
+ {
+       struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
+@@ -73,17 +74,17 @@ static int bcm47xx_wdt_keepalive(struct
+       return 0;
+ }
+-static int bcm47xx_wdt_start(struct watchdog_device *wdd)
++static int bcm47xx_wdt_soft_start(struct watchdog_device *wdd)
+ {
+       struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
+-      bcm47xx_wdt_keepalive(wdd);
+-      bcm47xx_timer_tick((unsigned long)wdt);
++      bcm47xx_wdt_soft_keepalive(wdd);
++      bcm47xx_wdt_soft_timer_tick((unsigned long)wdt);
+       return 0;
+ }
+-static int bcm47xx_wdt_stop(struct watchdog_device *wdd)
++static int bcm47xx_wdt_soft_stop(struct watchdog_device *wdd)
+ {
+       struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
+@@ -93,8 +94,8 @@ static int bcm47xx_wdt_stop(struct watch
+       return 0;
+ }
+-static int bcm47xx_wdt_set_timeout(struct watchdog_device *wdd,
+-                                 unsigned int new_time)
++static int bcm47xx_wdt_soft_set_timeout(struct watchdog_device *wdd,
++                                      unsigned int new_time)
+ {
+       if (new_time < 1 || new_time > WDT_MAX_TIME) {
+               pr_warn("timeout value must be 1<=x<=%d, using %d\n",
+@@ -124,12 +125,12 @@ static int bcm47xx_wdt_notify_sys(struct
+       return NOTIFY_DONE;
+ }
+-static struct watchdog_ops bcm47xx_wdt_ops = {
++static struct watchdog_ops bcm47xx_wdt_soft_ops = {
+       .owner          = THIS_MODULE,
+-      .start          = bcm47xx_wdt_start,
+-      .stop           = bcm47xx_wdt_stop,
+-      .ping           = bcm47xx_wdt_keepalive,
+-      .set_timeout    = bcm47xx_wdt_set_timeout,
++      .start          = bcm47xx_wdt_soft_start,
++      .stop           = bcm47xx_wdt_soft_stop,
++      .ping           = bcm47xx_wdt_soft_keepalive,
++      .set_timeout    = bcm47xx_wdt_soft_set_timeout,
+ };
+ static int __devinit bcm47xx_wdt_probe(struct platform_device *pdev)
+@@ -140,10 +141,10 @@ static int __devinit bcm47xx_wdt_probe(s
+       if (!wdt)
+               return -ENXIO;
+-      setup_timer(&wdt->soft_timer, bcm47xx_timer_tick,
++      setup_timer(&wdt->soft_timer, bcm47xx_wdt_soft_timer_tick,
+                   (long unsigned int)wdt);
+-      wdt->wdd.ops = &bcm47xx_wdt_ops;
++      wdt->wdd.ops = &bcm47xx_wdt_soft_ops;
+       wdt->wdd.info = &bcm47xx_wdt_info;
+       wdt->wdd.timeout = WDT_DEFAULT_TIME;
+       ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout);
diff --git a/target/linux/brcm47xx/patches-3.6/543-watchdog-bcm47xx_wdt.c-rename-wdt_timeout-to-timeout.patch b/target/linux/brcm47xx/patches-3.6/543-watchdog-bcm47xx_wdt.c-rename-wdt_timeout-to-timeout.patch
new file mode 100644 (file)
index 0000000..c08f0b1
--- /dev/null
@@ -0,0 +1,41 @@
+--- a/drivers/watchdog/bcm47xx_wdt.c
++++ b/drivers/watchdog/bcm47xx_wdt.c
+@@ -30,13 +30,13 @@
+ #define DRV_NAME              "bcm47xx_wdt"
+ #define WDT_DEFAULT_TIME      30      /* seconds */
+-#define WDT_MAX_TIME          255     /* seconds */
++#define WDT_SOFTTIMER_MAX     3600    /* seconds */
+-static int wdt_time = WDT_DEFAULT_TIME;
++static int timeout = WDT_DEFAULT_TIME;
+ static bool nowayout = WATCHDOG_NOWAYOUT;
+-module_param(wdt_time, int, 0);
+-MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
++module_param(timeout, int, 0);
++MODULE_PARM_DESC(timeout, "Watchdog time in seconds. (default="
+                               __MODULE_STRING(WDT_DEFAULT_TIME) ")");
+ #ifdef CONFIG_WATCHDOG_NOWAYOUT
+@@ -97,9 +97,9 @@ static int bcm47xx_wdt_soft_stop(struct
+ static int bcm47xx_wdt_soft_set_timeout(struct watchdog_device *wdd,
+                                       unsigned int new_time)
+ {
+-      if (new_time < 1 || new_time > WDT_MAX_TIME) {
++      if (new_time < 1 || new_time > WDT_SOFTTIMER_MAX) {
+               pr_warn("timeout value must be 1<=x<=%d, using %d\n",
+-                      WDT_MAX_TIME, new_time);
++                      WDT_SOFTTIMER_MAX, new_time);
+               return -EINVAL;
+       }
+@@ -163,7 +163,7 @@ static int __devinit bcm47xx_wdt_probe(s
+               goto err_notifier;
+       pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
+-              wdt_time, nowayout ? ", nowayout" : "");
++              timeout, nowayout ? ", nowayout" : "");
+       return 0;
+ err_notifier:
diff --git a/target/linux/brcm47xx/patches-3.6/544-watchdog-bcm47xx_wdt.c-add-hard-timer.patch b/target/linux/brcm47xx/patches-3.6/544-watchdog-bcm47xx_wdt.c-add-hard-timer.patch
new file mode 100644 (file)
index 0000000..3e67ba2
--- /dev/null
@@ -0,0 +1,120 @@
+--- a/drivers/watchdog/bcm47xx_wdt.c
++++ b/drivers/watchdog/bcm47xx_wdt.c
+@@ -31,6 +31,7 @@
+ #define WDT_DEFAULT_TIME      30      /* seconds */
+ #define WDT_SOFTTIMER_MAX     3600    /* seconds */
++#define WDT_SOFTTIMER_THRESHOLD       60      /* seconds */
+ static int timeout = WDT_DEFAULT_TIME;
+ static bool nowayout = WATCHDOG_NOWAYOUT;
+@@ -52,6 +53,53 @@ static inline struct bcm47xx_wdt *bcm47x
+       return container_of(wdd, struct bcm47xx_wdt, wdd);
+ }
++static int bcm47xx_wdt_hard_keepalive(struct watchdog_device *wdd)
++{
++      struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
++
++      wdt->timer_set_ms(wdt, wdd->timeout * 1000);
++
++      return 0;
++}
++
++static int bcm47xx_wdt_hard_start(struct watchdog_device *wdd)
++{
++      return 0;
++}
++
++static int bcm47xx_wdt_hard_stop(struct watchdog_device *wdd)
++{
++      struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
++
++      wdt->timer_set(wdt, 0);
++
++      return 0;
++}
++
++static int bcm47xx_wdt_hard_set_timeout(struct watchdog_device *wdd,
++                                      unsigned int new_time)
++{
++      struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
++      u32 max_timer = wdt->max_timer_ms;
++
++      if (new_time < 1 || new_time > max_timer / 1000) {
++              pr_warn("timeout value must be 1<=x<=%d, using %d\n",
++                      max_timer / 1000, new_time);
++              return -EINVAL;
++      }
++
++      wdd->timeout = new_time;
++      return 0;
++}
++
++static struct watchdog_ops bcm47xx_wdt_hard_ops = {
++      .owner          = THIS_MODULE,
++      .start          = bcm47xx_wdt_hard_start,
++      .stop           = bcm47xx_wdt_hard_stop,
++      .ping           = bcm47xx_wdt_hard_keepalive,
++      .set_timeout    = bcm47xx_wdt_hard_set_timeout,
++};
++
+ static void bcm47xx_wdt_soft_timer_tick(unsigned long data)
+ {
+       struct bcm47xx_wdt *wdt = (struct bcm47xx_wdt *)data;
+@@ -136,15 +184,22 @@ static struct watchdog_ops bcm47xx_wdt_s
+ static int __devinit bcm47xx_wdt_probe(struct platform_device *pdev)
+ {
+       int ret;
++      bool soft;
+       struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev);
+       if (!wdt)
+               return -ENXIO;
+-      setup_timer(&wdt->soft_timer, bcm47xx_wdt_soft_timer_tick,
+-                  (long unsigned int)wdt);
++      soft = wdt->max_timer_ms < WDT_SOFTTIMER_THRESHOLD * 1000;
++
++      if (soft) {
++              wdt->wdd.ops = &bcm47xx_wdt_soft_ops;
++              setup_timer(&wdt->soft_timer, bcm47xx_wdt_soft_timer_tick,
++                          (long unsigned int)wdt);
++      } else {
++              wdt->wdd.ops = &bcm47xx_wdt_hard_ops;
++      }
+-      wdt->wdd.ops = &bcm47xx_wdt_soft_ops;
+       wdt->wdd.info = &bcm47xx_wdt_info;
+       wdt->wdd.timeout = WDT_DEFAULT_TIME;
+       ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout);
+@@ -162,14 +217,16 @@ static int __devinit bcm47xx_wdt_probe(s
+       if (ret)
+               goto err_notifier;
+-      pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
+-              timeout, nowayout ? ", nowayout" : "");
++      dev_info(&pdev->dev, "BCM47xx Watchdog Timer enabled (%d seconds%s%s)\n",
++              timeout, nowayout ? ", nowayout" : "",
++              soft ? ", Software Timer" : "");
+       return 0;
+ err_notifier:
+       unregister_reboot_notifier(&wdt->notifier);
+ err_timer:
+-      del_timer_sync(&wdt->soft_timer);
++      if (soft)
++              del_timer_sync(&wdt->soft_timer);
+       return ret;
+ }
+--- a/include/linux/bcm47xx_wdt.h
++++ b/include/linux/bcm47xx_wdt.h
+@@ -10,6 +10,7 @@
+ struct bcm47xx_wdt {
+       u32 (*timer_set)(struct bcm47xx_wdt *, u32);
+       u32 (*timer_set_ms)(struct bcm47xx_wdt *, u32);
++      u32 max_timer_ms;
+       void *driver_data;
diff --git a/target/linux/brcm47xx/patches-3.6/545-bcma-add-bcma_chipco_alp_clock.patch b/target/linux/brcm47xx/patches-3.6/545-bcma-add-bcma_chipco_alp_clock.patch
new file mode 100644 (file)
index 0000000..f6f0012
--- /dev/null
@@ -0,0 +1,35 @@
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -4,6 +4,7 @@
+  *
+  * 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.
+  */
+@@ -22,6 +23,14 @@ static inline u32 bcma_cc_write32_masked
+       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;
++}
++
+ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
+ {
+       if (cc->early_setup_done)
+@@ -180,8 +189,7 @@ void bcma_chipco_serial_init(struct bcma
+       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/target/linux/brcm47xx/patches-3.6/546-bcma-set-the-pmu-watchdog-if-available.patch b/target/linux/brcm47xx/patches-3.6/546-bcma-set-the-pmu-watchdog-if-available.patch
new file mode 100644 (file)
index 0000000..651415e
--- /dev/null
@@ -0,0 +1,57 @@
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -31,6 +31,28 @@ static u32 bcma_chipco_alp_clock(struct
+       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;
++}
++
++
+ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
+ {
+       if (cc->early_setup_done)
+@@ -87,8 +109,23 @@ void bcma_core_chipcommon_init(struct bc
+ /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
+ void 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;
++              bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks);
++      }
+ }
+ void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value)
diff --git a/target/linux/brcm47xx/patches-3.6/547-bcma-add-methods-for-watchdog-driver.patch b/target/linux/brcm47xx/patches-3.6/547-bcma-add-methods-for-watchdog-driver.patch
new file mode 100644 (file)
index 0000000..1be2476
--- /dev/null
@@ -0,0 +1,93 @@
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -10,6 +10,7 @@
+  */
+ #include "bcma_private.h"
++#include <linux/bcm47xx_wdt.h>
+ #include <linux/export.h>
+ #include <linux/bcma/bcma.h>
+@@ -52,6 +53,39 @@ static u32 bcma_chipco_watchdog_get_max_
+               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;
++      }
++}
+ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
+ {
+@@ -102,12 +136,13 @@ void bcma_core_chipcommon_init(struct bc
+       }
+       spin_lock_init(&cc->gpio_lock);
++      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)
+ {
+       u32 maxt;
+       enum bcma_clkmode clkmode;
+@@ -126,6 +161,7 @@ void bcma_chipco_watchdog_timer_set(stru
+                       ticks = maxt;
+               bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks);
+       }
++      return ticks;
+ }
+ void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value)
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -554,6 +554,7 @@ struct bcma_drv_cc {
+       /* Lock for GPIO register access. */
+       spinlock_t gpio_lock;
++      u32 ticks_per_ms;
+ };
+ /* Register access */
+@@ -577,8 +578,7 @@ extern void bcma_chipco_resume(struct bc
+ void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
+-extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
+-                                        u32 ticks);
++extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
+ void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value);
diff --git a/target/linux/brcm47xx/patches-3.6/548-bcma-register-watchdog-driver.patch b/target/linux/brcm47xx/patches-3.6/548-bcma-register-watchdog-driver.patch
new file mode 100644 (file)
index 0000000..457df36
--- /dev/null
@@ -0,0 +1,92 @@
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -85,6 +85,8 @@ extern void __exit bcma_host_pci_exit(vo
+ /* 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);
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -12,6 +12,7 @@
+ #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,
+@@ -87,6 +88,27 @@ static int bcma_chipco_watchdog_ticks_pe
+       }
+ }
++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)
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -173,6 +173,12 @@ static int bcma_register_cores(struct bc
+       }
+ #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;
+ }
+@@ -185,6 +191,8 @@ static void bcma_unregister_cores(struct
+               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)
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -4,6 +4,8 @@
+ #include <linux/mtd/bcm47xx_sflash.h>
+ #include <linux/mtd/bcm47xx_nand.h>
++#include <linux/platform_device.h>
++
+ /** ChipCommon core registers. **/
+ #define BCMA_CC_ID                    0x0000
+ #define  BCMA_CC_ID_ID                        0x0000FFFF
+@@ -555,6 +557,7 @@ struct bcma_drv_cc {
+       /* Lock for GPIO register access. */
+       spinlock_t gpio_lock;
+       u32 ticks_per_ms;
++      struct platform_device *watchdog;
+ };
+ /* Register access */
diff --git a/target/linux/brcm47xx/patches-3.6/549-ssb-get-alp-clock-from-devices-with-PMU.patch b/target/linux/brcm47xx/patches-3.6/549-ssb-get-alp-clock-from-devices-with-PMU.patch
new file mode 100644 (file)
index 0000000..f591298
--- /dev/null
@@ -0,0 +1,76 @@
+--- a/drivers/ssb/driver_chipcommon.c
++++ b/drivers/ssb/driver_chipcommon.c
+@@ -280,6 +280,14 @@ static void calc_fast_powerup_delay(stru
+       cc->fast_pwrup_delay = tmp;
+ }
++static u32 ssb_chipco_alp_clock(struct ssb_chipcommon *cc)
++{
++      if (cc->capabilities & SSB_CHIPCO_CAP_PMU)
++              return ssb_pmu_get_alp_clock(cc);
++
++      return 20000000;
++}
++
+ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
+ {
+       if (!cc->dev)
+@@ -474,11 +482,7 @@ int ssb_chipco_serial_init(struct ssb_ch
+                                      | SSB_CHIPCO_CORECTL_UARTCLK0);
+               } else if ((ccrev >= 11) && (ccrev != 15)) {
+                       /* Fixed ALP clock */
+-                      baud_base = 20000000;
+-                      if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
+-                              /* FIXME: baud_base is different for devices with a PMU */
+-                              SSB_WARN_ON(1);
+-                      }
++                      baud_base = ssb_chipco_alp_clock(cc);
+                       div = 1;
+                       if (ccrev >= 21) {
+                               /* Turn off UART clock before switching clocksource. */
+--- a/drivers/ssb/driver_chipcommon_pmu.c
++++ b/drivers/ssb/driver_chipcommon_pmu.c
+@@ -618,6 +618,33 @@ void ssb_pmu_set_ldo_paref(struct ssb_ch
+ EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage);
+ EXPORT_SYMBOL(ssb_pmu_set_ldo_paref);
++static u32 ssb_pmu_get_alp_clock_clk0(struct ssb_chipcommon *cc)
++{
++      u32 crystalfreq;
++      const struct pmu0_plltab_entry *e = NULL;
++
++      crystalfreq = chipco_read32(cc, SSB_CHIPCO_PMU_CTL) &
++                    SSB_CHIPCO_PMU_CTL_XTALFREQ >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT;
++      e = pmu0_plltab_find_entry(crystalfreq);
++      BUG_ON(!e);
++      return e->freq * 1000;
++}
++
++u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc)
++{
++      struct ssb_bus *bus = cc->dev->bus;
++
++      switch (bus->chip_id) {
++      case 0x5354:
++              ssb_pmu_get_alp_clock_clk0(cc);
++      default:
++              ssb_printk(KERN_ERR PFX
++                         "ERROR: PMU alp clock unknown for device %04X\n",
++                         bus->chip_id);
++              return 0;
++      }
++}
++
+ u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc)
+ {
+       struct ssb_bus *bus = cc->dev->bus;
+--- a/drivers/ssb/ssb_private.h
++++ b/drivers/ssb/ssb_private.h
+@@ -210,6 +210,7 @@ static inline void b43_pci_ssb_bridge_ex
+ /* driver_chipcommon_pmu.c */
+ extern u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc);
+ extern u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc);
++extern u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc);
+ #ifdef CONFIG_SSB_SFLASH
+ /* driver_chipcommon_sflash.c */
diff --git a/target/linux/brcm47xx/patches-3.6/550-ssb-set-the-pmu-watchdog-if-available.patch b/target/linux/brcm47xx/patches-3.6/550-ssb-set-the-pmu-watchdog-if-available.patch
new file mode 100644 (file)
index 0000000..f7cc07b
--- /dev/null
@@ -0,0 +1,54 @@
+--- a/drivers/ssb/driver_chipcommon.c
++++ b/drivers/ssb/driver_chipcommon.c
+@@ -288,6 +288,24 @@ static u32 ssb_chipco_alp_clock(struct s
+       return 20000000;
+ }
++static u32 ssb_chipco_watchdog_get_max_timer(struct ssb_chipcommon *cc)
++{
++      u32 nb;
++
++      if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
++              if (cc->dev->id.revision < 26)
++                      nb = 16;
++              else
++                      nb = (cc->dev->id.revision >= 37) ? 32 : 24;
++      } else {
++              nb = 28;
++      }
++      if (nb == 32)
++              return 0xffffffff;
++      else
++              return (1 << nb) - 1;
++}
++
+ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
+ {
+       if (!cc->dev)
+@@ -405,8 +423,24 @@ void ssb_chipco_timing_init(struct ssb_c
+ /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
+ void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks)
+ {
+-      /* instant NMI */
+-      chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks);
++      u32 maxt;
++      enum ssb_clkmode clkmode;
++
++      maxt = ssb_chipco_watchdog_get_max_timer(cc);
++      if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
++              if (ticks == 1)
++                      ticks = 2;
++              else if (ticks > maxt)
++                      ticks = maxt;
++              chipco_write32(cc, SSB_CHIPCO_PMU_WATCHDOG, ticks);
++      } else {
++              clkmode = ticks ? SSB_CLKMODE_FAST : SSB_CLKMODE_DYNAMIC;
++              ssb_chipco_set_clockmode(cc, clkmode);
++              if (ticks > maxt)
++                      ticks = maxt;
++              /* instant NMI */
++              chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks);
++      }
+ }
+ void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value)
diff --git a/target/linux/brcm47xx/patches-3.6/551-ssb-add-methods-for-watchdog-driver.patch b/target/linux/brcm47xx/patches-3.6/551-ssb-add-methods-for-watchdog-driver.patch
new file mode 100644 (file)
index 0000000..46911d1
--- /dev/null
@@ -0,0 +1,131 @@
+--- a/drivers/ssb/driver_chipcommon.c
++++ b/drivers/ssb/driver_chipcommon.c
+@@ -4,6 +4,7 @@
+  *
+  * 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.
+  */
+@@ -12,6 +13,7 @@
+ #include <linux/ssb/ssb_regs.h>
+ #include <linux/export.h>
+ #include <linux/pci.h>
++#include <linux/bcm47xx_wdt.h>
+ #include "ssb_private.h"
+@@ -306,6 +308,43 @@ static u32 ssb_chipco_watchdog_get_max_t
+               return (1 << nb) - 1;
+ }
++u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks)
++{
++      struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt);
++
++      if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB)
++              return 0;
++
++      return ssb_chipco_watchdog_timer_set(cc, ticks);
++}
++
++u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms)
++{
++      struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt);
++      u32 ticks;
++
++      if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB)
++              return 0;
++
++      ticks = ssb_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms);
++      return ticks / cc->ticks_per_ms;
++}
++
++static int ssb_chipco_watchdog_ticks_per_ms(struct ssb_chipcommon *cc)
++{
++      struct ssb_bus *bus = cc->dev->bus;
++
++      if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
++                      /* based on 32KHz ILP clock */
++                      return 32;
++      } else {
++              if (cc->dev->id.revision < 18)
++                      return ssb_clockspeed(bus) / 1000;
++              else
++                      return ssb_chipco_alp_clock(cc) / 1000;
++      }
++}
++
+ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
+ {
+       if (!cc->dev)
+@@ -323,6 +362,11 @@ void ssb_chipcommon_init(struct ssb_chip
+       chipco_powercontrol_init(cc);
+       ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
+       calc_fast_powerup_delay(cc);
++
++      if (cc->dev->bus->bustype == SSB_BUSTYPE_SSB) {
++              cc->ticks_per_ms = ssb_chipco_watchdog_ticks_per_ms(cc);
++              cc->max_timer_ms = ssb_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
++      }
+ }
+ void ssb_chipco_suspend(struct ssb_chipcommon *cc)
+@@ -421,7 +465,7 @@ void ssb_chipco_timing_init(struct ssb_c
+ }
+ /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
+-void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks)
++u32 ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks)
+ {
+       u32 maxt;
+       enum ssb_clkmode clkmode;
+@@ -441,6 +485,7 @@ void ssb_chipco_watchdog_timer_set(struc
+               /* instant NMI */
+               chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks);
+       }
++      return ticks;
+ }
+ void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value)
+--- a/drivers/ssb/ssb_private.h
++++ b/drivers/ssb/ssb_private.h
+@@ -3,6 +3,7 @@
+ #include <linux/ssb/ssb.h>
+ #include <linux/types.h>
++#include <linux/bcm47xx_wdt.h>
+ #define PFX   "ssb: "
+@@ -226,4 +227,8 @@ static inline int ssb_sflash_init(struct
+ extern struct platform_device ssb_pflash_dev;
++extern u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt,
++                                           u32 ticks);
++extern u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms);
++
+ #endif /* LINUX_SSB_PRIVATE_H_ */
+--- a/include/linux/ssb/ssb_driver_chipcommon.h
++++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -607,6 +607,8 @@ struct ssb_chipcommon {
+ #ifdef CONFIG_SSB_SFLASH
+       struct bcm47xx_sflash sflash;
+ #endif
++      u32 ticks_per_ms;
++      u32 max_timer_ms;
+ };
+ static inline bool ssb_chipco_available(struct ssb_chipcommon *cc)
+@@ -646,8 +648,7 @@ enum ssb_clkmode {
+ extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
+                                    enum ssb_clkmode mode);
+-extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc,
+-                                        u32 ticks);
++extern u32 ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks);
+ void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value);
diff --git a/target/linux/brcm47xx/patches-3.6/552-ssb-extif-add-check-for-max-value-in-watchdog.patch b/target/linux/brcm47xx/patches-3.6/552-ssb-extif-add-check-for-max-value-in-watchdog.patch
new file mode 100644 (file)
index 0000000..c6756dd
--- /dev/null
@@ -0,0 +1,25 @@
+--- a/drivers/ssb/driver_extif.c
++++ b/drivers/ssb/driver_extif.c
+@@ -112,9 +112,10 @@ void ssb_extif_get_clockcontrol(struct s
+       *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB);
+ }
+-void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
+-                                u32 ticks)
++void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks)
+ {
++      if (ticks > SSB_EXTIF_WATCHDOG_MAX_TIMER)
++              ticks = SSB_EXTIF_WATCHDOG_MAX_TIMER;
+       extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks);
+ }
+--- a/include/linux/ssb/ssb_driver_extif.h
++++ b/include/linux/ssb/ssb_driver_extif.h
+@@ -152,6 +152,7 @@
+ /* watchdog */
+ #define SSB_EXTIF_WATCHDOG_CLK                48000000        /* Hz */
++#define SSB_EXTIF_WATCHDOG_MAX_TIMER  ((1 << 28) - 1)
+ #ifdef CONFIG_SSB_DRIVER_EXTIF
diff --git a/target/linux/brcm47xx/patches-3.6/553-ssb-extif-add-methods-for-watchdog-driver.patch b/target/linux/brcm47xx/patches-3.6/553-ssb-extif-add-methods-for-watchdog-driver.patch
new file mode 100644 (file)
index 0000000..555cf64
--- /dev/null
@@ -0,0 +1,89 @@
+--- a/drivers/ssb/driver_extif.c
++++ b/drivers/ssb/driver_extif.c
+@@ -112,11 +112,30 @@ void ssb_extif_get_clockcontrol(struct s
+       *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB);
+ }
+-void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks)
++u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks)
++{
++      struct ssb_extif *extif = bcm47xx_wdt_get_drvdata(wdt);
++
++      return ssb_extif_watchdog_timer_set(extif, ticks);
++}
++
++u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms)
++{
++      struct ssb_extif *extif = bcm47xx_wdt_get_drvdata(wdt);
++      u32 ticks = (SSB_EXTIF_WATCHDOG_CLK / 1000) * ms;
++
++      ticks = ssb_extif_watchdog_timer_set(extif, ticks);
++
++      return (ticks * 1000) / SSB_EXTIF_WATCHDOG_CLK;
++}
++
++u32 ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks)
+ {
+       if (ticks > SSB_EXTIF_WATCHDOG_MAX_TIMER)
+               ticks = SSB_EXTIF_WATCHDOG_MAX_TIMER;
+       extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks);
++
++      return ticks;
+ }
+ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
+--- a/drivers/ssb/ssb_private.h
++++ b/drivers/ssb/ssb_private.h
+@@ -231,4 +231,19 @@ extern u32 ssb_chipco_watchdog_timer_set
+                                            u32 ticks);
+ extern u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms);
++#ifdef CONFIG_SSB_DRIVER_EXTIF
++extern u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks);
++extern u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms);
++#else
++static inline u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt,
++                                                 u32 ticks)
++{
++      return 0;
++}
++static inline u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt,
++                                                u32 ms)
++{
++      return 0;
++}
++#endif
+ #endif /* LINUX_SSB_PRIVATE_H_ */
+--- a/include/linux/ssb/ssb_driver_extif.h
++++ b/include/linux/ssb/ssb_driver_extif.h
+@@ -153,6 +153,8 @@
+ #define SSB_EXTIF_WATCHDOG_CLK                48000000        /* Hz */
+ #define SSB_EXTIF_WATCHDOG_MAX_TIMER  ((1 << 28) - 1)
++#define SSB_EXTIF_WATCHDOG_MAX_TIMER_MS       (SSB_EXTIF_WATCHDOG_MAX_TIMER \
++                                       / (SSB_EXTIF_WATCHDOG_CLK / 1000))
+ #ifdef CONFIG_SSB_DRIVER_EXTIF
+@@ -172,8 +174,7 @@ extern void ssb_extif_get_clockcontrol(s
+ extern void ssb_extif_timing_init(struct ssb_extif *extif,
+                                 unsigned long ns);
+-extern void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
+-                                       u32 ticks);
++extern u32 ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks);
+ /* Extif GPIO pin access */
+ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask);
+@@ -206,9 +207,9 @@ void ssb_extif_get_clockcontrol(struct s
+ }
+ static inline
+-void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
+-                                u32 ticks)
++u32 ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks)
+ {
++      return 0;
+ }
+ #endif /* CONFIG_SSB_DRIVER_EXTIF */
diff --git a/target/linux/brcm47xx/patches-3.6/554-ssb-register-watchdog-driver.patch b/target/linux/brcm47xx/patches-3.6/554-ssb-register-watchdog-driver.patch
new file mode 100644 (file)
index 0000000..c814c54
--- /dev/null
@@ -0,0 +1,122 @@
+--- a/drivers/ssb/embedded.c
++++ b/drivers/ssb/embedded.c
+@@ -4,11 +4,13 @@
+  *
+  * Copyright 2005-2008, Broadcom Corporation
+  * Copyright 2006-2008, Michael Buesch <m@bues.ch>
++ * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+ #include <linux/export.h>
++#include <linux/platform_device.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_embedded.h>
+ #include <linux/ssb/ssb_driver_pci.h>
+@@ -32,6 +34,39 @@ int ssb_watchdog_timer_set(struct ssb_bu
+ }
+ EXPORT_SYMBOL(ssb_watchdog_timer_set);
++int ssb_watchdog_register(struct ssb_bus *bus)
++{
++      struct bcm47xx_wdt wdt = {};
++      struct platform_device *pdev;
++
++      if (ssb_chipco_available(&bus->chipco)) {
++              wdt.driver_data = &bus->chipco;
++              wdt.timer_set = ssb_chipco_watchdog_timer_set_wdt;
++              wdt.timer_set_ms = ssb_chipco_watchdog_timer_set_ms;
++              wdt.max_timer_ms = bus->chipco.max_timer_ms;
++      } else if (ssb_extif_available(&bus->extif)) {
++              wdt.driver_data = &bus->extif;
++              wdt.timer_set = ssb_extif_watchdog_timer_set_wdt;
++              wdt.timer_set_ms = ssb_extif_watchdog_timer_set_ms;
++              wdt.max_timer_ms = SSB_EXTIF_WATCHDOG_MAX_TIMER_MS;
++      } else {
++              return -ENODEV;
++      }
++
++      pdev = platform_device_register_data(NULL, "bcm47xx-wdt",
++                                           bus->busnumber, &wdt,
++                                           sizeof(wdt));
++      if (IS_ERR(pdev)) {
++              ssb_dprintk(KERN_INFO PFX
++                          "can not register watchdog device, err: %li\n",
++                          PTR_ERR(pdev));
++              return PTR_ERR(pdev);
++      }
++
++      bus->watchdog = pdev;
++      return 0;
++}
++
+ u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask)
+ {
+       unsigned long flags;
+--- a/drivers/ssb/main.c
++++ b/drivers/ssb/main.c
+@@ -13,6 +13,7 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
+ #include <linux/module.h>
++#include <linux/platform_device.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_regs.h>
+ #include <linux/ssb/ssb_driver_gige.h>
+@@ -434,6 +435,11 @@ static void ssb_devices_unregister(struc
+               if (sdev->dev)
+                       device_unregister(sdev->dev);
+       }
++
++#ifdef CONFIG_SSB_EMBEDDED
++      if (bus->bustype == SSB_BUSTYPE_SSB)
++              platform_device_unregister(bus->watchdog);
++#endif
+ }
+ void ssb_bus_unregister(struct ssb_bus *bus)
+@@ -579,6 +585,8 @@ static int __devinit ssb_attach_queued_b
+               if (err)
+                       goto error;
+               ssb_pcicore_init(&bus->pcicore);
++              if (bus->bustype == SSB_BUSTYPE_SSB)
++                      ssb_watchdog_register(bus);
+               ssb_bus_may_powerdown(bus);
+               err = ssb_devices_register(bus);
+--- a/drivers/ssb/ssb_private.h
++++ b/drivers/ssb/ssb_private.h
+@@ -246,4 +246,14 @@ static inline u32 ssb_extif_watchdog_tim
+       return 0;
+ }
+ #endif
++
++#ifdef CONFIG_SSB_EMBEDDED
++extern int ssb_watchdog_register(struct ssb_bus *bus);
++#else /* CONFIG_SSB_EMBEDDED */
++static inline int ssb_watchdog_register(struct ssb_bus *bus)
++{
++      return 0;
++}
++#endif /* CONFIG_SSB_EMBEDDED */
++
+ #endif /* LINUX_SSB_PRIVATE_H_ */
+--- a/include/linux/ssb/ssb.h
++++ b/include/linux/ssb/ssb.h
+@@ -8,6 +8,7 @@
+ #include <linux/pci.h>
+ #include <linux/mod_devicetable.h>
+ #include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
+ #include <linux/ssb/ssb_regs.h>
+@@ -432,6 +433,7 @@ struct ssb_bus {
+ #ifdef CONFIG_SSB_EMBEDDED
+       /* Lock for GPIO register access. */
+       spinlock_t gpio_lock;
++      struct platform_device *watchdog;
+ #endif /* EMBEDDED */
+       /* Internal-only stuff follows. Do not touch. */
diff --git a/target/linux/brcm47xx/patches-3.6/900-bcm47xx_wdt-noprescale.patch b/target/linux/brcm47xx/patches-3.6/900-bcm47xx_wdt-noprescale.patch
deleted file mode 100644 (file)
index bf0a192..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
---- a/drivers/watchdog/bcm47xx_wdt.c
-+++ b/drivers/watchdog/bcm47xx_wdt.c
-@@ -33,6 +33,7 @@
- #define WDT_DEFAULT_TIME      30      /* seconds */
- #define WDT_MAX_TIME          255     /* seconds */
-+#define WDT_SHIFT             15      /* 32.768 KHz on cores with slow WDT clock */
- static int wdt_time = WDT_DEFAULT_TIME;
- static bool nowayout = WATCHDOG_NOWAYOUT;
-@@ -52,20 +53,20 @@ static unsigned long bcm47xx_wdt_busy;
- static char expect_release;
- static struct timer_list wdt_timer;
- static atomic_t ticks;
-+static int needs_sw_scale;
--static inline void bcm47xx_wdt_hw_start(void)
-+static inline void bcm47xx_wdt_hw_start(u32 ticks)
- {
--      /* 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);
-+              ssb_watchdog_timer_set(&bcm47xx_bus.ssb, ticks);
-               break;
- #endif
- #ifdef CONFIG_BCM47XX_BCMA
-       case BCM47XX_BUS_TYPE_BCMA:
-               bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc,
--                                             0xfffffff);
-+                                             ticks);
-               break;
- #endif
-       }
-@@ -90,33 +91,34 @@ static inline int bcm47xx_wdt_hw_stop(vo
- static void bcm47xx_timer_tick(unsigned long unused)
- {
-       if (!atomic_dec_and_test(&ticks)) {
--              bcm47xx_wdt_hw_start();
-+              /* This is 2,5s on 100Mhz clock and 2s on 133 Mhz */
-+              bcm47xx_wdt_hw_start(0xfffffff);
-               mod_timer(&wdt_timer, jiffies + HZ);
-       } else {
-               pr_crit("Watchdog will fire soon!!!\n");
-       }
- }
--static inline void bcm47xx_wdt_pet(void)
-+static void bcm47xx_wdt_pet(void)
- {
--      atomic_set(&ticks, wdt_time);
-+      if(needs_sw_scale)
-+              atomic_set(&ticks, wdt_time);
-+      else
-+              bcm47xx_wdt_hw_start(wdt_time << WDT_SHIFT);
- }
- static void bcm47xx_wdt_start(void)
- {
-       bcm47xx_wdt_pet();
--      bcm47xx_timer_tick(0);
--}
--
--static void bcm47xx_wdt_pause(void)
--{
--      del_timer_sync(&wdt_timer);
--      bcm47xx_wdt_hw_stop();
-+      if(needs_sw_scale)
-+              bcm47xx_timer_tick(0);
- }
- static void bcm47xx_wdt_stop(void)
- {
--      bcm47xx_wdt_pause();
-+      if(needs_sw_scale)
-+              del_timer_sync(&wdt_timer);
-+      bcm47xx_wdt_hw_stop();
- }
- static int bcm47xx_wdt_settimeout(int new_time)
-@@ -267,7 +269,20 @@ static int __init bcm47xx_wdt_init(void)
-       if (bcm47xx_wdt_hw_stop() < 0)
-               return -ENODEV;
--      setup_timer(&wdt_timer, bcm47xx_timer_tick, 0L);
-+      /* FIXME Other cores */
-+#ifdef BCM47XX_BUS_TYPE_BCMA
-+      if(bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA &&
-+         bcm47xx_bus.ssb.chip_id == 0x5354) {
-+              /* Slow WDT clock, no pre-scaling */
-+              needs_sw_scale = 0;
-+      } else {
-+#endif
-+              /* Fast WDT clock, needs software pre-scaling */
-+              needs_sw_scale = 1;
-+              setup_timer(&wdt_timer, bcm47xx_timer_tick, 0L);
-+#ifdef BCM47XX_BUS_TYPE_BCMA
-+      }
-+#endif
-       if (bcm47xx_wdt_settimeout(wdt_time)) {
-               bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME);