523 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Mediatek Watchdog Driver4 *5 * Copyright (C) 2014 Matthias Brugger6 *7 * Matthias Brugger <matthias.bgg@gmail.com>8 *9 * Based on sunxi_wdt.c10 */11 12#include <dt-bindings/reset/mt2712-resets.h>13#include <dt-bindings/reset/mediatek,mt6795-resets.h>14#include <dt-bindings/reset/mt7986-resets.h>15#include <dt-bindings/reset/mt8183-resets.h>16#include <dt-bindings/reset/mt8186-resets.h>17#include <dt-bindings/reset/mt8188-resets.h>18#include <dt-bindings/reset/mt8192-resets.h>19#include <dt-bindings/reset/mt8195-resets.h>20#include <linux/delay.h>21#include <linux/err.h>22#include <linux/init.h>23#include <linux/io.h>24#include <linux/kernel.h>25#include <linux/module.h>26#include <linux/moduleparam.h>27#include <linux/of.h>28#include <linux/platform_device.h>29#include <linux/reset-controller.h>30#include <linux/types.h>31#include <linux/watchdog.h>32#include <linux/interrupt.h>33 34#define WDT_MAX_TIMEOUT 3135#define WDT_MIN_TIMEOUT 236#define WDT_LENGTH_TIMEOUT(n) ((n) << 5)37 38#define WDT_LENGTH 0x0439#define WDT_LENGTH_KEY 0x840 41#define WDT_RST 0x0842#define WDT_RST_RELOAD 0x197143 44#define WDT_MODE 0x0045#define WDT_MODE_EN (1 << 0)46#define WDT_MODE_EXT_POL_LOW (0 << 1)47#define WDT_MODE_EXT_POL_HIGH (1 << 1)48#define WDT_MODE_EXRST_EN (1 << 2)49#define WDT_MODE_IRQ_EN (1 << 3)50#define WDT_MODE_AUTO_START (1 << 4)51#define WDT_MODE_DUAL_EN (1 << 6)52#define WDT_MODE_CNT_SEL (1 << 8)53#define WDT_MODE_KEY 0x2200000054 55#define WDT_SWRST 0x1456#define WDT_SWRST_KEY 0x120957 58#define WDT_SWSYSRST 0x18U59#define WDT_SWSYS_RST_KEY 0x8800000060 61#define WDT_SWSYSRST_EN 0xfc62 63#define DRV_NAME "mtk-wdt"64#define DRV_VERSION "1.0"65 66#define MT7988_TOPRGU_SW_RST_NUM 2467 68static bool nowayout = WATCHDOG_NOWAYOUT;69static unsigned int timeout;70 71struct mtk_wdt_dev {72 struct watchdog_device wdt_dev;73 void __iomem *wdt_base;74 spinlock_t lock; /* protects WDT_SWSYSRST reg */75 struct reset_controller_dev rcdev;76 bool disable_wdt_extrst;77 bool reset_by_toprgu;78 bool has_swsysrst_en;79};80 81struct mtk_wdt_data {82 int toprgu_sw_rst_num;83 bool has_swsysrst_en;84};85 86static const struct mtk_wdt_data mt2712_data = {87 .toprgu_sw_rst_num = MT2712_TOPRGU_SW_RST_NUM,88};89 90static const struct mtk_wdt_data mt6795_data = {91 .toprgu_sw_rst_num = MT6795_TOPRGU_SW_RST_NUM,92};93 94static const struct mtk_wdt_data mt7986_data = {95 .toprgu_sw_rst_num = MT7986_TOPRGU_SW_RST_NUM,96};97 98static const struct mtk_wdt_data mt7988_data = {99 .toprgu_sw_rst_num = MT7988_TOPRGU_SW_RST_NUM,100 .has_swsysrst_en = true,101};102 103static const struct mtk_wdt_data mt8183_data = {104 .toprgu_sw_rst_num = MT8183_TOPRGU_SW_RST_NUM,105};106 107static const struct mtk_wdt_data mt8186_data = {108 .toprgu_sw_rst_num = MT8186_TOPRGU_SW_RST_NUM,109};110 111static const struct mtk_wdt_data mt8188_data = {112 .toprgu_sw_rst_num = MT8188_TOPRGU_SW_RST_NUM,113};114 115static const struct mtk_wdt_data mt8192_data = {116 .toprgu_sw_rst_num = MT8192_TOPRGU_SW_RST_NUM,117};118 119static const struct mtk_wdt_data mt8195_data = {120 .toprgu_sw_rst_num = MT8195_TOPRGU_SW_RST_NUM,121};122 123/**124 * toprgu_reset_sw_en_unlocked() - enable/disable software control for reset bit125 * @data: Pointer to instance of driver data.126 * @id: Bit number identifying the reset to be enabled or disabled.127 * @enable: If true, enable software control for that bit, disable otherwise.128 *129 * Context: The caller must hold lock of struct mtk_wdt_dev.130 */131static void toprgu_reset_sw_en_unlocked(struct mtk_wdt_dev *data,132 unsigned long id, bool enable)133{134 u32 tmp;135 136 tmp = readl(data->wdt_base + WDT_SWSYSRST_EN);137 if (enable)138 tmp |= BIT(id);139 else140 tmp &= ~BIT(id);141 142 writel(tmp, data->wdt_base + WDT_SWSYSRST_EN);143}144 145static int toprgu_reset_update(struct reset_controller_dev *rcdev,146 unsigned long id, bool assert)147{148 unsigned int tmp;149 unsigned long flags;150 struct mtk_wdt_dev *data =151 container_of(rcdev, struct mtk_wdt_dev, rcdev);152 153 spin_lock_irqsave(&data->lock, flags);154 155 if (assert && data->has_swsysrst_en)156 toprgu_reset_sw_en_unlocked(data, id, true);157 158 tmp = readl(data->wdt_base + WDT_SWSYSRST);159 if (assert)160 tmp |= BIT(id);161 else162 tmp &= ~BIT(id);163 tmp |= WDT_SWSYS_RST_KEY;164 writel(tmp, data->wdt_base + WDT_SWSYSRST);165 166 if (!assert && data->has_swsysrst_en)167 toprgu_reset_sw_en_unlocked(data, id, false);168 169 spin_unlock_irqrestore(&data->lock, flags);170 171 return 0;172}173 174static int toprgu_reset_assert(struct reset_controller_dev *rcdev,175 unsigned long id)176{177 return toprgu_reset_update(rcdev, id, true);178}179 180static int toprgu_reset_deassert(struct reset_controller_dev *rcdev,181 unsigned long id)182{183 return toprgu_reset_update(rcdev, id, false);184}185 186static int toprgu_reset(struct reset_controller_dev *rcdev,187 unsigned long id)188{189 int ret;190 191 ret = toprgu_reset_assert(rcdev, id);192 if (ret)193 return ret;194 195 return toprgu_reset_deassert(rcdev, id);196}197 198static const struct reset_control_ops toprgu_reset_ops = {199 .assert = toprgu_reset_assert,200 .deassert = toprgu_reset_deassert,201 .reset = toprgu_reset,202};203 204static int toprgu_register_reset_controller(struct platform_device *pdev,205 int rst_num)206{207 int ret;208 struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev);209 210 spin_lock_init(&mtk_wdt->lock);211 212 mtk_wdt->rcdev.owner = THIS_MODULE;213 mtk_wdt->rcdev.nr_resets = rst_num;214 mtk_wdt->rcdev.ops = &toprgu_reset_ops;215 mtk_wdt->rcdev.of_node = pdev->dev.of_node;216 ret = devm_reset_controller_register(&pdev->dev, &mtk_wdt->rcdev);217 if (ret != 0)218 dev_err(&pdev->dev,219 "couldn't register wdt reset controller: %d\n", ret);220 return ret;221}222 223static int mtk_wdt_restart(struct watchdog_device *wdt_dev,224 unsigned long action, void *data)225{226 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);227 void __iomem *wdt_base;228 229 wdt_base = mtk_wdt->wdt_base;230 231 while (1) {232 writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST);233 mdelay(5);234 }235 236 return 0;237}238 239static int mtk_wdt_ping(struct watchdog_device *wdt_dev)240{241 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);242 void __iomem *wdt_base = mtk_wdt->wdt_base;243 244 iowrite32(WDT_RST_RELOAD, wdt_base + WDT_RST);245 246 return 0;247}248 249static int mtk_wdt_set_timeout(struct watchdog_device *wdt_dev,250 unsigned int timeout)251{252 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);253 void __iomem *wdt_base = mtk_wdt->wdt_base;254 u32 reg;255 256 wdt_dev->timeout = timeout;257 /*258 * In dual mode, irq will be triggered at timeout / 2259 * the real timeout occurs at timeout260 */261 if (wdt_dev->pretimeout)262 wdt_dev->pretimeout = timeout / 2;263 264 /*265 * One bit is the value of 512 ticks266 * The clock has 32 KHz267 */268 reg = WDT_LENGTH_TIMEOUT((timeout - wdt_dev->pretimeout) << 6)269 | WDT_LENGTH_KEY;270 iowrite32(reg, wdt_base + WDT_LENGTH);271 272 mtk_wdt_ping(wdt_dev);273 274 return 0;275}276 277static void mtk_wdt_init(struct watchdog_device *wdt_dev)278{279 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);280 void __iomem *wdt_base;281 282 wdt_base = mtk_wdt->wdt_base;283 284 if (readl(wdt_base + WDT_MODE) & WDT_MODE_EN) {285 set_bit(WDOG_HW_RUNNING, &wdt_dev->status);286 mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);287 }288}289 290static int mtk_wdt_stop(struct watchdog_device *wdt_dev)291{292 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);293 void __iomem *wdt_base = mtk_wdt->wdt_base;294 u32 reg;295 296 reg = readl(wdt_base + WDT_MODE);297 reg &= ~WDT_MODE_EN;298 reg |= WDT_MODE_KEY;299 iowrite32(reg, wdt_base + WDT_MODE);300 301 return 0;302}303 304static int mtk_wdt_start(struct watchdog_device *wdt_dev)305{306 u32 reg;307 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);308 void __iomem *wdt_base = mtk_wdt->wdt_base;309 int ret;310 311 ret = mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);312 if (ret < 0)313 return ret;314 315 reg = ioread32(wdt_base + WDT_MODE);316 if (wdt_dev->pretimeout)317 reg |= (WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);318 else319 reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);320 if (mtk_wdt->disable_wdt_extrst)321 reg &= ~WDT_MODE_EXRST_EN;322 if (mtk_wdt->reset_by_toprgu)323 reg |= WDT_MODE_CNT_SEL;324 reg |= (WDT_MODE_EN | WDT_MODE_KEY);325 iowrite32(reg, wdt_base + WDT_MODE);326 327 return 0;328}329 330static int mtk_wdt_set_pretimeout(struct watchdog_device *wdd,331 unsigned int timeout)332{333 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdd);334 void __iomem *wdt_base = mtk_wdt->wdt_base;335 u32 reg = ioread32(wdt_base + WDT_MODE);336 337 if (timeout && !wdd->pretimeout) {338 wdd->pretimeout = wdd->timeout / 2;339 reg |= (WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);340 } else if (!timeout && wdd->pretimeout) {341 wdd->pretimeout = 0;342 reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);343 } else {344 return 0;345 }346 347 reg |= WDT_MODE_KEY;348 iowrite32(reg, wdt_base + WDT_MODE);349 350 return mtk_wdt_set_timeout(wdd, wdd->timeout);351}352 353static irqreturn_t mtk_wdt_isr(int irq, void *arg)354{355 struct watchdog_device *wdd = arg;356 357 watchdog_notify_pretimeout(wdd);358 359 return IRQ_HANDLED;360}361 362static const struct watchdog_info mtk_wdt_info = {363 .identity = DRV_NAME,364 .options = WDIOF_SETTIMEOUT |365 WDIOF_KEEPALIVEPING |366 WDIOF_MAGICCLOSE,367};368 369static const struct watchdog_info mtk_wdt_pt_info = {370 .identity = DRV_NAME,371 .options = WDIOF_SETTIMEOUT |372 WDIOF_PRETIMEOUT |373 WDIOF_KEEPALIVEPING |374 WDIOF_MAGICCLOSE,375};376 377static const struct watchdog_ops mtk_wdt_ops = {378 .owner = THIS_MODULE,379 .start = mtk_wdt_start,380 .stop = mtk_wdt_stop,381 .ping = mtk_wdt_ping,382 .set_timeout = mtk_wdt_set_timeout,383 .set_pretimeout = mtk_wdt_set_pretimeout,384 .restart = mtk_wdt_restart,385};386 387static int mtk_wdt_probe(struct platform_device *pdev)388{389 struct device *dev = &pdev->dev;390 struct mtk_wdt_dev *mtk_wdt;391 const struct mtk_wdt_data *wdt_data;392 int err, irq;393 394 mtk_wdt = devm_kzalloc(dev, sizeof(*mtk_wdt), GFP_KERNEL);395 if (!mtk_wdt)396 return -ENOMEM;397 398 platform_set_drvdata(pdev, mtk_wdt);399 400 mtk_wdt->wdt_base = devm_platform_ioremap_resource(pdev, 0);401 if (IS_ERR(mtk_wdt->wdt_base))402 return PTR_ERR(mtk_wdt->wdt_base);403 404 irq = platform_get_irq_optional(pdev, 0);405 if (irq > 0) {406 err = devm_request_irq(&pdev->dev, irq, mtk_wdt_isr, 0, "wdt_bark",407 &mtk_wdt->wdt_dev);408 if (err)409 return err;410 411 mtk_wdt->wdt_dev.info = &mtk_wdt_pt_info;412 mtk_wdt->wdt_dev.pretimeout = WDT_MAX_TIMEOUT / 2;413 } else {414 if (irq == -EPROBE_DEFER)415 return -EPROBE_DEFER;416 417 mtk_wdt->wdt_dev.info = &mtk_wdt_info;418 }419 420 mtk_wdt->wdt_dev.ops = &mtk_wdt_ops;421 mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT;422 mtk_wdt->wdt_dev.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT * 1000;423 mtk_wdt->wdt_dev.min_timeout = WDT_MIN_TIMEOUT;424 mtk_wdt->wdt_dev.parent = dev;425 426 watchdog_init_timeout(&mtk_wdt->wdt_dev, timeout, dev);427 watchdog_set_nowayout(&mtk_wdt->wdt_dev, nowayout);428 watchdog_set_restart_priority(&mtk_wdt->wdt_dev, 128);429 430 watchdog_set_drvdata(&mtk_wdt->wdt_dev, mtk_wdt);431 432 mtk_wdt_init(&mtk_wdt->wdt_dev);433 434 watchdog_stop_on_reboot(&mtk_wdt->wdt_dev);435 err = devm_watchdog_register_device(dev, &mtk_wdt->wdt_dev);436 if (unlikely(err))437 return err;438 439 dev_info(dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n",440 mtk_wdt->wdt_dev.timeout, nowayout);441 442 wdt_data = of_device_get_match_data(dev);443 if (wdt_data) {444 err = toprgu_register_reset_controller(pdev,445 wdt_data->toprgu_sw_rst_num);446 if (err)447 return err;448 449 mtk_wdt->has_swsysrst_en = wdt_data->has_swsysrst_en;450 }451 452 mtk_wdt->disable_wdt_extrst =453 of_property_read_bool(dev->of_node, "mediatek,disable-extrst");454 455 mtk_wdt->reset_by_toprgu =456 of_property_read_bool(dev->of_node, "mediatek,reset-by-toprgu");457 458 return 0;459}460 461static int mtk_wdt_suspend(struct device *dev)462{463 struct mtk_wdt_dev *mtk_wdt = dev_get_drvdata(dev);464 465 if (watchdog_active(&mtk_wdt->wdt_dev))466 mtk_wdt_stop(&mtk_wdt->wdt_dev);467 468 return 0;469}470 471static int mtk_wdt_resume(struct device *dev)472{473 struct mtk_wdt_dev *mtk_wdt = dev_get_drvdata(dev);474 475 if (watchdog_active(&mtk_wdt->wdt_dev)) {476 mtk_wdt_start(&mtk_wdt->wdt_dev);477 mtk_wdt_ping(&mtk_wdt->wdt_dev);478 }479 480 return 0;481}482 483static const struct of_device_id mtk_wdt_dt_ids[] = {484 { .compatible = "mediatek,mt2712-wdt", .data = &mt2712_data },485 { .compatible = "mediatek,mt6589-wdt" },486 { .compatible = "mediatek,mt6795-wdt", .data = &mt6795_data },487 { .compatible = "mediatek,mt7986-wdt", .data = &mt7986_data },488 { .compatible = "mediatek,mt7988-wdt", .data = &mt7988_data },489 { .compatible = "mediatek,mt8183-wdt", .data = &mt8183_data },490 { .compatible = "mediatek,mt8186-wdt", .data = &mt8186_data },491 { .compatible = "mediatek,mt8188-wdt", .data = &mt8188_data },492 { .compatible = "mediatek,mt8192-wdt", .data = &mt8192_data },493 { .compatible = "mediatek,mt8195-wdt", .data = &mt8195_data },494 { /* sentinel */ }495};496MODULE_DEVICE_TABLE(of, mtk_wdt_dt_ids);497 498static DEFINE_SIMPLE_DEV_PM_OPS(mtk_wdt_pm_ops,499 mtk_wdt_suspend, mtk_wdt_resume);500 501static struct platform_driver mtk_wdt_driver = {502 .probe = mtk_wdt_probe,503 .driver = {504 .name = DRV_NAME,505 .pm = pm_sleep_ptr(&mtk_wdt_pm_ops),506 .of_match_table = mtk_wdt_dt_ids,507 },508};509 510module_platform_driver(mtk_wdt_driver);511 512module_param(timeout, uint, 0);513MODULE_PARM_DESC(timeout, "Watchdog heartbeat in seconds");514 515module_param(nowayout, bool, 0);516MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="517 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");518 519MODULE_LICENSE("GPL");520MODULE_AUTHOR("Matthias Brugger <matthias.bgg@gmail.com>");521MODULE_DESCRIPTION("Mediatek WatchDog Timer Driver");522MODULE_VERSION(DRV_VERSION);523