blob: 65fd2384f125404e92005df0898a7c40260816cf [file] [log] [blame]
Qiang Zhao3af19942019-05-07 03:16:09 +00001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Watchdog driver for SP805 on some Layerscape SoC
4 *
5 * Copyright 2019 NXP
6 */
7
8#include <asm/io.h>
9#include <common.h>
Rayagonda Kokatanurf0799902020-04-06 13:29:52 +053010#include <clk.h>
Qiang Zhao3af19942019-05-07 03:16:09 +000011#include <dm/device.h>
12#include <dm/fdtaddr.h>
13#include <dm/read.h>
14#include <linux/bitops.h>
15#include <watchdog.h>
16#include <wdt.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070017#include <linux/err.h>
Qiang Zhao3af19942019-05-07 03:16:09 +000018
19#define WDTLOAD 0x000
20#define WDTCONTROL 0x008
21#define WDTINTCLR 0x00C
22#define WDTLOCK 0xC00
23
24#define TIME_OUT_MIN_MSECS 1
25#define TIME_OUT_MAX_MSECS 120000
26#define SYS_FSL_WDT_CLK_DIV 16
27#define INT_ENABLE BIT(0)
28#define RESET_ENABLE BIT(1)
29#define DISABLE 0
30#define UNLOCK 0x1ACCE551
31#define LOCK 0x00000001
32#define INT_MASK BIT(0)
33
34DECLARE_GLOBAL_DATA_PTR;
35
36struct sp805_wdt_priv {
37 void __iomem *reg;
Rayagonda Kokatanurf0799902020-04-06 13:29:52 +053038 unsigned long clk_rate;
Qiang Zhao3af19942019-05-07 03:16:09 +000039};
40
41static int sp805_wdt_reset(struct udevice *dev)
42{
43 struct sp805_wdt_priv *priv = dev_get_priv(dev);
44
45 writel(UNLOCK, priv->reg + WDTLOCK);
46 writel(INT_MASK, priv->reg + WDTINTCLR);
47 writel(LOCK, priv->reg + WDTLOCK);
48 readl(priv->reg + WDTLOCK);
49
50 return 0;
51}
52
53static int sp805_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
54{
55 u32 load_value;
56 u32 load_time;
57 struct sp805_wdt_priv *priv = dev_get_priv(dev);
58
59 load_time = (u32)timeout;
60 if (timeout < TIME_OUT_MIN_MSECS)
61 load_time = TIME_OUT_MIN_MSECS;
62 else if (timeout > TIME_OUT_MAX_MSECS)
63 load_time = TIME_OUT_MAX_MSECS;
64 /* sp805 runs counter with given value twice, so when the max timeout is
65 * set 120s, the gd->bus_clk is less than 1145MHz, the load_value will
66 * not overflow.
67 */
Rayagonda Kokatanurf0799902020-04-06 13:29:52 +053068 if (gd->bus_clk) {
69 load_value = (gd->bus_clk) /
70 (2 * 1000 * SYS_FSL_WDT_CLK_DIV) * load_time;
71 } else {
72 /* platform provide clk */
73 load_value = (timeout / 2) * (priv->clk_rate / 1000);
74 }
Qiang Zhao3af19942019-05-07 03:16:09 +000075
76 writel(UNLOCK, priv->reg + WDTLOCK);
77 writel(load_value, priv->reg + WDTLOAD);
78 writel(INT_MASK, priv->reg + WDTINTCLR);
79 writel(INT_ENABLE | RESET_ENABLE, priv->reg + WDTCONTROL);
80 writel(LOCK, priv->reg + WDTLOCK);
81 readl(priv->reg + WDTLOCK);
82
83 return 0;
84}
85
86static int sp805_wdt_stop(struct udevice *dev)
87{
88 struct sp805_wdt_priv *priv = dev_get_priv(dev);
89
90 writel(UNLOCK, priv->reg + WDTLOCK);
91 writel(DISABLE, priv->reg + WDTCONTROL);
92 writel(LOCK, priv->reg + WDTLOCK);
93 readl(priv->reg + WDTLOCK);
94
95 return 0;
96}
97
Thomas Schaefer6345a342019-08-08 16:00:31 +080098static int sp805_wdt_expire_now(struct udevice *dev, ulong flags)
99{
100 sp805_wdt_start(dev, 0, flags);
101
102 return 0;
103}
104
Qiang Zhao3af19942019-05-07 03:16:09 +0000105static int sp805_wdt_probe(struct udevice *dev)
106{
Thomas Schaefer6345a342019-08-08 16:00:31 +0800107 debug("%s: Probing wdt%u (sp805-wdt)\n", __func__, dev->seq);
Qiang Zhao3af19942019-05-07 03:16:09 +0000108
109 return 0;
110}
111
112static int sp805_wdt_ofdata_to_platdata(struct udevice *dev)
113{
114 struct sp805_wdt_priv *priv = dev_get_priv(dev);
Rayagonda Kokatanurf0799902020-04-06 13:29:52 +0530115 struct clk clk;
Qiang Zhao3af19942019-05-07 03:16:09 +0000116
117 priv->reg = (void __iomem *)dev_read_addr(dev);
118 if (IS_ERR(priv->reg))
119 return PTR_ERR(priv->reg);
120
Rayagonda Kokatanurf0799902020-04-06 13:29:52 +0530121 if (!clk_get_by_index(dev, 0, &clk))
122 priv->clk_rate = clk_get_rate(&clk);
123
Qiang Zhao3af19942019-05-07 03:16:09 +0000124 return 0;
125}
126
127static const struct wdt_ops sp805_wdt_ops = {
128 .start = sp805_wdt_start,
129 .reset = sp805_wdt_reset,
130 .stop = sp805_wdt_stop,
Thomas Schaefer6345a342019-08-08 16:00:31 +0800131 .expire_now = sp805_wdt_expire_now,
Qiang Zhao3af19942019-05-07 03:16:09 +0000132};
133
134static const struct udevice_id sp805_wdt_ids[] = {
135 { .compatible = "arm,sp805-wdt" },
136 {}
137};
138
139U_BOOT_DRIVER(sp805_wdt) = {
140 .name = "sp805_wdt",
141 .id = UCLASS_WDT,
142 .of_match = sp805_wdt_ids,
143 .probe = sp805_wdt_probe,
144 .priv_auto_alloc_size = sizeof(struct sp805_wdt_priv),
145 .ofdata_to_platdata = sp805_wdt_ofdata_to_platdata,
146 .ops = &sp805_wdt_ops,
147};