Skip to content

Commit 23c788c

Browse files
Zhen Leidlezcano
authored andcommitted
clocksource/drivers/sp804: Support non-standard register offset
The ARM SP804 supports a maximum of 32-bit counter, but Hisilicon extends it to 64-bit. That means, the registers: TimerXload, TimerXValue and TimerXBGLoad are 64bits, all other registers are the same as those in the SP804. The driver code can be completely reused except that the register offset is different. Currently, we get a timer register address by: add the constant register offset to the timer base address. e.g. "base + TIMER_CTRL". It can not be dynamically adjusted at run time. So create a new structure "sp804_timer" to record the original registers offset, and create a new structure "sp804_clkevt" to record the calculated registers address. So the "base + TIMER_CTRL" is changed to "clkevt->ctrl", this will faster than "base + timer->ctrl". For example: struct sp804_timer arm_sp804_timer = { .ctrl = TIMER_CTRL, }; struct sp804_clkevt clkevt; clkevt.ctrl = base + arm_sp804_timer.ctrl. - writel(0, base + TIMER_CTRL); + writel(0, clkevt->ctrl); Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> Link: https://lore.kernel.org/r/20200918132237.3552-7-thunder.leizhen@huawei.com
1 parent e69aae7 commit 23c788c

2 files changed

Lines changed: 108 additions & 26 deletions

File tree

drivers/clocksource/timer-sp.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*
1111
* Every SP804 contains two identical timers.
1212
*/
13+
#define NR_TIMERS 2
1314
#define TIMER_1_BASE 0x00
1415
#define TIMER_2_BASE 0x20
1516

@@ -29,3 +30,28 @@
2930
#define TIMER_RIS 0x10 /* CVR ro */
3031
#define TIMER_MIS 0x14 /* CVR ro */
3132
#define TIMER_BGLOAD 0x18 /* CVR rw */
33+
34+
struct sp804_timer {
35+
int load;
36+
int value;
37+
int ctrl;
38+
int intclr;
39+
int ris;
40+
int mis;
41+
int bgload;
42+
int timer_base[NR_TIMERS];
43+
int width;
44+
};
45+
46+
struct sp804_clkevt {
47+
void __iomem *base;
48+
void __iomem *load;
49+
void __iomem *value;
50+
void __iomem *ctrl;
51+
void __iomem *intclr;
52+
void __iomem *ris;
53+
void __iomem *mis;
54+
void __iomem *bgload;
55+
unsigned long reload;
56+
int width;
57+
};

drivers/clocksource/timer-sp804.c

Lines changed: 82 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@
2020

2121
#include "timer-sp.h"
2222

23+
struct sp804_timer __initdata arm_sp804_timer = {
24+
.load = TIMER_LOAD,
25+
.value = TIMER_VALUE,
26+
.ctrl = TIMER_CTRL,
27+
.intclr = TIMER_INTCLR,
28+
.timer_base = {TIMER_1_BASE, TIMER_2_BASE},
29+
.width = 32,
30+
};
31+
32+
static struct sp804_clkevt sp804_clkevt[NR_TIMERS];
33+
2334
static long __init sp804_get_clock_rate(struct clk *clk, const char *name)
2435
{
2536
long rate;
@@ -58,11 +69,26 @@ static long __init sp804_get_clock_rate(struct clk *clk, const char *name)
5869
return rate;
5970
}
6071

61-
static void __iomem *sched_clock_base;
72+
static struct sp804_clkevt * __init sp804_clkevt_get(void __iomem *base)
73+
{
74+
int i;
75+
76+
for (i = 0; i < NR_TIMERS; i++) {
77+
if (sp804_clkevt[i].base == base)
78+
return &sp804_clkevt[i];
79+
}
80+
81+
/* It's impossible to reach here */
82+
WARN_ON(1);
83+
84+
return NULL;
85+
}
86+
87+
static struct sp804_clkevt *sched_clkevt;
6288

6389
static u64 notrace sp804_read(void)
6490
{
65-
return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
91+
return ~readl_relaxed(sched_clkevt->value);
6692
}
6793

6894
int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
@@ -71,31 +97,33 @@ int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
7197
int use_sched_clock)
7298
{
7399
long rate;
100+
struct sp804_clkevt *clkevt;
74101

75102
rate = sp804_get_clock_rate(clk, name);
76103
if (rate < 0)
77104
return -EINVAL;
78105

79-
writel(0, base + TIMER_CTRL);
80-
writel(0xffffffff, base + TIMER_LOAD);
81-
writel(0xffffffff, base + TIMER_VALUE);
106+
clkevt = sp804_clkevt_get(base);
107+
108+
writel(0, clkevt->ctrl);
109+
writel(0xffffffff, clkevt->load);
110+
writel(0xffffffff, clkevt->value);
82111
writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
83-
base + TIMER_CTRL);
112+
clkevt->ctrl);
84113

85-
clocksource_mmio_init(base + TIMER_VALUE, name,
114+
clocksource_mmio_init(clkevt->value, name,
86115
rate, 200, 32, clocksource_mmio_readl_down);
87116

88117
if (use_sched_clock) {
89-
sched_clock_base = base;
118+
sched_clkevt = clkevt;
90119
sched_clock_register(sp804_read, 32, rate);
91120
}
92121

93122
return 0;
94123
}
95124

96125

97-
static void __iomem *clkevt_base;
98-
static unsigned long clkevt_reload;
126+
static struct sp804_clkevt *common_clkevt;
99127

