1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * [origin: Linux kernel drivers/watchdog/at91sam9_wdt.c] 4 * 5 * Watchdog driver for AT91SAM9x processors. 6 * 7 * Copyright (C) 2008 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> 8 * Copyright (C) 2008 Renaud CERRATO r.cerrato@til-technologies.fr 9 */ 10 11 /* 12 * The Watchdog Timer Mode Register can be only written to once. If the 13 * timeout need to be set from U-Boot, be sure that the bootstrap doesn't 14 * write to this register. Inform Linux to it too 15 */ 16 17 #include <asm/io.h> 18 #include <asm/arch/at91_wdt.h> 19 #include <common.h> 20 #include <dm.h> 21 #include <errno.h> 22 #include <wdt.h> 23 24 DECLARE_GLOBAL_DATA_PTR; 25 26 /* 27 * AT91SAM9 watchdog runs a 12bit counter @ 256Hz, 28 * use this to convert a watchdog 29 * value from seconds. 30 */ 31 #define WDT_SEC2TICKS(s) (((s) << 8) - 1) 32 33 /* Hardware timeout in seconds */ 34 #define WDT_MAX_TIMEOUT 16 35 #define WDT_MIN_TIMEOUT 0 36 #define WDT_DEFAULT_TIMEOUT 2 37 38 struct at91_wdt_priv { 39 void __iomem *regs; 40 u32 regval; 41 u32 timeout; 42 }; 43 44 /* 45 * Set the watchdog time interval in 1/256Hz (write-once) 46 * Counter is 12 bit. 47 */ 48 static int at91_wdt_start(struct udevice *dev, u64 timeout_s, ulong flags) 49 { 50 struct at91_wdt_priv *priv = dev_get_priv(dev); 51 u32 timeout = WDT_SEC2TICKS(timeout_s); 52 53 if (timeout_s > WDT_MAX_TIMEOUT || timeout_s < WDT_MIN_TIMEOUT) 54 timeout = priv->timeout; 55 56 /* Check if disabled */ 57 if (readl(priv->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) { 58 printf("sorry, watchdog is disabled\n"); 59 return -1; 60 } 61 62 /* 63 * All counting occurs at SLOW_CLOCK / 128 = 256 Hz 64 * 65 * Since WDV is a 12-bit counter, the maximum period is 66 * 4096 / 256 = 16 seconds. 67 */ 68 69 priv->regval = AT91_WDT_MR_WDRSTEN /* causes watchdog reset */ 70 | AT91_WDT_MR_WDDBGHLT /* disabled in debug mode */ 71 | AT91_WDT_MR_WDD(0xfff) /* restart at any time */ 72 | AT91_WDT_MR_WDV(timeout); /* timer value */ 73 74 writel(priv->regval, priv->regs + AT91_WDT_MR); 75 76 return 0; 77 } 78 79 static int at91_wdt_stop(struct udevice *dev) 80 { 81 struct at91_wdt_priv *priv = dev_get_priv(dev); 82 83 /* Disable Watchdog Timer */ 84 priv->regval |= AT91_WDT_MR_WDDIS; 85 writel(priv->regval, priv->regs + AT91_WDT_MR); 86 87 return 0; 88 } 89 90 static int at91_wdt_reset(struct udevice *dev) 91 { 92 struct at91_wdt_priv *priv = dev_get_priv(dev); 93 94 writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, priv->regs + AT91_WDT_CR); 95 96 return 0; 97 } 98 99 static const struct wdt_ops at91_wdt_ops = { 100 .start = at91_wdt_start, 101 .stop = at91_wdt_stop, 102 .reset = at91_wdt_reset, 103 }; 104 105 static const struct udevice_id at91_wdt_ids[] = { 106 { .compatible = "atmel,at91sam9260-wdt" }, 107 {} 108 }; 109 110 static int at91_wdt_probe(struct udevice *dev) 111 { 112 struct at91_wdt_priv *priv = dev_get_priv(dev); 113 114 priv->regs = dev_remap_addr(dev); 115 if (!priv->regs) 116 return -EINVAL; 117 118 #ifdef CONFIG_AT91_HW_WDT_TIMEOUT 119 priv->timeout = dev_read_u32_default(dev, "timeout-sec", 120 WDT_DEFAULT_TIMEOUT); 121 debug("%s: timeout %d", __func__, priv->timeout); 122 #endif 123 124 debug("%s: Probing wdt%u\n", __func__, dev->seq); 125 126 return 0; 127 } 128 129 U_BOOT_DRIVER(at91_wdt) = { 130 .name = "at91_wdt", 131 .id = UCLASS_WDT, 132 .of_match = at91_wdt_ids, 133 .priv_auto_alloc_size = sizeof(struct at91_wdt_priv), 134 .ops = &at91_wdt_ops, 135 .probe = at91_wdt_probe, 136 }; 137