1 // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2 /*
3  * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
4  */
5 
6 #define LOG_CATEGORY UCLASS_WDT
7 
8 #include <common.h>
9 #include <clk.h>
10 #include <dm.h>
11 #include <log.h>
12 #include <syscon.h>
13 #include <wdt.h>
14 #include <asm/io.h>
15 #include <dm/device_compat.h>
16 #include <linux/bitops.h>
17 #include <linux/iopoll.h>
18 
19 /* IWDG registers */
20 #define IWDG_KR		0x00	/* Key register */
21 #define IWDG_PR		0x04	/* Prescaler Register */
22 #define IWDG_RLR	0x08	/* ReLoad Register */
23 #define IWDG_SR		0x0C	/* Status Register */
24 
25 /* IWDG_KR register bit mask */
26 #define KR_KEY_RELOAD	0xAAAA	/* Reload counter enable */
27 #define KR_KEY_ENABLE	0xCCCC	/* Peripheral enable */
28 #define KR_KEY_EWA	0x5555	/* Write access enable */
29 
30 /* IWDG_PR register bit values */
31 #define PR_256		0x06	/* Prescaler set to 256 */
32 
33 /* IWDG_RLR register values */
34 #define RLR_MAX		0xFFF	/* Max value supported by reload register */
35 
36 /* IWDG_SR register bit values */
37 #define SR_PVU		BIT(0)	/* Watchdog prescaler value update */
38 #define SR_RVU		BIT(1)	/* Watchdog counter reload value update */
39 
40 struct stm32mp_wdt_priv {
41 	fdt_addr_t base;		/* registers addr in physical memory */
42 	unsigned long wdt_clk_rate;	/* Watchdog dedicated clock rate */
43 };
44 
stm32mp_wdt_reset(struct udevice * dev)45 static int stm32mp_wdt_reset(struct udevice *dev)
46 {
47 	struct stm32mp_wdt_priv *priv = dev_get_priv(dev);
48 
49 	writel(KR_KEY_RELOAD, priv->base + IWDG_KR);
50 
51 	return 0;
52 }
53 
stm32mp_wdt_start(struct udevice * dev,u64 timeout_ms,ulong flags)54 static int stm32mp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
55 {
56 	struct stm32mp_wdt_priv *priv = dev_get_priv(dev);
57 	int reload;
58 	u32 val;
59 	int ret;
60 
61 	/* Prescaler fixed to 256 */
62 	reload = timeout_ms * priv->wdt_clk_rate / 256;
63 	if (reload > RLR_MAX + 1)
64 		/* Force to max watchdog counter reload value */
65 		reload = RLR_MAX + 1;
66 	else if (!reload)
67 		/* Force to min watchdog counter reload value */
68 		reload = priv->wdt_clk_rate / 256;
69 
70 	/* Set prescaler & reload registers */
71 	writel(KR_KEY_EWA, priv->base + IWDG_KR);
72 	writel(PR_256, priv->base + IWDG_PR);
73 	writel(reload - 1, priv->base + IWDG_RLR);
74 
75 	/* Enable watchdog */
76 	writel(KR_KEY_ENABLE, priv->base + IWDG_KR);
77 
78 	/* Wait for the registers to be updated */
79 	ret = readl_poll_timeout(priv->base + IWDG_SR, val,
80 				 val & (SR_PVU | SR_RVU), CONFIG_SYS_HZ);
81 
82 	if (ret < 0) {
83 		dev_err(dev, "Updating IWDG registers timeout");
84 		return -ETIMEDOUT;
85 	}
86 
87 	return 0;
88 }
89 
stm32mp_wdt_probe(struct udevice * dev)90 static int stm32mp_wdt_probe(struct udevice *dev)
91 {
92 	struct stm32mp_wdt_priv *priv = dev_get_priv(dev);
93 	struct clk clk;
94 	int ret;
95 
96 	dev_dbg(dev, "IWDG init\n");
97 
98 	priv->base = dev_read_addr(dev);
99 	if (priv->base == FDT_ADDR_T_NONE)
100 		return -EINVAL;
101 
102 	/* Enable clock */
103 	ret = clk_get_by_name(dev, "pclk", &clk);
104 	if (ret)
105 		return ret;
106 
107 	ret = clk_enable(&clk);
108 	if (ret)
109 		return ret;
110 
111 	/* Get LSI clock */
112 	ret = clk_get_by_name(dev, "lsi", &clk);
113 	if (ret)
114 		return ret;
115 
116 	priv->wdt_clk_rate = clk_get_rate(&clk);
117 
118 	dev_dbg(dev, "IWDG init done\n");
119 
120 	return 0;
121 }
122 
123 static const struct wdt_ops stm32mp_wdt_ops = {
124 	.start = stm32mp_wdt_start,
125 	.reset = stm32mp_wdt_reset,
126 };
127 
128 static const struct udevice_id stm32mp_wdt_match[] = {
129 	{ .compatible = "st,stm32mp1-iwdg" },
130 	{ /* sentinel */ }
131 };
132 
133 U_BOOT_DRIVER(stm32mp_wdt) = {
134 	.name = "stm32mp-wdt",
135 	.id = UCLASS_WDT,
136 	.of_match = stm32mp_wdt_match,
137 	.priv_auto	= sizeof(struct stm32mp_wdt_priv),
138 	.probe = stm32mp_wdt_probe,
139 	.ops = &stm32mp_wdt_ops,
140 };
141