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