"Das U-Boot" Source Tree

watchdog: add watchdog driver for MediaTek MT7620 SoC

This patch adds watchdog support for the Mediatek MT7620 SoC

Reviewed-by: Stefan Roese <sr@denx.de>
Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>

authored by

Weijie Gao and committed by
Daniel Schwierzeck
bba4ec81 a9a3a3aa

+150
+7
drivers/watchdog/Kconfig
··· 134 134 help 135 135 Select this to enable mpc8xx watchdog timer 136 136 137 + config WDT_MT7620 138 + bool "MediaTek MT7620 watchdog timer support" 139 + depends on WDT && SOC_MT7620 140 + help 141 + Select this to enable watchdog timer on MediaTek MT7620 and earlier 142 + SoC chips. 143 + 137 144 config WDT_MT7621 138 145 bool "MediaTek MT7621 watchdog timer support" 139 146 depends on WDT && SOC_MT7628
+1
drivers/watchdog/Makefile
··· 25 25 obj-$(CONFIG_WDT_ORION) += orion_wdt.o 26 26 obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o 27 27 obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o 28 + obj-$(CONFIG_WDT_MT7620) += mt7620_wdt.o 28 29 obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o 29 30 obj-$(CONFIG_WDT_MTK) += mtk_wdt.o 30 31 obj-$(CONFIG_WDT_OCTEONTX) += octeontx_wdt.o
+142
drivers/watchdog/mt7620_wdt.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2020 MediaTek Inc. 4 + * 5 + * Author: Weijie Gao <weijie.gao@mediatek.com> 6 + * 7 + * Watchdog timer for MT7620 and earlier SoCs 8 + */ 9 + 10 + #include <div64.h> 11 + #include <dm.h> 12 + #include <reset.h> 13 + #include <wdt.h> 14 + #include <linux/bitops.h> 15 + #include <linux/io.h> 16 + 17 + struct mt7620_wdt { 18 + void __iomem *regs; 19 + u64 timeout; 20 + }; 21 + 22 + #define TIMER_FREQ 40000000 23 + #define TIMER_MASK 0xffff 24 + #define TIMER_PRESCALE 65536 25 + 26 + #define TIMER_LOAD 0x00 27 + #define TIMER_CTL 0x08 28 + 29 + #define TIMER_ENABLE BIT(7) 30 + #define TIMER_MODE_SHIFT 4 31 + #define TIMER_MODE_WDT 3 32 + #define TIMER_PRESCALE_SHIFT 0 33 + #define TIMER_PRESCALE_65536 15 34 + 35 + static void mt7620_wdt_ping(struct mt7620_wdt *priv) 36 + { 37 + u64 val; 38 + 39 + val = (TIMER_FREQ / TIMER_PRESCALE) * priv->timeout; 40 + do_div(val, 1000); 41 + 42 + if (val > TIMER_MASK) 43 + val = TIMER_MASK; 44 + 45 + writel(val, priv->regs + TIMER_LOAD); 46 + } 47 + 48 + static int mt7620_wdt_start(struct udevice *dev, u64 ms, ulong flags) 49 + { 50 + struct mt7620_wdt *priv = dev_get_priv(dev); 51 + 52 + priv->timeout = ms; 53 + mt7620_wdt_ping(priv); 54 + 55 + writel(TIMER_ENABLE | (TIMER_MODE_WDT << TIMER_MODE_SHIFT) | 56 + (TIMER_PRESCALE_65536 << TIMER_PRESCALE_SHIFT), 57 + priv->regs + TIMER_CTL); 58 + 59 + return 0; 60 + } 61 + 62 + static int mt7620_wdt_stop(struct udevice *dev) 63 + { 64 + struct mt7620_wdt *priv = dev_get_priv(dev); 65 + 66 + mt7620_wdt_ping(priv); 67 + 68 + clrbits_32(priv->regs + TIMER_CTL, TIMER_ENABLE); 69 + 70 + return 0; 71 + } 72 + 73 + static int mt7620_wdt_reset(struct udevice *dev) 74 + { 75 + struct mt7620_wdt *priv = dev_get_priv(dev); 76 + 77 + mt7620_wdt_ping(priv); 78 + 79 + return 0; 80 + } 81 + 82 + static int mt7620_wdt_expire_now(struct udevice *dev, ulong flags) 83 + { 84 + struct mt7620_wdt *priv = dev_get_priv(dev); 85 + 86 + mt7620_wdt_start(dev, 1, flags); 87 + 88 + /* 89 + * 0 will disable the timer directly, a positive number must be used 90 + * instead. Since the timer is a countdown timer, 1 (tick) is used. 91 + * 92 + * For a timer with input clock = 40MHz, 1 timer tick is short 93 + * enough to trigger a timeout immediately. 94 + * 95 + * Restore prescale to 1, and load timer with 1 to trigger timeout. 96 + */ 97 + writel(TIMER_ENABLE | (TIMER_MODE_WDT << TIMER_MODE_SHIFT), 98 + priv->regs + TIMER_CTL); 99 + writel(1, priv->regs + TIMER_LOAD); 100 + 101 + return 0; 102 + } 103 + 104 + static int mt7620_wdt_probe(struct udevice *dev) 105 + { 106 + struct mt7620_wdt *priv = dev_get_priv(dev); 107 + struct reset_ctl reset_wdt; 108 + int ret; 109 + 110 + ret = reset_get_by_index(dev, 0, &reset_wdt); 111 + if (!ret) 112 + reset_deassert(&reset_wdt); 113 + 114 + priv->regs = dev_remap_addr(dev); 115 + if (!priv->regs) 116 + return -EINVAL; 117 + 118 + mt7620_wdt_stop(dev); 119 + 120 + return 0; 121 + } 122 + 123 + static const struct wdt_ops mt7620_wdt_ops = { 124 + .start = mt7620_wdt_start, 125 + .reset = mt7620_wdt_reset, 126 + .stop = mt7620_wdt_stop, 127 + .expire_now = mt7620_wdt_expire_now, 128 + }; 129 + 130 + static const struct udevice_id mt7620_wdt_ids[] = { 131 + { .compatible = "mediatek,mt7620-wdt" }, 132 + {} 133 + }; 134 + 135 + U_BOOT_DRIVER(mt7620_wdt) = { 136 + .name = "mt7620_wdt", 137 + .id = UCLASS_WDT, 138 + .of_match = mt7620_wdt_ids, 139 + .probe = mt7620_wdt_probe, 140 + .priv_auto = sizeof(struct mt7620_wdt), 141 + .ops = &mt7620_wdt_ops, 142 + };