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