/src/u-boot/drivers/watchdog/ftwdt010_wdt.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0+ |
2 | | /* |
3 | | * Watchdog driver for the FTWDT010 Watch Dog Driver |
4 | | * |
5 | | * (c) Copyright 2004 Faraday Technology Corp. (www.faraday-tech.com) |
6 | | * Based on sa1100_wdt.c by Oleg Drokin <green@crimea.edu> |
7 | | * Based on SoftDog driver by Alan Cox <alan@redhat.com> |
8 | | * |
9 | | * Copyright (C) 2011 Andes Technology Corporation |
10 | | * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com> |
11 | | * |
12 | | * 27/11/2004 Initial release, Faraday. |
13 | | * 12/01/2011 Port to u-boot, Macpaul Lin. |
14 | | * 22/08/2022 Port to DM |
15 | | */ |
16 | | |
17 | | #include <dm.h> |
18 | | #include <wdt.h> |
19 | | #include <log.h> |
20 | | #include <asm/io.h> |
21 | | #include <faraday/ftwdt010_wdt.h> |
22 | | |
23 | | struct ftwdt010_wdt_priv { |
24 | | struct ftwdt010_wdt __iomem *regs; |
25 | | }; |
26 | | |
27 | | static int ftwdt010_wdt_reset(struct udevice *dev) |
28 | 0 | { |
29 | 0 | struct ftwdt010_wdt_priv *priv = dev_get_priv(dev); |
30 | 0 | struct ftwdt010_wdt *wd = priv->regs; |
31 | |
|
32 | 0 | debug("Reset WDT..\n"); |
33 | | |
34 | | /* clear control register */ |
35 | 0 | writel(0, &wd->wdcr); |
36 | | |
37 | | /* Write Magic number */ |
38 | 0 | writel(FTWDT010_WDRESTART_MAGIC, &wd->wdrestart); |
39 | | |
40 | | /* Enable WDT */ |
41 | 0 | writel(FTWDT010_WDCR_RST | FTWDT010_WDCR_ENABLE, &wd->wdcr); |
42 | |
|
43 | 0 | return 0; |
44 | 0 | } |
45 | | |
46 | | /* |
47 | | * Set the watchdog time interval and start the timer. |
48 | | * Counter is 32 bit. |
49 | | */ |
50 | | static int ftwdt010_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) |
51 | 0 | { |
52 | 0 | struct ftwdt010_wdt_priv *priv = dev_get_priv(dev); |
53 | 0 | struct ftwdt010_wdt *wd = priv->regs; |
54 | 0 | unsigned int reg; |
55 | |
|
56 | 0 | debug("Activating WDT %llu ms\n", timeout_ms); |
57 | | |
58 | | /* Check if disabled */ |
59 | 0 | if (readl(&wd->wdcr) & ~FTWDT010_WDCR_ENABLE) { |
60 | 0 | printf("sorry, watchdog is disabled\n"); |
61 | 0 | return -1; |
62 | 0 | } |
63 | | |
64 | | /* |
65 | | * In a 66MHz system, |
66 | | * if you set WDLOAD as 0x03EF1480 (66000000) |
67 | | * the reset timer is 1 second. |
68 | | */ |
69 | 0 | reg = FTWDT010_WDLOAD(timeout_ms * FTWDT010_TIMEOUT_FACTOR); |
70 | |
|
71 | 0 | writel(reg, &wd->wdload); |
72 | |
|
73 | 0 | return ftwdt010_wdt_reset(dev); |
74 | 0 | } |
75 | | |
76 | | static int ftwdt010_wdt_stop(struct udevice *dev) |
77 | 0 | { |
78 | 0 | struct ftwdt010_wdt_priv *priv = dev_get_priv(dev); |
79 | 0 | struct ftwdt010_wdt *wd = priv->regs; |
80 | |
|
81 | 0 | debug("Deactivating WDT..\n"); |
82 | | |
83 | | /* |
84 | | * It was defined with CONFIG_WATCHDOG_NOWAYOUT in Linux |
85 | | * |
86 | | * Shut off the timer. |
87 | | * Lock it in if it's a module and we defined ...NOWAYOUT |
88 | | */ |
89 | 0 | writel(0, &wd->wdcr); |
90 | 0 | return 0; |
91 | 0 | } |
92 | | |
93 | | static int ftwdt010_wdt_expire_now(struct udevice *dev, ulong flags) |
94 | 0 | { |
95 | 0 | struct ftwdt010_wdt_priv *priv = dev_get_priv(dev); |
96 | 0 | struct ftwdt010_wdt *wd = priv->regs; |
97 | |
|
98 | 0 | debug("Expiring WDT..\n"); |
99 | 0 | writel(FTWDT010_WDLOAD(0), &wd->wdload); |
100 | 0 | return ftwdt010_wdt_reset(dev); |
101 | 0 | } |
102 | | |
103 | | static int ftwdt010_wdt_probe(struct udevice *dev) |
104 | 0 | { |
105 | 0 | struct ftwdt010_wdt_priv *priv = dev_get_priv(dev); |
106 | |
|
107 | 0 | priv->regs = dev_read_addr_ptr(dev); |
108 | 0 | if (!priv->regs) |
109 | 0 | return -EINVAL; |
110 | | |
111 | 0 | return 0; |
112 | 0 | } |
113 | | |
114 | | static const struct wdt_ops ftwdt010_wdt_ops = { |
115 | | .start = ftwdt010_wdt_start, |
116 | | .reset = ftwdt010_wdt_reset, |
117 | | .stop = ftwdt010_wdt_stop, |
118 | | .expire_now = ftwdt010_wdt_expire_now, |
119 | | }; |
120 | | |
121 | | static const struct udevice_id ftwdt010_wdt_ids[] = { |
122 | | { .compatible = "faraday,ftwdt010" }, |
123 | | {} |
124 | | }; |
125 | | |
126 | | U_BOOT_DRIVER(ftwdt010_wdt) = { |
127 | | .name = "ftwdt010_wdt", |
128 | | .id = UCLASS_WDT, |
129 | | .of_match = ftwdt010_wdt_ids, |
130 | | .ops = &ftwdt010_wdt_ops, |
131 | | .probe = ftwdt010_wdt_probe, |
132 | | .priv_auto = sizeof(struct ftwdt010_wdt_priv), |
133 | | }; |