blob: 03585529bb636a763fcbd536646bbd453735d1bc [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
Simon Glass3ba929a2020-10-30 21:38:53 -06008#include <asm/global_data.h>
Zhao Qiangfb816fa2020-07-10 16:55:18 +08009#include <asm/io.h>
Zhao Qiangfb816fa2020-07-10 16:55:18 +080010#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();
Zhao Qiangab5959e2020-11-25 12:55:47 +080064 writel(clk / (2 * 1000) * timeout,
Zhao Qiangfb816fa2020-07-10 16:55:18 +080065 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{
Simon Glass75e534b2020-12-16 21:20:07 -070091 debug("%s: Probing wdt%u (sbsa-gwdt)\n", __func__, dev_seq(dev));
Zhao Qiangfb816fa2020-07-10 16:55:18 +080092
93 return 0;
94}
95
Simon Glassaad29ae2020-12-03 16:55:21 -070096static int sbsa_gwdt_of_to_plat(struct udevice *dev)
Zhao Qiangfb816fa2020-07-10 16:55:18 +080097{
98 struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
99
Johan Jonker5ff88122023-03-13 01:31:49 +0100100 priv->reg_control = dev_read_addr_index_ptr(dev, 0);
101 if (!priv->reg_control)
102 return -EINVAL;
Zhao Qiangfb816fa2020-07-10 16:55:18 +0800103
Johan Jonker5ff88122023-03-13 01:31:49 +0100104 priv->reg_refresh = dev_read_addr_index_ptr(dev, 1);
105 if (!priv->reg_refresh)
106 return -EINVAL;
Zhao Qiangfb816fa2020-07-10 16:55:18 +0800107
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,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700128 .priv_auto = sizeof(struct sbsa_gwdt_priv),
Simon Glassaad29ae2020-12-03 16:55:21 -0700129 .of_to_plat = sbsa_gwdt_of_to_plat,
Zhao Qiangfb816fa2020-07-10 16:55:18 +0800130 .ops = &sbsa_gwdt_ops,
131};