1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2004 Simtec Electronics 4 * Ben Dooks <ben@simtec.co.uk> 5 * 6 * S3C2410 Watchdog Timer Support 7 * 8 * Based on, softdog.c by Alan Cox, 9 * (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk> 10 */ 11 12 #include <linux/bits.h> 13 #include <linux/module.h> 14 #include <linux/moduleparam.h> 15 #include <linux/types.h> 16 #include <linux/timer.h> 17 #include <linux/watchdog.h> 18 #include <linux/platform_device.h> 19 #include <linux/interrupt.h> 20 #include <linux/clk.h> 21 #include <linux/uaccess.h> 22 #include <linux/io.h> 23 #include <linux/cpufreq.h> 24 #include <linux/slab.h> 25 #include <linux/err.h> 26 #include <linux/of.h> 27 #include <linux/mfd/syscon.h> 28 #include <linux/regmap.h> 29 #include <linux/delay.h> 30 #include <linux/math64.h> 31 32 #define S3C2410_WTCON 0x00 33 #define S3C2410_WTDAT 0x04 34 #define S3C2410_WTCNT 0x08 35 #define S3C2410_WTCLRINT 0x0c 36 37 #define S3C2410_WTCNT_MAXCNT_16 0xffff 38 #define S3C2410_WTCNT_MAXCNT_32 0xffffffff 39 40 #define S3C2410_WTCON_RSTEN BIT(0) 41 #define S3C2410_WTCON_INTEN BIT(2) 42 #define S3C2410_WTCON_ENABLE BIT(5) 43 #define S3C2410_WTCON_DBGACK_MASK BIT(16) 44 45 #define S3C2410_WTCON_DIV16 (0 << 3) 46 #define S3C2410_WTCON_DIV32 (1 << 3) 47 #define S3C2410_WTCON_DIV64 (2 << 3) 48 #define S3C2410_WTCON_DIV128 (3 << 3) 49 50 #define S3C2410_WTCON_MAXDIV 0x80 51 52 #define S3C2410_WTCON_PRESCALE(x) ((x) << 8) 53 #define S3C2410_WTCON_PRESCALE_MASK (0xff << 8) 54 #define S3C2410_WTCON_PRESCALE_MAX 0xff 55 56 #define S3C2410_WATCHDOG_ATBOOT (0) 57 #define S3C2410_WATCHDOG_DEFAULT_TIME (15) 58 59 #define EXYNOS5_RST_STAT_REG_OFFSET 0x0404 60 #define EXYNOS5_WDT_DISABLE_REG_OFFSET 0x0408 61 #define EXYNOS5_WDT_MASK_RESET_REG_OFFSET 0x040c 62 #define EXYNOS850_CLUSTER0_NONCPU_OUT 0x1220 63 #define EXYNOS850_CLUSTER0_NONCPU_INT_EN 0x1244 64 #define EXYNOS850_CLUSTER1_NONCPU_OUT 0x1620 65 #define EXYNOS850_CLUSTER1_NONCPU_INT_EN 0x1644 66 #define EXYNOSAUTOV9_CLUSTER1_NONCPU_OUT 0x1520 67 #define EXYNOSAUTOV9_CLUSTER1_NONCPU_INT_EN 0x1544 68 #define EXYNOSAUTOV920_CLUSTER0_NONCPU_OUT 0x1420 69 #define EXYNOSAUTOV920_CLUSTER0_NONCPU_INT_EN 0x1444 70 #define EXYNOSAUTOV920_CLUSTER1_NONCPU_OUT 0x1720 71 #define EXYNOSAUTOV920_CLUSTER1_NONCPU_INT_EN 0x1744 72 73 #define EXYNOS850_CLUSTER0_WDTRESET_BIT 24 74 #define EXYNOS850_CLUSTER1_WDTRESET_BIT 23 75 #define EXYNOSAUTOV9_CLUSTER0_WDTRESET_BIT 25 76 #define EXYNOSAUTOV9_CLUSTER1_WDTRESET_BIT 24 77 #define EXYNOSAUTOV920_CLUSTER0_WDTRESET_BIT 0 78 #define EXYNOSAUTOV920_CLUSTER1_WDTRESET_BIT 1 79 80 #define GS_CLUSTER0_NONCPU_OUT 0x1220 81 #define GS_CLUSTER1_NONCPU_OUT 0x1420 82 #define GS_CLUSTER0_NONCPU_INT_EN 0x1244 83 #define GS_CLUSTER1_NONCPU_INT_EN 0x1444 84 #define GS_CLUSTER2_NONCPU_INT_EN 0x1644 85 #define GS_RST_STAT_REG_OFFSET 0x3B44 86 87 #define EXYNOS990_CLUSTER2_NONCPU_OUT 0x1620 88 #define EXYNOS990_CLUSTER2_NONCPU_INT_EN 0x1644 89 #define EXYNOS990_CLUSTER2_WDTRESET_BIT 23 90 91 /** 92 * DOC: Quirk flags for different Samsung watchdog IP-cores 93 * 94 * This driver supports multiple Samsung SoCs, each of which might have 95 * different set of registers and features supported. As watchdog block 96 * sometimes requires modifying PMU registers for proper functioning, register 97 * differences in both watchdog and PMU IP-cores should be accounted for. Quirk 98 * flags described below serve the purpose of telling the driver about mentioned 99 * SoC traits, and can be specified in driver data for each particular supported 100 * device. 101 * 102 * %QUIRK_HAS_WTCLRINT_REG: Watchdog block has WTCLRINT register. It's used to 103 * clear the interrupt once the interrupt service routine is complete. It's 104 * write-only, writing any values to this register clears the interrupt, but 105 * reading is not permitted. 106 * 107 * %QUIRK_HAS_PMU_MASK_RESET: PMU block has the register for disabling/enabling 108 * WDT reset request. On old SoCs it's usually called MASK_WDT_RESET_REQUEST, 109 * new SoCs have CLUSTERx_NONCPU_INT_EN register, which 'mask_bit' value is 110 * inverted compared to the former one. 111 * 112 * %QUIRK_HAS_PMU_RST_STAT: PMU block has RST_STAT (reset status) register, 113 * which contains bits indicating the reason for most recent CPU reset. If 114 * present, driver will use this register to check if previous reboot was due to 115 * watchdog timer reset. 116 * 117 * %QUIRK_HAS_PMU_AUTO_DISABLE: PMU block has AUTOMATIC_WDT_RESET_DISABLE 118 * register. If 'mask_bit' bit is set, PMU will disable WDT reset when 119 * corresponding processor is in reset state. 120 * 121 * %QUIRK_HAS_PMU_CNT_EN: PMU block has some register (e.g. CLUSTERx_NONCPU_OUT) 122 * with "watchdog counter enable" bit. That bit should be set to make watchdog 123 * counter running. 124 * 125 * %QUIRK_HAS_DBGACK_BIT: WTCON register has DBGACK_MASK bit. Setting the 126 * DBGACK_MASK bit disables the watchdog outputs when the SoC is in debug mode. 127 * Debug mode is determined by the DBGACK CPU signal. 128 * 129 * %QUIRK_HAS_32BIT_CNT: WTDAT and WTCNT are 32-bit registers. With these 130 * 32-bit registers, larger values will be set, which means that larger timeouts 131 * value can be set. 132 */ 133 #define QUIRK_HAS_WTCLRINT_REG BIT(0) 134 #define QUIRK_HAS_PMU_MASK_RESET BIT(1) 135 #define QUIRK_HAS_PMU_RST_STAT BIT(2) 136 #define QUIRK_HAS_PMU_AUTO_DISABLE BIT(3) 137 #define QUIRK_HAS_PMU_CNT_EN BIT(4) 138 #define QUIRK_HAS_DBGACK_BIT BIT(5) 139 #define QUIRK_HAS_32BIT_CNT BIT(6) 140 141 /* These quirks require that we have a PMU register map */ 142 #define QUIRKS_HAVE_PMUREG \ 143 (QUIRK_HAS_PMU_MASK_RESET | QUIRK_HAS_PMU_RST_STAT | \ 144 QUIRK_HAS_PMU_AUTO_DISABLE | QUIRK_HAS_PMU_CNT_EN) 145 146 static bool nowayout = WATCHDOG_NOWAYOUT; 147 static int tmr_margin; 148 static int tmr_atboot = S3C2410_WATCHDOG_ATBOOT; 149 static int soft_noboot; 150 151 module_param(tmr_margin, int, 0); 152 module_param(tmr_atboot, int, 0); 153 module_param(nowayout, bool, 0); 154 module_param(soft_noboot, int, 0); 155 156 MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. (default=" 157 __MODULE_STRING(S3C2410_WATCHDOG_DEFAULT_TIME) ")"); 158 MODULE_PARM_DESC(tmr_atboot, 159 "Watchdog is started at boot time if set to 1, default=" 160 __MODULE_STRING(S3C2410_WATCHDOG_ATBOOT)); 161 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 162 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 163 MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default 0)"); 164 165 /** 166 * struct s3c2410_wdt_variant - Per-variant config data 167 * 168 * @disable_reg: Offset in pmureg for the register that disables the watchdog 169 * timer reset functionality. 170 * @mask_reset_reg: Offset in pmureg for the register that masks the watchdog 171 * timer reset functionality. 172 * @mask_reset_inv: If set, mask_reset_reg value will have inverted meaning. 173 * @mask_bit: Bit number for the watchdog timer in the disable register and the 174 * mask reset register. 175 * @rst_stat_reg: Offset in pmureg for the register that has the reset status. 176 * @rst_stat_bit: Bit number in the rst_stat register indicating a watchdog 177 * reset. 178 * @cnt_en_reg: Offset in pmureg for the register that enables WDT counter. 179 * @cnt_en_bit: Bit number for "watchdog counter enable" in cnt_en register. 180 * @quirks: A bitfield of quirks. 181 */ 182 183 struct s3c2410_wdt_variant { 184 int disable_reg; 185 int mask_reset_reg; 186 bool mask_reset_inv; 187 int mask_bit; 188 int rst_stat_reg; 189 int rst_stat_bit; 190 int cnt_en_reg; 191 int cnt_en_bit; 192 u32 quirks; 193 }; 194 195 struct s3c2410_wdt { 196 struct device *dev; 197 struct clk *bus_clk; /* for register interface (PCLK) */ 198 struct clk *src_clk; /* for WDT counter */ 199 void __iomem *reg_base; 200 unsigned int count; 201 spinlock_t lock; 202 unsigned long wtcon_save; 203 unsigned long wtdat_save; 204 struct watchdog_device wdt_device; 205 struct notifier_block freq_transition; 206 const struct s3c2410_wdt_variant *drv_data; 207 struct regmap *pmureg; 208 u32 max_cnt; 209 }; 210 211 static const struct s3c2410_wdt_variant drv_data_s3c2410 = { 212 .quirks = 0 213 }; 214 215 #ifdef CONFIG_OF 216 static const struct s3c2410_wdt_variant drv_data_s3c6410 = { 217 .quirks = QUIRK_HAS_WTCLRINT_REG, 218 }; 219 220 static const struct s3c2410_wdt_variant drv_data_exynos5250 = { 221 .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, 222 .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, 223 .mask_bit = 20, 224 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 225 .rst_stat_bit = 20, 226 .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | \ 227 QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_AUTO_DISABLE, 228 }; 229 230 static const struct s3c2410_wdt_variant drv_data_exynos5420 = { 231 .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, 232 .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, 233 .mask_bit = 0, 234 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 235 .rst_stat_bit = 9, 236 .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | \ 237 QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_AUTO_DISABLE, 238 }; 239 240 static const struct s3c2410_wdt_variant drv_data_exynos7 = { 241 .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, 242 .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, 243 .mask_bit = 23, 244 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 245 .rst_stat_bit = 23, /* A57 WDTRESET */ 246 .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | \ 247 QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_AUTO_DISABLE, 248 }; 249 250 static const struct s3c2410_wdt_variant drv_data_exynos850_cl0 = { 251 .mask_reset_reg = EXYNOS850_CLUSTER0_NONCPU_INT_EN, 252 .mask_bit = 2, 253 .mask_reset_inv = true, 254 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 255 .rst_stat_bit = EXYNOS850_CLUSTER0_WDTRESET_BIT, 256 .cnt_en_reg = EXYNOS850_CLUSTER0_NONCPU_OUT, 257 .cnt_en_bit = 7, 258 .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | \ 259 QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN, 260 }; 261 262 static const struct s3c2410_wdt_variant drv_data_exynos850_cl1 = { 263 .mask_reset_reg = EXYNOS850_CLUSTER1_NONCPU_INT_EN, 264 .mask_bit = 2, 265 .mask_reset_inv = true, 266 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 267 .rst_stat_bit = EXYNOS850_CLUSTER1_WDTRESET_BIT, 268 .cnt_en_reg = EXYNOS850_CLUSTER1_NONCPU_OUT, 269 .cnt_en_bit = 7, 270 .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | \ 271 QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN, 272 }; 273 274 static const struct s3c2410_wdt_variant drv_data_exynos990_cl0 = { 275 .mask_reset_reg = GS_CLUSTER0_NONCPU_INT_EN, 276 .mask_bit = 2, 277 .mask_reset_inv = true, 278 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 279 .rst_stat_bit = EXYNOS850_CLUSTER0_WDTRESET_BIT, 280 .cnt_en_reg = EXYNOSAUTOV920_CLUSTER0_NONCPU_OUT, 281 .cnt_en_bit = 7, 282 .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | 283 QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN | 284 QUIRK_HAS_DBGACK_BIT, 285 }; 286 287 static const struct s3c2410_wdt_variant drv_data_exynos990_cl2 = { 288 .mask_reset_reg = EXYNOS990_CLUSTER2_NONCPU_INT_EN, 289 .mask_bit = 2, 290 .mask_reset_inv = true, 291 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 292 .rst_stat_bit = EXYNOS990_CLUSTER2_WDTRESET_BIT, 293 .cnt_en_reg = EXYNOS990_CLUSTER2_NONCPU_OUT, 294 .cnt_en_bit = 7, 295 .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | 296 QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN | 297 QUIRK_HAS_DBGACK_BIT, 298 }; 299 300 static const struct s3c2410_wdt_variant drv_data_exynosautov9_cl0 = { 301 .mask_reset_reg = EXYNOS850_CLUSTER0_NONCPU_INT_EN, 302 .mask_bit = 2, 303 .mask_reset_inv = true, 304 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 305 .rst_stat_bit = EXYNOSAUTOV9_CLUSTER0_WDTRESET_BIT, 306 .cnt_en_reg = EXYNOS850_CLUSTER0_NONCPU_OUT, 307 .cnt_en_bit = 7, 308 .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | 309 QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN | 310 QUIRK_HAS_DBGACK_BIT | QUIRK_HAS_32BIT_CNT, 311 }; 312 313 static const struct s3c2410_wdt_variant drv_data_exynosautov9_cl1 = { 314 .mask_reset_reg = EXYNOSAUTOV9_CLUSTER1_NONCPU_INT_EN, 315 .mask_bit = 2, 316 .mask_reset_inv = true, 317 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 318 .rst_stat_bit = EXYNOSAUTOV9_CLUSTER1_WDTRESET_BIT, 319 .cnt_en_reg = EXYNOSAUTOV9_CLUSTER1_NONCPU_OUT, 320 .cnt_en_bit = 7, 321 .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | 322 QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN | 323 QUIRK_HAS_DBGACK_BIT | QUIRK_HAS_32BIT_CNT, 324 }; 325 326 static const struct s3c2410_wdt_variant drv_data_gs101_cl0 = { 327 .mask_reset_reg = GS_CLUSTER0_NONCPU_INT_EN, 328 .mask_bit = 2, 329 .mask_reset_inv = true, 330 .rst_stat_reg = GS_RST_STAT_REG_OFFSET, 331 .rst_stat_bit = 0, 332 .cnt_en_reg = GS_CLUSTER0_NONCPU_OUT, 333 .cnt_en_bit = 8, 334 .quirks = QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_MASK_RESET | 335 QUIRK_HAS_PMU_CNT_EN | QUIRK_HAS_WTCLRINT_REG | 336 QUIRK_HAS_DBGACK_BIT, 337 }; 338 339 static const struct s3c2410_wdt_variant drv_data_gs101_cl1 = { 340 .mask_reset_reg = GS_CLUSTER1_NONCPU_INT_EN, 341 .mask_bit = 2, 342 .mask_reset_inv = true, 343 .rst_stat_reg = GS_RST_STAT_REG_OFFSET, 344 .rst_stat_bit = 1, 345 .cnt_en_reg = GS_CLUSTER1_NONCPU_OUT, 346 .cnt_en_bit = 7, 347 .quirks = QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_MASK_RESET | 348 QUIRK_HAS_PMU_CNT_EN | QUIRK_HAS_WTCLRINT_REG | 349 QUIRK_HAS_DBGACK_BIT, 350 }; 351 352 static const struct s3c2410_wdt_variant drv_data_exynosautov920_cl0 = { 353 .mask_reset_reg = EXYNOSAUTOV920_CLUSTER0_NONCPU_INT_EN, 354 .mask_bit = 2, 355 .mask_reset_inv = true, 356 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 357 .rst_stat_bit = EXYNOSAUTOV920_CLUSTER0_WDTRESET_BIT, 358 .cnt_en_reg = EXYNOSAUTOV920_CLUSTER0_NONCPU_OUT, 359 .cnt_en_bit = 8, 360 .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | 361 QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN | 362 QUIRK_HAS_DBGACK_BIT | QUIRK_HAS_32BIT_CNT, 363 }; 364 365 static const struct s3c2410_wdt_variant drv_data_exynosautov920_cl1 = { 366 .mask_reset_reg = EXYNOSAUTOV920_CLUSTER1_NONCPU_INT_EN, 367 .mask_bit = 2, 368 .mask_reset_inv = true, 369 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 370 .rst_stat_bit = EXYNOSAUTOV920_CLUSTER1_WDTRESET_BIT, 371 .cnt_en_reg = EXYNOSAUTOV920_CLUSTER1_NONCPU_OUT, 372 .cnt_en_bit = 8, 373 .quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET | 374 QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN | 375 QUIRK_HAS_DBGACK_BIT | QUIRK_HAS_32BIT_CNT, 376 }; 377 378 static const struct of_device_id s3c2410_wdt_match[] = { 379 { .compatible = "google,gs101-wdt", 380 .data = &drv_data_gs101_cl0 }, 381 { .compatible = "samsung,s3c2410-wdt", 382 .data = &drv_data_s3c2410 }, 383 { .compatible = "samsung,s3c6410-wdt", 384 .data = &drv_data_s3c6410 }, 385 { .compatible = "samsung,exynos5250-wdt", 386 .data = &drv_data_exynos5250 }, 387 { .compatible = "samsung,exynos5420-wdt", 388 .data = &drv_data_exynos5420 }, 389 { .compatible = "samsung,exynos7-wdt", 390 .data = &drv_data_exynos7 }, 391 { .compatible = "samsung,exynos850-wdt", 392 .data = &drv_data_exynos850_cl0 }, 393 { .compatible = "samsung,exynos990-wdt", 394 .data = &drv_data_exynos990_cl0 }, 395 { .compatible = "samsung,exynosautov9-wdt", 396 .data = &drv_data_exynosautov9_cl0 }, 397 { .compatible = "samsung,exynosautov920-wdt", 398 .data = &drv_data_exynosautov920_cl0 }, 399 {}, 400 }; 401 MODULE_DEVICE_TABLE(of, s3c2410_wdt_match); 402 #endif 403 404 static const struct platform_device_id s3c2410_wdt_ids[] = { 405 { 406 .name = "s3c2410-wdt", 407 .driver_data = (unsigned long)&drv_data_s3c2410, 408 }, 409 {} 410 }; 411 MODULE_DEVICE_TABLE(platform, s3c2410_wdt_ids); 412 413 /* functions */ 414 415 static inline unsigned long s3c2410wdt_get_freq(struct s3c2410_wdt *wdt) 416 { 417 return clk_get_rate(wdt->src_clk ? wdt->src_clk : wdt->bus_clk); 418 } 419 420 static inline unsigned int s3c2410wdt_max_timeout(struct s3c2410_wdt *wdt) 421 { 422 const unsigned long freq = s3c2410wdt_get_freq(wdt); 423 const u64 n_max = (u64)(S3C2410_WTCON_PRESCALE_MAX + 1) * 424 S3C2410_WTCON_MAXDIV * wdt->max_cnt; 425 u64 t_max = div64_ul(n_max, freq); 426 427 if (t_max > UINT_MAX) 428 t_max = UINT_MAX; 429 430 return t_max; 431 } 432 433 static int s3c2410wdt_disable_wdt_reset(struct s3c2410_wdt *wdt, bool mask) 434 { 435 const u32 mask_val = BIT(wdt->drv_data->mask_bit); 436 const u32 val = mask ? mask_val : 0; 437 int ret; 438 439 ret = regmap_update_bits(wdt->pmureg, wdt->drv_data->disable_reg, 440 mask_val, val); 441 if (ret < 0) 442 dev_err(wdt->dev, "failed to update reg(%d)\n", ret); 443 444 return ret; 445 } 446 447 static int s3c2410wdt_mask_wdt_reset(struct s3c2410_wdt *wdt, bool mask) 448 { 449 const u32 mask_val = BIT(wdt->drv_data->mask_bit); 450 const bool val_inv = wdt->drv_data->mask_reset_inv; 451 const u32 val = (mask ^ val_inv) ? mask_val : 0; 452 int ret; 453 454 ret = regmap_update_bits(wdt->pmureg, wdt->drv_data->mask_reset_reg, 455 mask_val, val); 456 if (ret < 0) 457 dev_err(wdt->dev, "failed to update reg(%d)\n", ret); 458 459 return ret; 460 } 461 462 static int s3c2410wdt_enable_counter(struct s3c2410_wdt *wdt, bool en) 463 { 464 const u32 mask_val = BIT(wdt->drv_data->cnt_en_bit); 465 const u32 val = en ? mask_val : 0; 466 int ret; 467 468 ret = regmap_update_bits(wdt->pmureg, wdt->drv_data->cnt_en_reg, 469 mask_val, val); 470 if (ret < 0) 471 dev_err(wdt->dev, "failed to update reg(%d)\n", ret); 472 473 return ret; 474 } 475 476 static int s3c2410wdt_enable(struct s3c2410_wdt *wdt, bool en) 477 { 478 int ret; 479 480 if (wdt->drv_data->quirks & QUIRK_HAS_PMU_AUTO_DISABLE) { 481 ret = s3c2410wdt_disable_wdt_reset(wdt, !en); 482 if (ret < 0) 483 return ret; 484 } 485 486 if (wdt->drv_data->quirks & QUIRK_HAS_PMU_MASK_RESET) { 487 ret = s3c2410wdt_mask_wdt_reset(wdt, !en); 488 if (ret < 0) 489 return ret; 490 } 491 492 if (wdt->drv_data->quirks & QUIRK_HAS_PMU_CNT_EN) { 493 ret = s3c2410wdt_enable_counter(wdt, en); 494 if (ret < 0) 495 return ret; 496 } 497 498 return 0; 499 } 500 501 /* Disable watchdog outputs if CPU is in debug mode */ 502 static void s3c2410wdt_mask_dbgack(struct s3c2410_wdt *wdt) 503 { 504 unsigned long wtcon; 505 506 if (!(wdt->drv_data->quirks & QUIRK_HAS_DBGACK_BIT)) 507 return; 508 509 wtcon = readl(wdt->reg_base + S3C2410_WTCON); 510 wtcon |= S3C2410_WTCON_DBGACK_MASK; 511 writel(wtcon, wdt->reg_base + S3C2410_WTCON); 512 } 513 514 static int s3c2410wdt_keepalive(struct watchdog_device *wdd) 515 { 516 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); 517 unsigned long flags; 518 519 spin_lock_irqsave(&wdt->lock, flags); 520 writel(wdt->count, wdt->reg_base + S3C2410_WTCNT); 521 spin_unlock_irqrestore(&wdt->lock, flags); 522 523 return 0; 524 } 525 526 static void __s3c2410wdt_stop(struct s3c2410_wdt *wdt) 527 { 528 unsigned long wtcon; 529 530 wtcon = readl(wdt->reg_base + S3C2410_WTCON); 531 wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN); 532 writel(wtcon, wdt->reg_base + S3C2410_WTCON); 533 } 534 535 static int s3c2410wdt_stop(struct watchdog_device *wdd) 536 { 537 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); 538 unsigned long flags; 539 540 spin_lock_irqsave(&wdt->lock, flags); 541 __s3c2410wdt_stop(wdt); 542 spin_unlock_irqrestore(&wdt->lock, flags); 543 544 return 0; 545 } 546 547 static int s3c2410wdt_start(struct watchdog_device *wdd) 548 { 549 unsigned long wtcon; 550 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); 551 unsigned long flags; 552 553 spin_lock_irqsave(&wdt->lock, flags); 554 555 __s3c2410wdt_stop(wdt); 556 557 wtcon = readl(wdt->reg_base + S3C2410_WTCON); 558 wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128; 559 560 if (soft_noboot) { 561 wtcon |= S3C2410_WTCON_INTEN; 562 wtcon &= ~S3C2410_WTCON_RSTEN; 563 } else { 564 wtcon &= ~S3C2410_WTCON_INTEN; 565 wtcon |= S3C2410_WTCON_RSTEN; 566 } 567 568 dev_dbg(wdt->dev, "Starting watchdog: count=0x%08x, wtcon=%08lx\n", 569 wdt->count, wtcon); 570 571 writel(wdt->count, wdt->reg_base + S3C2410_WTDAT); 572 writel(wdt->count, wdt->reg_base + S3C2410_WTCNT); 573 writel(wtcon, wdt->reg_base + S3C2410_WTCON); 574 spin_unlock_irqrestore(&wdt->lock, flags); 575 576 return 0; 577 } 578 579 static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, 580 unsigned int timeout) 581 { 582 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); 583 unsigned long freq = s3c2410wdt_get_freq(wdt); 584 unsigned long count; 585 unsigned int divisor = 1; 586 unsigned long wtcon; 587 588 if (timeout < 1) 589 return -EINVAL; 590 591 freq = DIV_ROUND_UP(freq, 128); 592 count = timeout * freq; 593 594 dev_dbg(wdt->dev, "Heartbeat: count=%lu, timeout=%d, freq=%lu\n", 595 count, timeout, freq); 596 597 /* if the count is bigger than the watchdog register, 598 then work out what we need to do (and if) we can 599 actually make this value 600 */ 601 602 if (count > wdt->max_cnt) { 603 divisor = DIV_ROUND_UP(count, wdt->max_cnt); 604 605 if (divisor > S3C2410_WTCON_PRESCALE_MAX + 1) { 606 dev_err(wdt->dev, "timeout %d too big\n", timeout); 607 return -EINVAL; 608 } 609 } 610 611 dev_dbg(wdt->dev, "Heartbeat: timeout=%d, divisor=%d, count=%lu (%08lx)\n", 612 timeout, divisor, count, DIV_ROUND_UP(count, divisor)); 613 614 count = DIV_ROUND_UP(count, divisor); 615 wdt->count = count; 616 617 /* update the pre-scaler */ 618 wtcon = readl(wdt->reg_base + S3C2410_WTCON); 619 wtcon &= ~S3C2410_WTCON_PRESCALE_MASK; 620 wtcon |= S3C2410_WTCON_PRESCALE(divisor-1); 621 622 writel(count, wdt->reg_base + S3C2410_WTDAT); 623 writel(wtcon, wdt->reg_base + S3C2410_WTCON); 624 625 wdd->timeout = (count * divisor) / freq; 626 627 return 0; 628 } 629 630 static int s3c2410wdt_restart(struct watchdog_device *wdd, unsigned long action, 631 void *data) 632 { 633 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); 634 void __iomem *wdt_base = wdt->reg_base; 635 636 /* disable watchdog, to be safe */ 637 writel(0, wdt_base + S3C2410_WTCON); 638 639 /* put initial values into count and data */ 640 writel(0x80, wdt_base + S3C2410_WTCNT); 641 writel(0x80, wdt_base + S3C2410_WTDAT); 642 643 /* set the watchdog to go and reset... */ 644 writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV16 | 645 S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x20), 646 wdt_base + S3C2410_WTCON); 647 648 /* wait for reset to assert... */ 649 mdelay(500); 650 651 return 0; 652 } 653 654 #define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE) 655 656 static const struct watchdog_info s3c2410_wdt_ident = { 657 .options = OPTIONS, 658 .firmware_version = 0, 659 .identity = "S3C2410 Watchdog", 660 }; 661 662 static const struct watchdog_ops s3c2410wdt_ops = { 663 .owner = THIS_MODULE, 664 .start = s3c2410wdt_start, 665 .stop = s3c2410wdt_stop, 666 .ping = s3c2410wdt_keepalive, 667 .set_timeout = s3c2410wdt_set_heartbeat, 668 .restart = s3c2410wdt_restart, 669 }; 670 671 static const struct watchdog_device s3c2410_wdd = { 672 .info = &s3c2410_wdt_ident, 673 .ops = &s3c2410wdt_ops, 674 .timeout = S3C2410_WATCHDOG_DEFAULT_TIME, 675 }; 676 677 /* interrupt handler code */ 678 679 static irqreturn_t s3c2410wdt_irq(int irqno, void *param) 680 { 681 struct s3c2410_wdt *wdt = platform_get_drvdata(param); 682 683 dev_info(wdt->dev, "watchdog timer expired (irq)\n"); 684 685 s3c2410wdt_keepalive(&wdt->wdt_device); 686 687 if (wdt->drv_data->quirks & QUIRK_HAS_WTCLRINT_REG) 688 writel(0x1, wdt->reg_base + S3C2410_WTCLRINT); 689 690 return IRQ_HANDLED; 691 } 692 693 static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt) 694 { 695 unsigned int rst_stat; 696 int ret; 697 698 if (!(wdt->drv_data->quirks & QUIRK_HAS_PMU_RST_STAT)) 699 return 0; 700 701 ret = regmap_read(wdt->pmureg, wdt->drv_data->rst_stat_reg, &rst_stat); 702 if (ret) 703 dev_warn(wdt->dev, "Couldn't get RST_STAT register\n"); 704 else if (rst_stat & BIT(wdt->drv_data->rst_stat_bit)) 705 return WDIOF_CARDRESET; 706 707 return 0; 708 } 709 710 static inline int 711 s3c2410_get_wdt_drv_data(struct platform_device *pdev, struct s3c2410_wdt *wdt) 712 { 713 const struct s3c2410_wdt_variant *variant; 714 struct device *dev = &pdev->dev; 715 716 variant = of_device_get_match_data(dev); 717 if (!variant) { 718 /* Device matched by platform_device_id */ 719 variant = (struct s3c2410_wdt_variant *) 720 platform_get_device_id(pdev)->driver_data; 721 } 722 723 #ifdef CONFIG_OF 724 /* Choose Exynos850/ExynosAutov9 driver data w.r.t. cluster index */ 725 if (variant == &drv_data_exynos850_cl0 || 726 variant == &drv_data_exynosautov9_cl0 || 727 variant == &drv_data_gs101_cl0 || 728 variant == &drv_data_exynosautov920_cl0 || 729 variant == &drv_data_exynos990_cl0) { 730 u32 index; 731 int err; 732 733 err = of_property_read_u32(dev->of_node, 734 "samsung,cluster-index", &index); 735 if (err) 736 return dev_err_probe(dev, -EINVAL, "failed to get cluster index\n"); 737 738 switch (index) { 739 case 0: 740 break; 741 case 1: 742 if (variant == &drv_data_exynos850_cl0) 743 variant = &drv_data_exynos850_cl1; 744 else if (variant == &drv_data_exynosautov9_cl0) 745 variant = &drv_data_exynosautov9_cl1; 746 else if (variant == &drv_data_gs101_cl0) 747 variant = &drv_data_gs101_cl1; 748 else if (variant == &drv_data_exynosautov920_cl0) 749 variant = &drv_data_exynosautov920_cl1; 750 break; 751 case 2: 752 if (variant == &drv_data_exynos990_cl0) 753 variant = &drv_data_exynos990_cl2; 754 break; 755 default: 756 return dev_err_probe(dev, -EINVAL, "wrong cluster index: %u\n", index); 757 } 758 } 759 #endif 760 761 wdt->drv_data = variant; 762 return 0; 763 } 764 765 static void s3c2410wdt_wdt_disable_action(void *data) 766 { 767 s3c2410wdt_enable(data, false); 768 } 769 770 static int s3c2410wdt_probe(struct platform_device *pdev) 771 { 772 struct device *dev = &pdev->dev; 773 struct s3c2410_wdt *wdt; 774 unsigned int wtcon; 775 int wdt_irq; 776 int ret; 777 778 wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); 779 if (!wdt) 780 return -ENOMEM; 781 782 wdt->dev = dev; 783 spin_lock_init(&wdt->lock); 784 wdt->wdt_device = s3c2410_wdd; 785 786 ret = s3c2410_get_wdt_drv_data(pdev, wdt); 787 if (ret) 788 return ret; 789 790 if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) { 791 wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node, 792 "samsung,syscon-phandle"); 793 if (IS_ERR(wdt->pmureg)) 794 return dev_err_probe(dev, PTR_ERR(wdt->pmureg), 795 "syscon regmap lookup failed.\n"); 796 } 797 798 wdt_irq = platform_get_irq(pdev, 0); 799 if (wdt_irq < 0) 800 return wdt_irq; 801 802 /* get the memory region for the watchdog timer */ 803 wdt->reg_base = devm_platform_ioremap_resource(pdev, 0); 804 if (IS_ERR(wdt->reg_base)) 805 return PTR_ERR(wdt->reg_base); 806 807 wdt->bus_clk = devm_clk_get_enabled(dev, "watchdog"); 808 if (IS_ERR(wdt->bus_clk)) 809 return dev_err_probe(dev, PTR_ERR(wdt->bus_clk), "failed to get bus clock\n"); 810 811 /* 812 * "watchdog_src" clock is optional; if it's not present -- just skip it 813 * and use "watchdog" clock as both bus and source clock. 814 */ 815 wdt->src_clk = devm_clk_get_optional_enabled(dev, "watchdog_src"); 816 if (IS_ERR(wdt->src_clk)) 817 return dev_err_probe(dev, PTR_ERR(wdt->src_clk), "failed to get source clock\n"); 818 819 if (wdt->drv_data->quirks & QUIRK_HAS_32BIT_CNT) 820 wdt->max_cnt = S3C2410_WTCNT_MAXCNT_32; 821 else 822 wdt->max_cnt = S3C2410_WTCNT_MAXCNT_16; 823 824 wdt->wdt_device.min_timeout = 1; 825 wdt->wdt_device.max_timeout = s3c2410wdt_max_timeout(wdt); 826 827 watchdog_set_drvdata(&wdt->wdt_device, wdt); 828 829 /* see if we can actually set the requested timer margin, and if 830 * not, try the default value */ 831 832 watchdog_init_timeout(&wdt->wdt_device, tmr_margin, dev); 833 ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device, 834 wdt->wdt_device.timeout); 835 if (ret) { 836 ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device, 837 S3C2410_WATCHDOG_DEFAULT_TIME); 838 if (ret == 0) 839 dev_warn(dev, "tmr_margin value out of range, default %d used\n", 840 S3C2410_WATCHDOG_DEFAULT_TIME); 841 else 842 return dev_err_probe(dev, ret, "failed to use default timeout\n"); 843 } 844 845 ret = devm_request_irq(dev, wdt_irq, s3c2410wdt_irq, 0, 846 pdev->name, pdev); 847 if (ret != 0) 848 return dev_err_probe(dev, ret, "failed to install irq (%d)\n", ret); 849 850 watchdog_set_nowayout(&wdt->wdt_device, nowayout); 851 watchdog_set_restart_priority(&wdt->wdt_device, 128); 852 853 wdt->wdt_device.bootstatus = s3c2410wdt_get_bootstatus(wdt); 854 wdt->wdt_device.parent = dev; 855 856 s3c2410wdt_mask_dbgack(wdt); 857 858 /* 859 * If "tmr_atboot" param is non-zero, start the watchdog right now. Also 860 * set WDOG_HW_RUNNING bit, so that watchdog core can kick the watchdog. 861 * 862 * If we're not enabling the watchdog, then ensure it is disabled if it 863 * has been left running from the bootloader or other source. 864 */ 865 if (tmr_atboot) { 866 dev_info(dev, "starting watchdog timer\n"); 867 s3c2410wdt_start(&wdt->wdt_device); 868 set_bit(WDOG_HW_RUNNING, &wdt->wdt_device.status); 869 } else { 870 s3c2410wdt_stop(&wdt->wdt_device); 871 } 872 873 ret = devm_watchdog_register_device(dev, &wdt->wdt_device); 874 if (ret) 875 return ret; 876 877 ret = s3c2410wdt_enable(wdt, true); 878 if (ret < 0) 879 return ret; 880 881 ret = devm_add_action_or_reset(dev, s3c2410wdt_wdt_disable_action, wdt); 882 if (ret) 883 return ret; 884 885 platform_set_drvdata(pdev, wdt); 886 887 /* print out a statement of readiness */ 888 889 wtcon = readl(wdt->reg_base + S3C2410_WTCON); 890 891 dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n", 892 (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in", 893 (wtcon & S3C2410_WTCON_RSTEN) ? "en" : "dis", 894 (wtcon & S3C2410_WTCON_INTEN) ? "en" : "dis"); 895 896 return 0; 897 } 898 899 static void s3c2410wdt_shutdown(struct platform_device *dev) 900 { 901 struct s3c2410_wdt *wdt = platform_get_drvdata(dev); 902 903 s3c2410wdt_enable(wdt, false); 904 s3c2410wdt_stop(&wdt->wdt_device); 905 } 906 907 static int s3c2410wdt_suspend(struct device *dev) 908 { 909 int ret; 910 struct s3c2410_wdt *wdt = dev_get_drvdata(dev); 911 912 /* Save watchdog state, and turn it off. */ 913 wdt->wtcon_save = readl(wdt->reg_base + S3C2410_WTCON); 914 wdt->wtdat_save = readl(wdt->reg_base + S3C2410_WTDAT); 915 916 ret = s3c2410wdt_enable(wdt, false); 917 if (ret < 0) 918 return ret; 919 920 /* Note that WTCNT doesn't need to be saved. */ 921 s3c2410wdt_stop(&wdt->wdt_device); 922 923 return 0; 924 } 925 926 static int s3c2410wdt_resume(struct device *dev) 927 { 928 int ret; 929 struct s3c2410_wdt *wdt = dev_get_drvdata(dev); 930 931 /* Restore watchdog state. */ 932 writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTDAT); 933 writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTCNT);/* Reset count */ 934 writel(wdt->wtcon_save, wdt->reg_base + S3C2410_WTCON); 935 936 ret = s3c2410wdt_enable(wdt, true); 937 if (ret < 0) 938 return ret; 939 940 dev_info(dev, "watchdog %sabled\n", 941 (wdt->wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); 942 943 return 0; 944 } 945 946 static DEFINE_SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops, 947 s3c2410wdt_suspend, s3c2410wdt_resume); 948 949 static struct platform_driver s3c2410wdt_driver = { 950 .probe = s3c2410wdt_probe, 951 .shutdown = s3c2410wdt_shutdown, 952 .id_table = s3c2410_wdt_ids, 953 .driver = { 954 .name = "s3c2410-wdt", 955 .pm = pm_sleep_ptr(&s3c2410wdt_pm_ops), 956 .of_match_table = of_match_ptr(s3c2410_wdt_match), 957 }, 958 }; 959 960 module_platform_driver(s3c2410wdt_driver); 961 962 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, Dimitry Andric <dimitry.andric@tomtom.com>"); 963 MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver"); 964 MODULE_LICENSE("GPL"); 965