1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Renesas RZ/V2H(P) WDT Watchdog Driver 4 * 5 * Copyright (C) 2024 Renesas Electronics Corporation. 6 */ 7 #include <linux/clk.h> 8 #include <linux/delay.h> 9 #include <linux/io.h> 10 #include <linux/kernel.h> 11 #include <linux/module.h> 12 #include <linux/of.h> 13 #include <linux/platform_device.h> 14 #include <linux/pm_runtime.h> 15 #include <linux/reset.h> 16 #include <linux/stringify.h> 17 #include <linux/units.h> 18 #include <linux/watchdog.h> 19 20 #define WDTRR 0x00 /* WDT Refresh Register RW, 8 */ 21 #define WDTCR 0x02 /* WDT Control Register RW, 16 */ 22 #define WDTSR 0x04 /* WDT Status Register RW, 16 */ 23 #define WDTRCR 0x06 /* WDT Reset Control Register RW, 8 */ 24 25 /* This register is only available on RZ/T2H and RZ/N2H SoCs */ 26 #define WDTDCR 0x00 /* WDT Debug Control Register RW, 32 */ 27 28 #define WDTCR_TOPS_1024 0x00 29 #define WDTCR_TOPS_4096 0x01 30 #define WDTCR_TOPS_16384 0x03 31 32 #define WDTCR_CKS_CLK_1 0x00 33 #define WDTCR_CKS_CLK_4 0x10 34 #define WDTCR_CKS_CLK_256 0x50 35 #define WDTCR_CKS_CLK_8192 0x80 36 37 #define WDTCR_RPES_0 0x300 38 #define WDTCR_RPES_75 0x000 39 40 #define WDTCR_RPSS_25 0x00 41 #define WDTCR_RPSS_100 0x3000 42 43 #define WDTRCR_RSTIRQS BIT(7) 44 45 #define WDTDCR_WDTSTOPCTRL BIT(0) 46 47 #define WDT_DEFAULT_TIMEOUT 60U 48 49 static bool nowayout = WATCHDOG_NOWAYOUT; 50 module_param(nowayout, bool, 0); 51 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 52 __stringify(WATCHDOG_NOWAYOUT) ")"); 53 54 enum rzv2h_wdt_count_source { 55 COUNT_SOURCE_LOCO, 56 COUNT_SOURCE_PCLK, 57 }; 58 59 struct rzv2h_of_data { 60 u8 cks_min; 61 u8 cks_max; 62 u16 cks_div; 63 u8 tops; 64 u16 timeout_cycles; 65 enum rzv2h_wdt_count_source count_source; 66 bool wdtdcr; 67 }; 68 69 struct rzv2h_wdt_priv { 70 void __iomem *base; 71 void __iomem *wdtdcr; 72 struct clk *pclk; 73 struct clk *oscclk; 74 struct reset_control *rstc; 75 struct watchdog_device wdev; 76 const struct rzv2h_of_data *of_data; 77 }; 78 79 static int rzv2h_wdt_ping(struct watchdog_device *wdev) 80 { 81 struct rzv2h_wdt_priv *priv = watchdog_get_drvdata(wdev); 82 83 /* 84 * The down-counter is refreshed and starts counting operation on 85 * a write of the values 00h and FFh to the WDTRR register. 86 */ 87 writeb(0x0, priv->base + WDTRR); 88 writeb(0xFF, priv->base + WDTRR); 89 90 return 0; 91 } 92 93 static void rzt2h_wdt_wdtdcr_count_stop(struct rzv2h_wdt_priv *priv) 94 { 95 u32 reg = readl(priv->wdtdcr + WDTDCR); 96 97 writel(reg | WDTDCR_WDTSTOPCTRL, priv->wdtdcr + WDTDCR); 98 } 99 100 static void rzt2h_wdt_wdtdcr_count_start(struct rzv2h_wdt_priv *priv) 101 { 102 u32 reg = readl(priv->wdtdcr + WDTDCR); 103 104 writel(reg & ~WDTDCR_WDTSTOPCTRL, priv->wdtdcr + WDTDCR); 105 } 106 107 static void rzv2h_wdt_setup(struct watchdog_device *wdev, u16 wdtcr) 108 { 109 struct rzv2h_wdt_priv *priv = watchdog_get_drvdata(wdev); 110 111 /* Configure the timeout, clock division ratio, and window start and end positions. */ 112 writew(wdtcr, priv->base + WDTCR); 113 114 /* Enable interrupt output to the ICU. */ 115 writeb(0, priv->base + WDTRCR); 116 117 /* Clear underflow flag and refresh error flag. */ 118 writew(0, priv->base + WDTSR); 119 } 120 121 static int rzv2h_wdt_start(struct watchdog_device *wdev) 122 { 123 struct rzv2h_wdt_priv *priv = watchdog_get_drvdata(wdev); 124 const struct rzv2h_of_data *of_data = priv->of_data; 125 int ret; 126 127 ret = pm_runtime_resume_and_get(wdev->parent); 128 if (ret) 129 return ret; 130 131 ret = reset_control_deassert(priv->rstc); 132 if (ret) { 133 pm_runtime_put(wdev->parent); 134 return ret; 135 } 136 137 /* delay to handle clock halt after de-assert operation */ 138 udelay(3); 139 140 /* 141 * WDTCR 142 * - CKS[7:4] - Clock Division Ratio Select 143 * - 0101b: oscclk/256 for RZ/V2H(P) 144 * - 1000b: pclkl/8192 for RZ/T2H 145 * - RPSS[13:12] - Window Start Position Select - 11b: 100% 146 * - RPES[9:8] - Window End Position Select - 11b: 0% 147 * - TOPS[1:0] - Timeout Period Select 148 * - 11b: 16384 cycles (3FFFh) for RZ/V2H(P) 149 * - 01b: 4096 cycles (0FFFh) for RZ/T2H 150 */ 151 rzv2h_wdt_setup(wdev, of_data->cks_max | WDTCR_RPSS_100 | 152 WDTCR_RPES_0 | of_data->tops); 153 154 if (priv->of_data->wdtdcr) 155 rzt2h_wdt_wdtdcr_count_start(priv); 156 157 /* 158 * Down counting starts after writing the sequence 00h -> FFh to the 159 * WDTRR register. Hence, call the ping operation after loading the counter. 160 */ 161 rzv2h_wdt_ping(wdev); 162 163 return 0; 164 } 165 166 static int rzv2h_wdt_stop(struct watchdog_device *wdev) 167 { 168 struct rzv2h_wdt_priv *priv = watchdog_get_drvdata(wdev); 169 int ret; 170 171 ret = reset_control_assert(priv->rstc); 172 if (ret) 173 return ret; 174 175 if (priv->of_data->wdtdcr) 176 rzt2h_wdt_wdtdcr_count_stop(priv); 177 178 pm_runtime_put(wdev->parent); 179 180 return 0; 181 } 182 183 static const struct watchdog_info rzv2h_wdt_ident = { 184 .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, 185 .identity = "Renesas RZ/V2H WDT Watchdog", 186 }; 187 188 static int rzv2h_wdt_restart(struct watchdog_device *wdev, 189 unsigned long action, void *data) 190 { 191 struct rzv2h_wdt_priv *priv = watchdog_get_drvdata(wdev); 192 int ret; 193 194 if (!watchdog_active(wdev)) { 195 ret = clk_enable(priv->pclk); 196 if (ret) 197 return ret; 198 199 ret = clk_enable(priv->oscclk); 200 if (ret) { 201 clk_disable(priv->pclk); 202 return ret; 203 } 204 205 ret = reset_control_deassert(priv->rstc); 206 if (ret) { 207 clk_disable(priv->oscclk); 208 clk_disable(priv->pclk); 209 return ret; 210 } 211 } else { 212 /* 213 * Writing to the WDT Control Register (WDTCR) or WDT Reset 214 * Control Register (WDTRCR) is possible once between the 215 * release from the reset state and the first refresh operation. 216 * Therefore, issue a reset if the watchdog is active. 217 */ 218 ret = reset_control_reset(priv->rstc); 219 if (ret) 220 return ret; 221 } 222 223 /* delay to handle clock halt after de-assert operation */ 224 udelay(3); 225 226 /* 227 * WDTCR 228 * - CKS[7:4] - Clock Division Ratio Select 229 * - 0000b: oscclk/1 for RZ/V2H(P) 230 * - 0100b: pclkl/4 for RZ/T2H 231 * - RPSS[13:12] - Window Start Position Select - 00b: 25% 232 * - RPES[9:8] - Window End Position Select - 00b: 75% 233 * - TOPS[1:0] - Timeout Period Select - 00b: 1024 cycles (03FFh) 234 */ 235 rzv2h_wdt_setup(wdev, priv->of_data->cks_min | WDTCR_RPSS_25 | 236 WDTCR_RPES_75 | WDTCR_TOPS_1024); 237 238 if (priv->of_data->wdtdcr) 239 rzt2h_wdt_wdtdcr_count_start(priv); 240 241 rzv2h_wdt_ping(wdev); 242 243 /* wait for underflow to trigger... */ 244 udelay(5); 245 246 return 0; 247 } 248 249 static const struct watchdog_ops rzv2h_wdt_ops = { 250 .owner = THIS_MODULE, 251 .start = rzv2h_wdt_start, 252 .stop = rzv2h_wdt_stop, 253 .ping = rzv2h_wdt_ping, 254 .restart = rzv2h_wdt_restart, 255 }; 256 257 static int rzt2h_wdt_wdtdcr_init(struct platform_device *pdev, 258 struct rzv2h_wdt_priv *priv) 259 { 260 int ret; 261 262 priv->wdtdcr = devm_platform_ioremap_resource(pdev, 1); 263 if (IS_ERR(priv->wdtdcr)) 264 return PTR_ERR(priv->wdtdcr); 265 266 ret = pm_runtime_resume_and_get(&pdev->dev); 267 if (ret) 268 return ret; 269 270 rzt2h_wdt_wdtdcr_count_stop(priv); 271 272 pm_runtime_put(&pdev->dev); 273 274 return 0; 275 } 276 277 static int rzv2h_wdt_probe(struct platform_device *pdev) 278 { 279 struct device *dev = &pdev->dev; 280 struct rzv2h_wdt_priv *priv; 281 struct clk *count_clk; 282 unsigned long rate; 283 int ret; 284 285 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 286 if (!priv) 287 return -ENOMEM; 288 289 priv->of_data = of_device_get_match_data(dev); 290 291 priv->base = devm_platform_ioremap_resource(pdev, 0); 292 if (IS_ERR(priv->base)) 293 return PTR_ERR(priv->base); 294 295 priv->pclk = devm_clk_get_prepared(dev, "pclk"); 296 if (IS_ERR(priv->pclk)) 297 return dev_err_probe(dev, PTR_ERR(priv->pclk), "Failed to get pclk\n"); 298 299 priv->oscclk = devm_clk_get_optional_prepared(dev, "oscclk"); 300 if (IS_ERR(priv->oscclk)) 301 return dev_err_probe(dev, PTR_ERR(priv->oscclk), "Failed to get oscclk\n"); 302 303 priv->rstc = devm_reset_control_get_optional_exclusive(dev, NULL); 304 if (IS_ERR(priv->rstc)) 305 return dev_err_probe(dev, PTR_ERR(priv->rstc), 306 "Failed to get cpg reset\n"); 307 308 switch (priv->of_data->count_source) { 309 case COUNT_SOURCE_LOCO: 310 count_clk = priv->oscclk; 311 break; 312 case COUNT_SOURCE_PCLK: 313 count_clk = priv->pclk; 314 break; 315 default: 316 return dev_err_probe(dev, -EINVAL, "Invalid count source\n"); 317 } 318 319 rate = clk_get_rate(count_clk); 320 if (!rate) 321 return dev_err_probe(dev, -EINVAL, "Invalid clock rate\n"); 322 323 priv->wdev.max_hw_heartbeat_ms = (MILLI * priv->of_data->timeout_cycles * 324 priv->of_data->cks_div) / rate; 325 dev_dbg(dev, "max hw timeout of %dms\n", priv->wdev.max_hw_heartbeat_ms); 326 327 ret = devm_pm_runtime_enable(dev); 328 if (ret) 329 return ret; 330 331 if (priv->of_data->wdtdcr) { 332 ret = rzt2h_wdt_wdtdcr_init(pdev, priv); 333 if (ret) 334 return dev_err_probe(dev, ret, "WDTDCR init failed\n"); 335 } 336 337 priv->wdev.min_timeout = 1; 338 priv->wdev.timeout = WDT_DEFAULT_TIMEOUT; 339 priv->wdev.info = &rzv2h_wdt_ident; 340 priv->wdev.ops = &rzv2h_wdt_ops; 341 priv->wdev.parent = dev; 342 watchdog_set_drvdata(&priv->wdev, priv); 343 watchdog_set_nowayout(&priv->wdev, nowayout); 344 watchdog_stop_on_unregister(&priv->wdev); 345 346 watchdog_init_timeout(&priv->wdev, 0, dev); 347 348 return devm_watchdog_register_device(dev, &priv->wdev); 349 } 350 351 static const struct rzv2h_of_data rzt2h_wdt_of_data = { 352 .cks_min = WDTCR_CKS_CLK_4, 353 .cks_max = WDTCR_CKS_CLK_8192, 354 .cks_div = 8192, 355 .tops = WDTCR_TOPS_4096, 356 .timeout_cycles = 4096, 357 .count_source = COUNT_SOURCE_PCLK, 358 .wdtdcr = true, 359 }; 360 361 static const struct rzv2h_of_data rzv2h_wdt_of_data = { 362 .cks_min = WDTCR_CKS_CLK_1, 363 .cks_max = WDTCR_CKS_CLK_256, 364 .cks_div = 256, 365 .tops = WDTCR_TOPS_16384, 366 .timeout_cycles = 16384, 367 .count_source = COUNT_SOURCE_LOCO, 368 }; 369 370 static const struct of_device_id rzv2h_wdt_ids[] = { 371 { .compatible = "renesas,r9a09g057-wdt", .data = &rzv2h_wdt_of_data }, 372 { .compatible = "renesas,r9a09g077-wdt", .data = &rzt2h_wdt_of_data }, 373 { /* sentinel */ } 374 }; 375 MODULE_DEVICE_TABLE(of, rzv2h_wdt_ids); 376 377 static struct platform_driver rzv2h_wdt_driver = { 378 .driver = { 379 .name = "rzv2h_wdt", 380 .of_match_table = rzv2h_wdt_ids, 381 }, 382 .probe = rzv2h_wdt_probe, 383 }; 384 module_platform_driver(rzv2h_wdt_driver); 385 MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>"); 386 MODULE_DESCRIPTION("Renesas RZ/V2H(P) WDT Watchdog Driver"); 387 MODULE_LICENSE("GPL"); 388