Source
15
15
DECLARE_GLOBAL_DATA_PTR;
16
16
17
17
struct a37xx_wdt {
18
18
void __iomem *sel_reg;
19
19
void __iomem *reg;
20
20
ulong clk_rate;
21
21
u64 timeout;
22
22
};
23
23
24
24
/*
25
-
* We use Counter 1 for watchdog timer, because so does Marvell's Linux by
26
-
* default.
25
+
* We use Counter 1 as watchdog timer, and Counter 0 for re-triggering Counter 1
27
26
*/
28
27
29
-
#define CNTR_CTRL 0x10
28
+
#define CNTR_CTRL(id) ((id) * 0x10)
30
29
#define CNTR_CTRL_ENABLE 0x0001
31
30
#define CNTR_CTRL_ACTIVE 0x0002
32
31
#define CNTR_CTRL_MODE_MASK 0x000c
33
32
#define CNTR_CTRL_MODE_ONESHOT 0x0000
33
+
#define CNTR_CTRL_MODE_HWSIG 0x000c
34
+
#define CNTR_CTRL_TRIG_SRC_MASK 0x00f0
35
+
#define CNTR_CTRL_TRIG_SRC_PREV_CNTR 0x0050
34
36
#define CNTR_CTRL_PRESCALE_MASK 0xff00
35
37
#define CNTR_CTRL_PRESCALE_MIN 2
36
38
#define CNTR_CTRL_PRESCALE_SHIFT 8
37
39
38
-
#define CNTR_COUNT_LOW 0x14
39
-
#define CNTR_COUNT_HIGH 0x18
40
+
#define CNTR_COUNT_LOW(id) (CNTR_CTRL(id) + 0x4)
41
+
#define CNTR_COUNT_HIGH(id) (CNTR_CTRL(id) + 0x8)
40
42
41
-
static void set_counter_value(struct a37xx_wdt *priv)
43
+
static void set_counter_value(struct a37xx_wdt *priv, int id, u64 val)
42
44
{
43
-
writel(priv->timeout & 0xffffffff, priv->reg + CNTR_COUNT_LOW);
44
-
writel(priv->timeout >> 32, priv->reg + CNTR_COUNT_HIGH);
45
+
writel(val & 0xffffffff, priv->reg + CNTR_COUNT_LOW(id));
46
+
writel(val >> 32, priv->reg + CNTR_COUNT_HIGH(id));
45
47
}
46
48
47
-
static void a37xx_wdt_enable(struct a37xx_wdt *priv)
49
+
static void counter_enable(struct a37xx_wdt *priv, int id)
48
50
{
49
-
u32 reg = readl(priv->reg + CNTR_CTRL);
51
+
setbits_le32(priv->reg + CNTR_CTRL(id), CNTR_CTRL_ENABLE);
52
+
}
50
53
51
-
reg |= CNTR_CTRL_ENABLE;
52
-
writel(reg, priv->reg + CNTR_CTRL);
54
+
static void counter_disable(struct a37xx_wdt *priv, int id)
55
+
{
56
+
clrbits_le32(priv->reg + CNTR_CTRL(id), CNTR_CTRL_ENABLE);
53
57
}
54
58
55
-
static void a37xx_wdt_disable(struct a37xx_wdt *priv)
59
+
static int init_counter(struct a37xx_wdt *priv, int id, u32 mode, u32 trig_src)
56
60
{
57
-
u32 reg = readl(priv->reg + CNTR_CTRL);
61
+
u32 reg;
62
+
63
+
reg = readl(priv->reg + CNTR_CTRL(id));
64
+
if (reg & CNTR_CTRL_ACTIVE)
65
+
return -EBUSY;
66
+
67
+
reg &= ~(CNTR_CTRL_MODE_MASK | CNTR_CTRL_PRESCALE_MASK |
68
+
CNTR_CTRL_TRIG_SRC_MASK);
69
+
70
+
/* set mode */
71
+
reg |= mode;
72
+
73
+
/* set prescaler to the min value */
74
+
reg |= CNTR_CTRL_PRESCALE_MIN << CNTR_CTRL_PRESCALE_SHIFT;
75
+
76
+
/* set trigger source */
77
+
reg |= trig_src;
58
78
59
-
reg &= ~CNTR_CTRL_ENABLE;
60
-
writel(reg, priv->reg + CNTR_CTRL);
79
+
writel(reg, priv->reg + CNTR_CTRL(id));
80
+
81
+
return 0;
61
82
}
62
83
63
84
static int a37xx_wdt_reset(struct udevice *dev)
64
85
{
65
86
struct a37xx_wdt *priv = dev_get_priv(dev);
66
87
67
88
if (!priv->timeout)
68
89
return -EINVAL;
69
90
70
-
a37xx_wdt_disable(priv);
71
-
set_counter_value(priv);
72
-
a37xx_wdt_enable(priv);
91
+
/* counter 1 is retriggered by forcing end count on counter 0 */
92
+
counter_disable(priv, 0);
93
+
counter_enable(priv, 0);
73
94
74
95
return 0;
75
96
}
76
97
77
98
static int a37xx_wdt_expire_now(struct udevice *dev, ulong flags)
78
99
{
79
100
struct a37xx_wdt *priv = dev_get_priv(dev);
80
101
81
-
a37xx_wdt_disable(priv);
82
-
priv->timeout = 0;
83
-
set_counter_value(priv);
84
-
a37xx_wdt_enable(priv);
102
+
/* first we set timeout to 0 */
103
+
counter_disable(priv, 1);
104
+
set_counter_value(priv, 1, 0);
105
+
counter_enable(priv, 1);
106
+
107
+
/* and then we start counter 1 by forcing end count on counter 0 */
108
+
counter_disable(priv, 0);
109
+
counter_enable(priv, 0);
85
110
86
111
return 0;
87
112
}
88
113
89
114
static int a37xx_wdt_start(struct udevice *dev, u64 ms, ulong flags)
90
115
{
91
116
struct a37xx_wdt *priv = dev_get_priv(dev);
92
-
u32 reg;
93
-
94
-
reg = readl(priv->reg + CNTR_CTRL);
95
-
96
-
if (reg & CNTR_CTRL_ACTIVE)
97
-
return -EBUSY;
117
+
int err;
98
118
99
-
/* set mode */
100
-
reg = (reg & ~CNTR_CTRL_MODE_MASK) | CNTR_CTRL_MODE_ONESHOT;
119
+
err = init_counter(priv, 0, CNTR_CTRL_MODE_ONESHOT, 0);
120
+
if (err < 0)
121
+
return err;
101
122
102
-
/* set prescaler to the min value */
103
-
reg &= ~CNTR_CTRL_PRESCALE_MASK;
104
-
reg |= CNTR_CTRL_PRESCALE_MIN << CNTR_CTRL_PRESCALE_SHIFT;
123
+
err = init_counter(priv, 1, CNTR_CTRL_MODE_HWSIG,
124
+
CNTR_CTRL_TRIG_SRC_PREV_CNTR);
125
+
if (err < 0)
126
+
return err;
105
127
106
128
priv->timeout = ms * priv->clk_rate / 1000 / CNTR_CTRL_PRESCALE_MIN;
107
129
108
-
writel(reg, priv->reg + CNTR_CTRL);
130
+
set_counter_value(priv, 0, 0);
131
+
set_counter_value(priv, 1, priv->timeout);
132
+
counter_enable(priv, 1);
109
133
110
-
set_counter_value(priv);
111
-
a37xx_wdt_enable(priv);
134
+
/* we have to force end count on counter 0 to start counter 1 */
135
+
counter_enable(priv, 0);
112
136
113
137
return 0;
114
138
}
115
139
116
140
static int a37xx_wdt_stop(struct udevice *dev)
117
141
{
118
142
struct a37xx_wdt *priv = dev_get_priv(dev);
119
143
120
-
a37xx_wdt_disable(priv);
144
+
counter_disable(priv, 1);
145
+
counter_disable(priv, 0);
146
+
writel(0, priv->sel_reg);
121
147
122
148
return 0;
123
149
}
124
150
125
151
static int a37xx_wdt_probe(struct udevice *dev)
126
152
{
127
153
struct a37xx_wdt *priv = dev_get_priv(dev);
128
154
fdt_addr_t addr;
129
155
130
156
addr = dev_read_addr_index(dev, 0);
132
158
goto err;
133
159
priv->sel_reg = (void __iomem *)addr;
134
160
135
161
addr = dev_read_addr_index(dev, 1);
136
162
if (addr == FDT_ADDR_T_NONE)
137
163
goto err;
138
164
priv->reg = (void __iomem *)addr;
139
165
140
166
priv->clk_rate = (ulong)get_ref_clk() * 1000000;
141
167
142
-
a37xx_wdt_disable(priv);
143
-
144
168
/*
145
-
* We use timer 1 as watchdog timer (because Marvell's Linux uses that
146
-
* timer as default), therefore we only set bit TIMER1_IS_WCHDOG_TIMER.
169
+
* We use counter 1 as watchdog timer, therefore we only set bit
170
+
* TIMER1_IS_WCHDOG_TIMER. Counter 0 is only used to force re-trigger on
171
+
* counter 1.
147
172
*/
148
173
writel(1 << 1, priv->sel_reg);
149
174
150
175
return 0;
151
176
err:
152
177
dev_err(dev, "no io address\n");
153
178
return -ENODEV;
154
179
}
155
180
156
181
static const struct wdt_ops a37xx_wdt_ops = {