aspeed_wdt.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * Copyright 2016 IBM Corporation
  3. *
  4. * Joel Stanley <joel@jms.id.au>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. */
  11. #include <linux/delay.h>
  12. #include <linux/io.h>
  13. #include <linux/kernel.h>
  14. #include <linux/module.h>
  15. #include <linux/of.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/watchdog.h>
  18. struct aspeed_wdt {
  19. struct watchdog_device wdd;
  20. void __iomem *base;
  21. u32 ctrl;
  22. };
  23. static const struct of_device_id aspeed_wdt_of_table[] = {
  24. { .compatible = "aspeed,ast2400-wdt" },
  25. { .compatible = "aspeed,ast2500-wdt" },
  26. { },
  27. };
  28. MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);
  29. #define WDT_STATUS 0x00
  30. #define WDT_RELOAD_VALUE 0x04
  31. #define WDT_RESTART 0x08
  32. #define WDT_CTRL 0x0C
  33. #define WDT_CTRL_RESET_MODE_SOC (0x00 << 5)
  34. #define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5)
  35. #define WDT_CTRL_1MHZ_CLK BIT(4)
  36. #define WDT_CTRL_WDT_EXT BIT(3)
  37. #define WDT_CTRL_WDT_INTR BIT(2)
  38. #define WDT_CTRL_RESET_SYSTEM BIT(1)
  39. #define WDT_CTRL_ENABLE BIT(0)
  40. #define WDT_RESTART_MAGIC 0x4755
  41. /* 32 bits at 1MHz, in milliseconds */
  42. #define WDT_MAX_TIMEOUT_MS 4294967
  43. #define WDT_DEFAULT_TIMEOUT 30
  44. #define WDT_RATE_1MHZ 1000000
  45. static struct aspeed_wdt *to_aspeed_wdt(struct watchdog_device *wdd)
  46. {
  47. return container_of(wdd, struct aspeed_wdt, wdd);
  48. }
  49. static void aspeed_wdt_enable(struct aspeed_wdt *wdt, int count)
  50. {
  51. wdt->ctrl |= WDT_CTRL_ENABLE;
  52. writel(0, wdt->base + WDT_CTRL);
  53. writel(count, wdt->base + WDT_RELOAD_VALUE);
  54. writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART);
  55. writel(wdt->ctrl, wdt->base + WDT_CTRL);
  56. }
  57. static int aspeed_wdt_start(struct watchdog_device *wdd)
  58. {
  59. struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
  60. aspeed_wdt_enable(wdt, wdd->timeout * WDT_RATE_1MHZ);
  61. return 0;
  62. }
  63. static int aspeed_wdt_stop(struct watchdog_device *wdd)
  64. {
  65. struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
  66. wdt->ctrl &= ~WDT_CTRL_ENABLE;
  67. writel(wdt->ctrl, wdt->base + WDT_CTRL);
  68. return 0;
  69. }
  70. static int aspeed_wdt_ping(struct watchdog_device *wdd)
  71. {
  72. struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
  73. writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART);
  74. return 0;
  75. }
  76. static int aspeed_wdt_set_timeout(struct watchdog_device *wdd,
  77. unsigned int timeout)
  78. {
  79. struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
  80. u32 actual;
  81. wdd->timeout = timeout;
  82. actual = min(timeout, wdd->max_hw_heartbeat_ms * 1000);
  83. writel(actual * WDT_RATE_1MHZ, wdt->base + WDT_RELOAD_VALUE);
  84. writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART);
  85. return 0;
  86. }
  87. static int aspeed_wdt_restart(struct watchdog_device *wdd,
  88. unsigned long action, void *data)
  89. {
  90. struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
  91. aspeed_wdt_enable(wdt, 128 * WDT_RATE_1MHZ / 1000);
  92. mdelay(1000);
  93. return 0;
  94. }
  95. static const struct watchdog_ops aspeed_wdt_ops = {
  96. .start = aspeed_wdt_start,
  97. .stop = aspeed_wdt_stop,
  98. .ping = aspeed_wdt_ping,
  99. .set_timeout = aspeed_wdt_set_timeout,
  100. .restart = aspeed_wdt_restart,
  101. .owner = THIS_MODULE,
  102. };
  103. static const struct watchdog_info aspeed_wdt_info = {
  104. .options = WDIOF_KEEPALIVEPING
  105. | WDIOF_MAGICCLOSE
  106. | WDIOF_SETTIMEOUT,
  107. .identity = KBUILD_MODNAME,
  108. };
  109. static int aspeed_wdt_remove(struct platform_device *pdev)
  110. {
  111. struct aspeed_wdt *wdt = platform_get_drvdata(pdev);
  112. watchdog_unregister_device(&wdt->wdd);
  113. return 0;
  114. }
  115. static int aspeed_wdt_probe(struct platform_device *pdev)
  116. {
  117. struct aspeed_wdt *wdt;
  118. struct resource *res;
  119. int ret;
  120. wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
  121. if (!wdt)
  122. return -ENOMEM;
  123. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  124. wdt->base = devm_ioremap_resource(&pdev->dev, res);
  125. if (IS_ERR(wdt->base))
  126. return PTR_ERR(wdt->base);
  127. /*
  128. * The ast2400 wdt can run at PCLK, or 1MHz. The ast2500 only
  129. * runs at 1MHz. We chose to always run at 1MHz, as there's no
  130. * good reason to have a faster watchdog counter.
  131. */
  132. wdt->wdd.info = &aspeed_wdt_info;
  133. wdt->wdd.ops = &aspeed_wdt_ops;
  134. wdt->wdd.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT_MS;
  135. wdt->wdd.parent = &pdev->dev;
  136. wdt->wdd.timeout = WDT_DEFAULT_TIMEOUT;
  137. watchdog_init_timeout(&wdt->wdd, 0, &pdev->dev);
  138. /*
  139. * Control reset on a per-device basis to ensure the
  140. * host is not affected by a BMC reboot, so only reset
  141. * the SOC and not the full chip
  142. */
  143. wdt->ctrl = WDT_CTRL_RESET_MODE_SOC |
  144. WDT_CTRL_1MHZ_CLK |
  145. WDT_CTRL_RESET_SYSTEM;
  146. if (readl(wdt->base + WDT_CTRL) & WDT_CTRL_ENABLE) {
  147. aspeed_wdt_start(&wdt->wdd);
  148. set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
  149. }
  150. ret = watchdog_register_device(&wdt->wdd);
  151. if (ret) {
  152. dev_err(&pdev->dev, "failed to register\n");
  153. return ret;
  154. }
  155. platform_set_drvdata(pdev, wdt);
  156. return 0;
  157. }
  158. static struct platform_driver aspeed_watchdog_driver = {
  159. .probe = aspeed_wdt_probe,
  160. .remove = aspeed_wdt_remove,
  161. .driver = {
  162. .name = KBUILD_MODNAME,
  163. .of_match_table = of_match_ptr(aspeed_wdt_of_table),
  164. },
  165. };
  166. module_platform_driver(aspeed_watchdog_driver);
  167. MODULE_DESCRIPTION("Aspeed Watchdog Driver");
  168. MODULE_LICENSE("GPL");