blob: 2eae431ba6c13c872e9c7744cfe7203dfd47309a [file] [log] [blame]
Zhao Qiangfb816fa2020-07-10 16:55:18 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Watchdog driver for SBSA
4 *
5 * Copyright 2020 NXP
6 */
7
8#include <asm/io.h>
9#include <common.h>
10#include <dm/device.h>
11#include <dm/fdtaddr.h>
12#include <dm/read.h>
13#include <linux/bitops.h>
14#include <linux/err.h>
15#include <watchdog.h>
16#include <wdt.h>
17
18DECLARE_GLOBAL_DATA_PTR;
19
20/* SBSA Generic Watchdog register definitions */
21/* refresh frame */
22#define SBSA_GWDT_WRR 0x000
23
24/* control frame */
25#define SBSA_GWDT_WCS 0x000
26#define SBSA_GWDT_WOR 0x008
27#define SBSA_GWDT_WCV 0x010
28
29/* refresh/control frame */
30#define SBSA_GWDT_W_IIDR 0xfcc
31#define SBSA_GWDT_IDR 0xfd0
32
33/* Watchdog Control and Status Register */
34#define SBSA_GWDT_WCS_EN BIT(0)
35#define SBSA_GWDT_WCS_WS0 BIT(1)
36#define SBSA_GWDT_WCS_WS1 BIT(2)
37
38struct sbsa_gwdt_priv {
39 void __iomem *reg_refresh;
40 void __iomem *reg_control;
41};
42
43static int sbsa_gwdt_reset(struct udevice *dev)
44{
45 struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
46
47 writel(0, priv->reg_refresh + SBSA_GWDT_WRR);
48
49 return 0;
50}
51
52static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags)
53{
54 struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
55 u32 clk;
56
57 /*
58 * it work in the single stage mode in u-boot,
59 * The first signal (WS0) is ignored,
60 * the timeout is (WOR * 2), so the WOR should be configured
61 * to half value of timeout.
62 */
63 clk = get_tbclk();
64 writel(clk / 2 * timeout,
65 priv->reg_control + SBSA_GWDT_WOR);
66
67 /* writing WCS will cause an explicit watchdog refresh */
68 writel(SBSA_GWDT_WCS_EN, priv->reg_control + SBSA_GWDT_WCS);
69
70 return 0;
71}
72
73static int sbsa_gwdt_stop(struct udevice *dev)
74{
75 struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
76
77 writel(0, priv->reg_control + SBSA_GWDT_WCS);
78
79 return 0;
80}
81
82static int sbsa_gwdt_expire_now(struct udevice *dev, ulong flags)
83{
84 sbsa_gwdt_start(dev, 0, flags);
85
86 return 0;
87}
88
89static int sbsa_gwdt_probe(struct udevice *dev)
90{
91 debug("%s: Probing wdt%u (sbsa-gwdt)\n", __func__, dev->seq);
92
93 return 0;
94}
95
96static int sbsa_gwdt_ofdata_to_platdata(struct udevice *dev)
97{
98 struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
99
100 priv->reg_control = (void __iomem *)dev_read_addr_index(dev, 0);
101 if (IS_ERR(priv->reg_control))
102 return PTR_ERR(priv->reg_control);
103
104 priv->reg_refresh = (void __iomem *)dev_read_addr_index(dev, 1);
105 if (IS_ERR(priv->reg_refresh))
106 return PTR_ERR(priv->reg_refresh);
107
108 return 0;
109}
110
111static const struct wdt_ops sbsa_gwdt_ops = {
112 .start = sbsa_gwdt_start,
113 .reset = sbsa_gwdt_reset,
114 .stop = sbsa_gwdt_stop,
115 .expire_now = sbsa_gwdt_expire_now,
116};
117
118static const struct udevice_id sbsa_gwdt_ids[] = {
119 { .compatible = "arm,sbsa-gwdt" },
120 {}
121};
122
123U_BOOT_DRIVER(sbsa_gwdt) = {
124 .name = "sbsa_gwdt",
125 .id = UCLASS_WDT,
126 .of_match = sbsa_gwdt_ids,
127 .probe = sbsa_gwdt_probe,
128 .priv_auto_alloc_size = sizeof(struct sbsa_gwdt_priv),
129 .ofdata_to_platdata = sbsa_gwdt_ofdata_to_platdata,
130 .ops = &sbsa_gwdt_ops,
131};