1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Watchdog driver for MediaTek SoCs 4 * 5 * Copyright (C) 2018 MediaTek Inc. 6 * Author: Ryder Lee <ryder.lee@mediatek.com> 7 */ 8 9 #include <common.h> 10 #include <dm.h> 11 #include <wdt.h> 12 #include <asm/io.h> 13 14 #define MTK_WDT_MODE 0x00 15 #define MTK_WDT_LENGTH 0x04 16 #define MTK_WDT_RESTART 0x08 17 #define MTK_WDT_STATUS 0x0c 18 #define MTK_WDT_INTERVAL 0x10 19 #define MTK_WDT_SWRST 0x14 20 #define MTK_WDT_REQ_MODE 0x30 21 #define MTK_WDT_DEBUG_CTL 0x40 22 23 #define WDT_MODE_KEY (0x22 << 24) 24 #define WDT_MODE_EN BIT(0) 25 #define WDT_MODE_EXTPOL BIT(1) 26 #define WDT_MODE_EXTEN BIT(2) 27 #define WDT_MODE_IRQ_EN BIT(3) 28 #define WDT_MODE_DUAL_EN BIT(6) 29 30 #define WDT_LENGTH_KEY 0x8 31 #define WDT_LENGTH_TIMEOUT(n) ((n) << 5) 32 33 #define WDT_RESTART_KEY 0x1971 34 #define WDT_SWRST_KEY 0x1209 35 36 struct mtk_wdt_priv { 37 void __iomem *base; 38 }; 39 40 static int mtk_wdt_reset(struct udevice *dev) 41 { 42 struct mtk_wdt_priv *priv = dev_get_priv(dev); 43 44 /* Reload watchdog duration */ 45 writel(WDT_RESTART_KEY, priv->base + MTK_WDT_RESTART); 46 47 return 0; 48 } 49 50 static int mtk_wdt_stop(struct udevice *dev) 51 { 52 struct mtk_wdt_priv *priv = dev_get_priv(dev); 53 54 clrsetbits_le32(priv->base + MTK_WDT_MODE, WDT_MODE_EN, WDT_MODE_KEY); 55 56 return 0; 57 } 58 59 static int mtk_wdt_expire_now(struct udevice *dev, ulong flags) 60 { 61 struct mtk_wdt_priv *priv = dev_get_priv(dev); 62 63 /* Kick watchdog to prevent counter == 0 */ 64 writel(WDT_RESTART_KEY, priv->base + MTK_WDT_RESTART); 65 66 /* Reset */ 67 writel(WDT_SWRST_KEY, priv->base + MTK_WDT_SWRST); 68 hang(); 69 70 return 0; 71 } 72 73 static void mtk_wdt_set_timeout(struct udevice *dev, unsigned int timeout) 74 { 75 struct mtk_wdt_priv *priv = dev_get_priv(dev); 76 77 /* 78 * One bit is the value of 512 ticks 79 * The clock has 32 KHz 80 */ 81 timeout = WDT_LENGTH_TIMEOUT(timeout << 6) | WDT_LENGTH_KEY; 82 writel(timeout, priv->base + MTK_WDT_LENGTH); 83 84 mtk_wdt_reset(dev); 85 } 86 87 static int mtk_wdt_start(struct udevice *dev, u64 timeout, ulong flags) 88 { 89 struct mtk_wdt_priv *priv = dev_get_priv(dev); 90 91 mtk_wdt_set_timeout(dev, timeout); 92 93 /* Enable watchdog reset signal */ 94 setbits_le32(priv->base + MTK_WDT_MODE, 95 WDT_MODE_EN | WDT_MODE_KEY | WDT_MODE_EXTEN); 96 97 return 0; 98 } 99 100 static int mtk_wdt_probe(struct udevice *dev) 101 { 102 struct mtk_wdt_priv *priv = dev_get_priv(dev); 103 104 priv->base = dev_read_addr_ptr(dev); 105 if (!priv->base) 106 return -ENOENT; 107 108 /* Clear status */ 109 clrsetbits_le32(priv->base + MTK_WDT_MODE, 110 WDT_MODE_IRQ_EN | WDT_MODE_EXTPOL, WDT_MODE_KEY); 111 112 return mtk_wdt_stop(dev); 113 } 114 115 static const struct wdt_ops mtk_wdt_ops = { 116 .start = mtk_wdt_start, 117 .reset = mtk_wdt_reset, 118 .stop = mtk_wdt_stop, 119 .expire_now = mtk_wdt_expire_now, 120 }; 121 122 static const struct udevice_id mtk_wdt_ids[] = { 123 { .compatible = "mediatek,wdt"}, 124 {} 125 }; 126 127 U_BOOT_DRIVER(mtk_wdt) = { 128 .name = "mtk_wdt", 129 .id = UCLASS_WDT, 130 .of_match = mtk_wdt_ids, 131 .priv_auto_alloc_size = sizeof(struct mtk_wdt_priv), 132 .probe = mtk_wdt_probe, 133 .ops = &mtk_wdt_ops, 134 .flags = DM_FLAG_PRE_RELOC, 135 }; 136