100128
/*
101129
* IRQ handler for the timer
@@ -105,7 +133,7 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
105133
struct clock_event_device *evt = dev_id;
106134

107135
/* clear the interrupt */
108-
writel(1, clkevt_base + TIMER_INTCLR);
136+
writel(1, common_clkevt->intclr);
109137

110138
evt->event_handler(evt);
111139

@@ -114,7 +142,7 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
114142

115143
static inline void timer_shutdown(struct clock_event_device *evt)
116144
{
117-
writel(0, clkevt_base + TIMER_CTRL);
145+
writel(0, common_clkevt->ctrl);
118146
}
119147

120148
static int sp804_shutdown(struct clock_event_device *evt)
@@ -129,8 +157,8 @@ static int sp804_set_periodic(struct clock_event_device *evt)
129157
TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
130158

131159
timer_shutdown(evt);
132-
writel(clkevt_reload, clkevt_base + TIMER_LOAD);
133-
writel(ctrl, clkevt_base + TIMER_CTRL);
160+
writel(common_clkevt->reload, common_clkevt->load);
161+
writel(ctrl, common_clkevt->ctrl);
134162
return 0;
135163
}
136164

@@ -140,8 +168,8 @@ static int sp804_set_next_event(unsigned long next,
140168
unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
141169
TIMER_CTRL_ONESHOT | TIMER_CTRL_ENABLE;
142170

143-
writel(next, clkevt_base + TIMER_LOAD);
144-
writel(ctrl, clkevt_base + TIMER_CTRL);
171+
writel(next, common_clkevt->load);
172+
writel(ctrl, common_clkevt->ctrl);
145173

146174
return 0;
147175
}
@@ -168,13 +196,13 @@ int __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
168196
if (rate < 0)
169197
return -EINVAL;
170198

171-
clkevt_base = base;
172-
clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ);
199+
common_clkevt = sp804_clkevt_get(base);
200+
common_clkevt->reload = DIV_ROUND_CLOSEST(rate, HZ);
173201
evt->name = name;
174202
evt->irq = irq;
175203
evt->cpumask = cpu_possible_mask;
176204

177-
writel(0, base + TIMER_CTRL);
205+
writel(0, common_clkevt->ctrl);
178206

179207
if (request_irq(irq, sp804_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
180208
"timer", &sp804_clockevent))
@@ -184,7 +212,26 @@ int __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
184212
return 0;
185213
}
186214

187-
static int __init sp804_of_init(struct device_node *np)
215+
static void __init sp804_clkevt_init(struct sp804_timer *timer, void __iomem *base)
216+
{
217+
int i;
218+
219+
for (i = 0; i < NR_TIMERS; i++) {
220+
void __iomem *timer_base;
221+
struct sp804_clkevt *clkevt;
222+
223+
timer_base = base + timer->timer_base[i];
224+
clkevt = &sp804_clkevt[i];
225+
clkevt->base = timer_base;
226+
clkevt->load = timer_base + timer->load;
227+
clkevt->value = timer_base + timer->value;
228+
clkevt->ctrl = timer_base + timer->ctrl;
229+
clkevt->intclr = timer_base + timer->intclr;
230+
clkevt->width = timer->width;
231+
}
232+
}
233+
234+
static int __init sp804_of_init(struct device_node *np, struct sp804_timer *timer)
188235
{
189236
static bool initialized = false;
190237
void __iomem *base;
@@ -199,12 +246,12 @@ static int __init sp804_of_init(struct device_node *np)
199246
if (!base)
200247
return -ENXIO;
201248

202-
timer1_base = base;
203-
timer2_base = base + TIMER_2_BASE;
249+
timer1_base = base + timer->timer_base[0];
250+
timer2_base = base + timer->timer_base[1];
204251

205252
/* Ensure timers are disabled */
206-
writel(0, timer1_base + TIMER_CTRL);
207-
writel(0, timer2_base + TIMER_CTRL);
253+
writel(0, timer1_base + timer->ctrl);
254+
writel(0, timer2_base + timer->ctrl);
208255

209256
if (initialized || !of_device_is_available(np)) {
210257
ret = -EINVAL;
@@ -230,6 +277,8 @@ static int __init sp804_of_init(struct device_node *np)
230277
if (irq <= 0)
231278
goto err;
232279

280+
sp804_clkevt_init(timer, base);
281+
233282
of_property_read_u32(np, "arm,sp804-has-irq", &irq_num);
234283
if (irq_num == 2) {
235284

@@ -259,7 +308,12 @@ static int __init sp804_of_init(struct device_node *np)
259308
iounmap(base);
260309
return ret;
261310
}
262-
TIMER_OF_DECLARE(sp804, "arm,sp804", sp804_of_init);
311+
312+
static int __init arm_sp804_of_init(struct device_node *np)
313+
{
314+
return sp804_of_init(np, &arm_sp804_timer);
315+
}
316+
TIMER_OF_DECLARE(sp804, "arm,sp804", arm_sp804_of_init);
263317

264318
static int __init integrator_cp_of_init(struct device_node *np)
265319
{
@@ -282,11 +336,13 @@ static int __init integrator_cp_of_init(struct device_node *np)
282336
}
283337

284338
/* Ensure timer is disabled */
285-
writel(0, base + TIMER_CTRL);
339+
writel(0, base + arm_sp804_timer.ctrl);
286340

287341
if (init_count == 2 || !of_device_is_available(np))
288342
goto err;
289343

344+
sp804_clkevt_init(&arm_sp804_timer, base);
345+
290346
if (!init_count) {
291347
ret = sp804_clocksource_and_sched_clock_init(base,
292348
name, clk, 0);

0 commit comments

Comments
 (0)