aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/moxart_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource/moxart_timer.c')
-rw-r--r--drivers/clocksource/moxart_timer.c193
1 files changed, 129 insertions, 64 deletions
diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c
index 841454417acd..2a8f4705c734 100644
--- a/drivers/clocksource/moxart_timer.c
+++ b/drivers/clocksource/moxart_timer.c
@@ -21,6 +21,7 @@
21#include <linux/io.h> 21#include <linux/io.h>
22#include <linux/clocksource.h> 22#include <linux/clocksource.h>
23#include <linux/bitops.h> 23#include <linux/bitops.h>
24#include <linux/slab.h>
24 25
25#define TIMER1_BASE 0x00 26#define TIMER1_BASE 0x00
26#define TIMER2_BASE 0x10 27#define TIMER2_BASE 0x10
@@ -36,75 +37,109 @@
36#define TIMER_INTR_MASK 0x38 37#define TIMER_INTR_MASK 0x38
37 38
38/* 39/*
39 * TIMER_CR flags: 40 * Moxart TIMER_CR flags:
40 * 41 *
41 * TIMEREG_CR_*_CLOCK 0: PCLK, 1: EXT1CLK 42 * MOXART_CR_*_CLOCK 0: PCLK, 1: EXT1CLK
42 * TIMEREG_CR_*_INT overflow interrupt enable bit 43 * MOXART_CR_*_INT overflow interrupt enable bit
43 */ 44 */
44#define TIMEREG_CR_1_ENABLE BIT(0) 45#define MOXART_CR_1_ENABLE BIT(0)
45#define TIMEREG_CR_1_CLOCK BIT(1) 46#define MOXART_CR_1_CLOCK BIT(1)
46#define TIMEREG_CR_1_INT BIT(2) 47#define MOXART_CR_1_INT BIT(2)
47#define TIMEREG_CR_2_ENABLE BIT(3) 48#define MOXART_CR_2_ENABLE BIT(3)
48#define TIMEREG_CR_2_CLOCK BIT(4) 49#define MOXART_CR_2_CLOCK BIT(4)
49#define TIMEREG_CR_2_INT BIT(5) 50#define MOXART_CR_2_INT BIT(5)
50#define TIMEREG_CR_3_ENABLE BIT(6) 51#define MOXART_CR_3_ENABLE BIT(6)
51#define TIMEREG_CR_3_CLOCK BIT(7) 52#define MOXART_CR_3_CLOCK BIT(7)
52#define TIMEREG_CR_3_INT BIT(8) 53#define MOXART_CR_3_INT BIT(8)
53#define TIMEREG_CR_COUNT_UP BIT(9) 54#define MOXART_CR_COUNT_UP BIT(9)
54 55
55#define TIMER1_ENABLE (TIMEREG_CR_2_ENABLE | TIMEREG_CR_1_ENABLE) 56#define MOXART_TIMER1_ENABLE (MOXART_CR_2_ENABLE | MOXART_CR_1_ENABLE)
56#define TIMER1_DISABLE (TIMEREG_CR_2_ENABLE) 57#define MOXART_TIMER1_DISABLE (MOXART_CR_2_ENABLE)
57 58
58static void __iomem *base; 59/*
59static unsigned int clock_count_per_tick; 60 * The ASpeed variant of the IP block has a different layout
61 * for the control register
62 */
63#define ASPEED_CR_1_ENABLE BIT(0)
64#define ASPEED_CR_1_CLOCK BIT(1)
65#define ASPEED_CR_1_INT BIT(2)
66#define ASPEED_CR_2_ENABLE BIT(4)
67#define ASPEED_CR_2_CLOCK BIT(5)
68#define ASPEED_CR_2_INT BIT(6)
69#define ASPEED_CR_3_ENABLE BIT(8)
70#define ASPEED_CR_3_CLOCK BIT(9)
71#define ASPEED_CR_3_INT BIT(10)
72
73#define ASPEED_TIMER1_ENABLE (ASPEED_CR_2_ENABLE | ASPEED_CR_1_ENABLE)
74#define ASPEED_TIMER1_DISABLE (ASPEED_CR_2_ENABLE)
75
76struct moxart_timer {
77 void __iomem *base;
78 unsigned int t1_disable_val;
79 unsigned int t1_enable_val;
80 unsigned int count_per_tick;
81 struct clock_event_device clkevt;
82};
83
84static inline struct moxart_timer *to_moxart(struct clock_event_device *evt)
85{
86 return container_of(evt, struct moxart_timer, clkevt);
87}
88
89static inline void moxart_disable(struct clock_event_device *evt)
90{
91 struct moxart_timer *timer = to_moxart(evt);
92
93 writel(timer->t1_disable_val, timer->base + TIMER_CR);
94}
95
96static inline void moxart_enable(struct clock_event_device *evt)
97{
98 struct moxart_timer *timer = to_moxart(evt);
99
100 writel(timer->t1_enable_val, timer->base + TIMER_CR);
101}
60 102
61static int moxart_shutdown(struct clock_event_device *evt) 103static int moxart_shutdown(struct clock_event_device *evt)
62{ 104{
63 writel(TIMER1_DISABLE, base + TIMER_CR); 105 moxart_disable(evt);
64 return 0; 106 return 0;
65} 107}
66 108
67static int moxart_set_oneshot(struct clock_event_device *evt) 109static int moxart_set_oneshot(struct clock_event_device *evt)
68{ 110{
69 writel(TIMER1_DISABLE, base + TIMER_CR); 111 moxart_disable(evt);
70 writel(~0, base + TIMER1_BASE + REG_LOAD); 112 writel(~0, to_moxart(evt)->base + TIMER1_BASE + REG_LOAD);
71 return 0; 113 return 0;
72} 114}
73 115
74static int moxart_set_periodic(struct clock_event_device *evt) 116static int moxart_set_periodic(struct clock_event_device *evt)
75{ 117{
76 writel(clock_count_per_tick, base + TIMER1_BASE + REG_LOAD); 118 struct moxart_timer *timer = to_moxart(evt);
77 writel(TIMER1_ENABLE, base + TIMER_CR); 119
120 moxart_disable(evt);
121 writel(timer->count_per_tick, timer->base + TIMER1_BASE + REG_LOAD);
122 writel(0, timer->base + TIMER1_BASE + REG_MATCH1);
123 moxart_enable(evt);
78 return 0; 124 return 0;
79} 125}
80 126
81static int moxart_clkevt_next_event(unsigned long cycles, 127static int moxart_clkevt_next_event(unsigned long cycles,
82 struct clock_event_device *unused) 128 struct clock_event_device *evt)
83{ 129{
130 struct moxart_timer *timer = to_moxart(evt);
84 u32 u; 131 u32 u;
85 132
86 writel(TIMER1_DISABLE, base + TIMER_CR); 133 moxart_disable(evt);
87 134
88 u = readl(base + TIMER1_BASE + REG_COUNT) - cycles; 135 u = readl(timer->base + TIMER1_BASE + REG_COUNT) - cycles;
89 writel(u, base + TIMER1_BASE + REG_MATCH1); 136 writel(u, timer->base + TIMER1_BASE + REG_MATCH1);
90 137
91 writel(TIMER1_ENABLE, base + TIMER_CR); 138 moxart_enable(evt);
92 139
93 return 0; 140 return 0;
94} 141}
95 142
96static struct clock_event_device moxart_clockevent = {
97 .name = "moxart_timer",
98 .rating = 200,
99 .features = CLOCK_EVT_FEAT_PERIODIC |
100 CLOCK_EVT_FEAT_ONESHOT,
101 .set_state_shutdown = moxart_shutdown,
102 .set_state_periodic = moxart_set_periodic,
103 .set_state_oneshot = moxart_set_oneshot,
104 .tick_resume = moxart_set_oneshot,
105 .set_next_event = moxart_clkevt_next_event,
106};
107
108static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id) 143static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id)
109{ 144{
110 struct clock_event_device *evt = dev_id; 145 struct clock_event_device *evt = dev_id;
@@ -112,21 +147,19 @@ static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id)
112 return IRQ_HANDLED; 147 return IRQ_HANDLED;
113} 148}
114 149
115static struct irqaction moxart_timer_irq = {
116 .name = "moxart-timer",
117 .flags = IRQF_TIMER,
118 .handler = moxart_timer_interrupt,
119 .dev_id = &moxart_clockevent,
120};
121
122static int __init moxart_timer_init(struct device_node *node) 150static int __init moxart_timer_init(struct device_node *node)
123{ 151{
124 int ret, irq; 152 int ret, irq;
125 unsigned long pclk; 153 unsigned long pclk;
126 struct clk *clk; 154 struct clk *clk;
155 struct moxart_timer *timer;
156
157 timer = kzalloc(sizeof(*timer), GFP_KERNEL);
158 if (!timer)
159 return -ENOMEM;
127 160
128 base = of_iomap(node, 0); 161 timer->base = of_iomap(node, 0);
129 if (!base) { 162 if (!timer->base) {
130 pr_err("%s: of_iomap failed\n", node->full_name); 163 pr_err("%s: of_iomap failed\n", node->full_name);
131 return -ENXIO; 164 return -ENXIO;
132 } 165 }
@@ -137,12 +170,6 @@ static int __init moxart_timer_init(struct device_node *node)
137 return -EINVAL; 170 return -EINVAL;
138 } 171 }
139 172
140 ret = setup_irq(irq, &moxart_timer_irq);
141 if (ret) {
142 pr_err("%s: setup_irq failed\n", node->full_name);
143 return ret;
144 }
145
146 clk = of_clk_get(node, 0); 173 clk = of_clk_get(node, 0);
147 if (IS_ERR(clk)) { 174 if (IS_ERR(clk)) {
148 pr_err("%s: of_clk_get failed\n", node->full_name); 175 pr_err("%s: of_clk_get failed\n", node->full_name);
@@ -151,7 +178,32 @@ static int __init moxart_timer_init(struct device_node *node)
151 178
152 pclk = clk_get_rate(clk); 179 pclk = clk_get_rate(clk);
153 180
154 ret = clocksource_mmio_init(base + TIMER2_BASE + REG_COUNT, 181 if (of_device_is_compatible(node, "moxa,moxart-timer")) {
182 timer->t1_enable_val = MOXART_TIMER1_ENABLE;
183 timer->t1_disable_val = MOXART_TIMER1_DISABLE;
184 } else if (of_device_is_compatible(node, "aspeed,ast2400-timer")) {
185 timer->t1_enable_val = ASPEED_TIMER1_ENABLE;
186 timer->t1_disable_val = ASPEED_TIMER1_DISABLE;
187 } else {
188 pr_err("%s: unknown platform\n", node->full_name);
189 return -EINVAL;
190 }
191
192 timer->count_per_tick = DIV_ROUND_CLOSEST(pclk, HZ);
193
194 timer->clkevt.name = node->name;
195 timer->clkevt.rating = 200;
196 timer->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
197 CLOCK_EVT_FEAT_ONESHOT;
198 timer->clkevt.set_state_shutdown = moxart_shutdown;
199 timer->clkevt.set_state_periodic = moxart_set_periodic;
200 timer->clkevt.set_state_oneshot = moxart_set_oneshot;
201 timer->clkevt.tick_resume = moxart_set_oneshot;
202 timer->clkevt.set_next_event = moxart_clkevt_next_event;
203 timer->clkevt.cpumask = cpumask_of(0);
204 timer->clkevt.irq = irq;
205
206 ret = clocksource_mmio_init(timer->base + TIMER2_BASE + REG_COUNT,
155 "moxart_timer", pclk, 200, 32, 207 "moxart_timer", pclk, 200, 32,
156 clocksource_mmio_readl_down); 208 clocksource_mmio_readl_down);
157 if (ret) { 209 if (ret) {
@@ -159,13 +211,26 @@ static int __init moxart_timer_init(struct device_node *node)
159 return ret; 211 return ret;
160 } 212 }
161 213
162 clock_count_per_tick = DIV_ROUND_CLOSEST(pclk, HZ); 214 ret = request_irq(irq, moxart_timer_interrupt, IRQF_TIMER,
215 node->name, &timer->clkevt);
216 if (ret) {
217 pr_err("%s: setup_irq failed\n", node->full_name);
218 return ret;
219 }
163 220
164 writel(~0, base + TIMER2_BASE + REG_LOAD); 221 /* Clear match registers */
165 writel(TIMEREG_CR_2_ENABLE, base + TIMER_CR); 222 writel(0, timer->base + TIMER1_BASE + REG_MATCH1);
223 writel(0, timer->base + TIMER1_BASE + REG_MATCH2);
224 writel(0, timer->base + TIMER2_BASE + REG_MATCH1);
225 writel(0, timer->base + TIMER2_BASE + REG_MATCH2);
166 226
167 moxart_clockevent.cpumask = cpumask_of(0); 227 /*
168 moxart_clockevent.irq = irq; 228 * Start timer 2 rolling as our main wall clock source, keep timer 1
229 * disabled
230 */
231 writel(0, timer->base + TIMER_CR);
232 writel(~0, timer->base + TIMER2_BASE + REG_LOAD);
233 writel(timer->t1_disable_val, timer->base + TIMER_CR);
169 234
170 /* 235 /*
171 * documentation is not publicly available: 236 * documentation is not publicly available:
@@ -173,9 +238,9 @@ static int __init moxart_timer_init(struct device_node *node)
173 * max_delta 0xfffffffe should be ok because count 238 * max_delta 0xfffffffe should be ok because count
174 * register size is u32 239 * register size is u32
175 */ 240 */
176 clockevents_config_and_register(&moxart_clockevent, pclk, 241 clockevents_config_and_register(&timer->clkevt, pclk, 0x4, 0xfffffffe);
177 0x4, 0xfffffffe);
178 242
179 return 0; 243 return 0;
180} 244}
181CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init); 245CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init);
246CLOCKSOURCE_OF_DECLARE(aspeed, "aspeed,ast2400-timer", moxart_timer_init);