1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Ralink MT7621/MT7628 built-in hardware watchdog timer 4 * 5 * Copyright (C) 2014 John Crispin <john@phrozen.org> 6 * 7 * This driver was based on: drivers/watchdog/rt2880_wdt.c 8 */ 9 10 #include <linux/clk.h> 11 #include <linux/reset.h> 12 #include <linux/module.h> 13 #include <linux/kernel.h> 14 #include <linux/watchdog.h> 15 #include <linux/moduleparam.h> 16 #include <linux/platform_device.h> 17 #include <linux/mod_devicetable.h> 18 19 #include <asm/mach-ralink/ralink_regs.h> 20 21 #define SYSC_RSTSTAT 0x38 22 #define WDT_RST_CAUSE BIT(1) 23 24 #define RALINK_WDT_TIMEOUT 30 25 26 #define TIMER_REG_TMRSTAT 0x00 27 #define TIMER_REG_TMR1LOAD 0x24 28 #define TIMER_REG_TMR1CTL 0x20 29 30 #define TMR1CTL_ENABLE BIT(7) 31 #define TMR1CTL_RESTART BIT(9) 32 #define TMR1CTL_PRESCALE_SHIFT 16 33 34 static void __iomem *mt7621_wdt_base; 35 static struct reset_control *mt7621_wdt_reset; 36 37 static bool nowayout = WATCHDOG_NOWAYOUT; 38 module_param(nowayout, bool, 0); 39 MODULE_PARM_DESC(nowayout, 40 "Watchdog cannot be stopped once started (default=" 41 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 42 43 static inline void rt_wdt_w32(unsigned reg, u32 val) 44 { 45 iowrite32(val, mt7621_wdt_base + reg); 46 } 47 48 static inline u32 rt_wdt_r32(unsigned reg) 49 { 50 return ioread32(mt7621_wdt_base + reg); 51 } 52 53 static int mt7621_wdt_ping(struct watchdog_device *w) 54 { 55 rt_wdt_w32(TIMER_REG_TMRSTAT, TMR1CTL_RESTART); 56 57 return 0; 58 } 59 60 static int mt7621_wdt_set_timeout(struct watchdog_device *w, unsigned int t) 61 { 62 w->timeout = t; 63 rt_wdt_w32(TIMER_REG_TMR1LOAD, t * 1000); 64 mt7621_wdt_ping(w); 65 66 return 0; 67 } 68 69 static int mt7621_wdt_start(struct watchdog_device *w) 70 { 71 u32 t; 72 73 /* set the prescaler to 1ms == 1000us */ 74 rt_wdt_w32(TIMER_REG_TMR1CTL, 1000 << TMR1CTL_PRESCALE_SHIFT); 75 76 mt7621_wdt_set_timeout(w, w->timeout); 77 78 t = rt_wdt_r32(TIMER_REG_TMR1CTL); 79 t |= TMR1CTL_ENABLE; 80 rt_wdt_w32(TIMER_REG_TMR1CTL, t); 81 82 return 0; 83 } 84 85 static int mt7621_wdt_stop(struct watchdog_device *w) 86 { 87 u32 t; 88 89 mt7621_wdt_ping(w); 90 91 t = rt_wdt_r32(TIMER_REG_TMR1CTL); 92 t &= ~TMR1CTL_ENABLE; 93 rt_wdt_w32(TIMER_REG_TMR1CTL, t); 94 95 return 0; 96 } 97 98 static int mt7621_wdt_bootcause(void) 99 { 100 if (rt_sysc_r32(SYSC_RSTSTAT) & WDT_RST_CAUSE) 101 return WDIOF_CARDRESET; 102 103 return 0; 104 } 105 106 static int mt7621_wdt_is_running(struct watchdog_device *w) 107 { 108 return !!(rt_wdt_r32(TIMER_REG_TMR1CTL) & TMR1CTL_ENABLE); 109 } 110 111 static const struct watchdog_info mt7621_wdt_info = { 112 .identity = "Mediatek Watchdog", 113 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 114 }; 115 116 static const struct watchdog_ops mt7621_wdt_ops = { 117 .owner = THIS_MODULE, 118 .start = mt7621_wdt_start, 119 .stop = mt7621_wdt_stop, 120 .ping = mt7621_wdt_ping, 121 .set_timeout = mt7621_wdt_set_timeout, 122 }; 123 124 static struct watchdog_device mt7621_wdt_dev = { 125 .info = &mt7621_wdt_info, 126 .ops = &mt7621_wdt_ops, 127 .min_timeout = 1, 128 .max_timeout = 0xfffful / 1000, 129 }; 130 131 static int mt7621_wdt_probe(struct platform_device *pdev) 132 { 133 struct device *dev = &pdev->dev; 134 mt7621_wdt_base = devm_platform_ioremap_resource(pdev, 0); 135 if (IS_ERR(mt7621_wdt_base)) 136 return PTR_ERR(mt7621_wdt_base); 137 138 mt7621_wdt_reset = devm_reset_control_get_exclusive(dev, NULL); 139 if (!IS_ERR(mt7621_wdt_reset)) 140 reset_control_deassert(mt7621_wdt_reset); 141 142 mt7621_wdt_dev.bootstatus = mt7621_wdt_bootcause(); 143 144 watchdog_init_timeout(&mt7621_wdt_dev, mt7621_wdt_dev.max_timeout, 145 dev); 146 watchdog_set_nowayout(&mt7621_wdt_dev, nowayout); 147 if (mt7621_wdt_is_running(&mt7621_wdt_dev)) { 148 /* 149 * Make sure to apply timeout from watchdog core, taking 150 * the prescaler of this driver here into account (the 151 * boot loader might be using a different prescaler). 152 * 153 * To avoid spurious resets because of different scaling, 154 * we first disable the watchdog, set the new prescaler 155 * and timeout, and then re-enable the watchdog. 156 */ 157 mt7621_wdt_stop(&mt7621_wdt_dev); 158 mt7621_wdt_start(&mt7621_wdt_dev); 159 set_bit(WDOG_HW_RUNNING, &mt7621_wdt_dev.status); 160 } 161 162 return devm_watchdog_register_device(dev, &mt7621_wdt_dev); 163 } 164 165 static void mt7621_wdt_shutdown(struct platform_device *pdev) 166 { 167 mt7621_wdt_stop(&mt7621_wdt_dev); 168 } 169 170 static const struct of_device_id mt7621_wdt_match[] = { 171 { .compatible = "mediatek,mt7621-wdt" }, 172 {}, 173 }; 174 MODULE_DEVICE_TABLE(of, mt7621_wdt_match); 175 176 static struct platform_driver mt7621_wdt_driver = { 177 .probe = mt7621_wdt_probe, 178 .shutdown = mt7621_wdt_shutdown, 179 .driver = { 180 .name = KBUILD_MODNAME, 181 .of_match_table = mt7621_wdt_match, 182 }, 183 }; 184 185 module_platform_driver(mt7621_wdt_driver); 186 187 MODULE_DESCRIPTION("MediaTek MT762x hardware watchdog driver"); 188 MODULE_AUTHOR("John Crispin <john@phrozen.org"); 189 MODULE_LICENSE("GPL v2"); 190