timer-sun5i.c (9482B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Allwinner SoCs hstimer driver. 4 * 5 * Copyright (C) 2013 Maxime Ripard 6 * 7 * Maxime Ripard <maxime.ripard@free-electrons.com> 8 */ 9 10#include <linux/clk.h> 11#include <linux/clockchips.h> 12#include <linux/clocksource.h> 13#include <linux/delay.h> 14#include <linux/interrupt.h> 15#include <linux/irq.h> 16#include <linux/irqreturn.h> 17#include <linux/reset.h> 18#include <linux/slab.h> 19#include <linux/of.h> 20#include <linux/of_address.h> 21#include <linux/of_irq.h> 22 23#define TIMER_IRQ_EN_REG 0x00 24#define TIMER_IRQ_EN(val) BIT(val) 25#define TIMER_IRQ_ST_REG 0x04 26#define TIMER_CTL_REG(val) (0x20 * (val) + 0x10) 27#define TIMER_CTL_ENABLE BIT(0) 28#define TIMER_CTL_RELOAD BIT(1) 29#define TIMER_CTL_CLK_PRES(val) (((val) & 0x7) << 4) 30#define TIMER_CTL_ONESHOT BIT(7) 31#define TIMER_INTVAL_LO_REG(val) (0x20 * (val) + 0x14) 32#define TIMER_INTVAL_HI_REG(val) (0x20 * (val) + 0x18) 33#define TIMER_CNTVAL_LO_REG(val) (0x20 * (val) + 0x1c) 34#define TIMER_CNTVAL_HI_REG(val) (0x20 * (val) + 0x20) 35 36#define TIMER_SYNC_TICKS 3 37 38struct sun5i_timer { 39 void __iomem *base; 40 struct clk *clk; 41 struct notifier_block clk_rate_cb; 42 u32 ticks_per_jiffy; 43}; 44 45#define to_sun5i_timer(x) \ 46 container_of(x, struct sun5i_timer, clk_rate_cb) 47 48struct sun5i_timer_clksrc { 49 struct sun5i_timer timer; 50 struct clocksource clksrc; 51}; 52 53#define to_sun5i_timer_clksrc(x) \ 54 container_of(x, struct sun5i_timer_clksrc, clksrc) 55 56struct sun5i_timer_clkevt { 57 struct sun5i_timer timer; 58 struct clock_event_device clkevt; 59}; 60 61#define to_sun5i_timer_clkevt(x) \ 62 container_of(x, struct sun5i_timer_clkevt, clkevt) 63 64/* 65 * When we disable a timer, we need to wait at least for 2 cycles of 66 * the timer source clock. We will use for that the clocksource timer 67 * that is already setup and runs at the same frequency than the other 68 * timers, and we never will be disabled. 69 */ 70static void sun5i_clkevt_sync(struct sun5i_timer_clkevt *ce) 71{ 72 u32 old = readl(ce->timer.base + TIMER_CNTVAL_LO_REG(1)); 73 74 while ((old - readl(ce->timer.base + TIMER_CNTVAL_LO_REG(1))) < TIMER_SYNC_TICKS) 75 cpu_relax(); 76} 77 78static void sun5i_clkevt_time_stop(struct sun5i_timer_clkevt *ce, u8 timer) 79{ 80 u32 val = readl(ce->timer.base + TIMER_CTL_REG(timer)); 81 writel(val & ~TIMER_CTL_ENABLE, ce->timer.base + TIMER_CTL_REG(timer)); 82 83 sun5i_clkevt_sync(ce); 84} 85 86static void sun5i_clkevt_time_setup(struct sun5i_timer_clkevt *ce, u8 timer, u32 delay) 87{ 88 writel(delay, ce->timer.base + TIMER_INTVAL_LO_REG(timer)); 89} 90 91static void sun5i_clkevt_time_start(struct sun5i_timer_clkevt *ce, u8 timer, bool periodic) 92{ 93 u32 val = readl(ce->timer.base + TIMER_CTL_REG(timer)); 94 95 if (periodic) 96 val &= ~TIMER_CTL_ONESHOT; 97 else 98 val |= TIMER_CTL_ONESHOT; 99 100 writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, 101 ce->timer.base + TIMER_CTL_REG(timer)); 102} 103 104static int sun5i_clkevt_shutdown(struct clock_event_device *clkevt) 105{ 106 struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt); 107 108 sun5i_clkevt_time_stop(ce, 0); 109 return 0; 110} 111 112static int sun5i_clkevt_set_oneshot(struct clock_event_device *clkevt) 113{ 114 struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt); 115 116 sun5i_clkevt_time_stop(ce, 0); 117 sun5i_clkevt_time_start(ce, 0, false); 118 return 0; 119} 120 121static int sun5i_clkevt_set_periodic(struct clock_event_device *clkevt) 122{ 123 struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt); 124 125 sun5i_clkevt_time_stop(ce, 0); 126 sun5i_clkevt_time_setup(ce, 0, ce->timer.ticks_per_jiffy); 127 sun5i_clkevt_time_start(ce, 0, true); 128 return 0; 129} 130 131static int sun5i_clkevt_next_event(unsigned long evt, 132 struct clock_event_device *clkevt) 133{ 134 struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt); 135 136 sun5i_clkevt_time_stop(ce, 0); 137 sun5i_clkevt_time_setup(ce, 0, evt - TIMER_SYNC_TICKS); 138 sun5i_clkevt_time_start(ce, 0, false); 139 140 return 0; 141} 142 143static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id) 144{ 145 struct sun5i_timer_clkevt *ce = (struct sun5i_timer_clkevt *)dev_id; 146 147 writel(0x1, ce->timer.base + TIMER_IRQ_ST_REG); 148 ce->clkevt.event_handler(&ce->clkevt); 149 150 return IRQ_HANDLED; 151} 152 153static u64 sun5i_clksrc_read(struct clocksource *clksrc) 154{ 155 struct sun5i_timer_clksrc *cs = to_sun5i_timer_clksrc(clksrc); 156 157 return ~readl(cs->timer.base + TIMER_CNTVAL_LO_REG(1)); 158} 159 160static int sun5i_rate_cb_clksrc(struct notifier_block *nb, 161 unsigned long event, void *data) 162{ 163 struct clk_notifier_data *ndata = data; 164 struct sun5i_timer *timer = to_sun5i_timer(nb); 165 struct sun5i_timer_clksrc *cs = container_of(timer, struct sun5i_timer_clksrc, timer); 166 167 switch (event) { 168 case PRE_RATE_CHANGE: 169 clocksource_unregister(&cs->clksrc); 170 break; 171 172 case POST_RATE_CHANGE: 173 clocksource_register_hz(&cs->clksrc, ndata->new_rate); 174 break; 175 176 default: 177 break; 178 } 179 180 return NOTIFY_DONE; 181} 182 183static int __init sun5i_setup_clocksource(struct device_node *node, 184 void __iomem *base, 185 struct clk *clk, int irq) 186{ 187 struct sun5i_timer_clksrc *cs; 188 unsigned long rate; 189 int ret; 190 191 cs = kzalloc(sizeof(*cs), GFP_KERNEL); 192 if (!cs) 193 return -ENOMEM; 194 195 ret = clk_prepare_enable(clk); 196 if (ret) { 197 pr_err("Couldn't enable parent clock\n"); 198 goto err_free; 199 } 200 201 rate = clk_get_rate(clk); 202 if (!rate) { 203 pr_err("Couldn't get parent clock rate\n"); 204 ret = -EINVAL; 205 goto err_disable_clk; 206 } 207 208 cs->timer.base = base; 209 cs->timer.clk = clk; 210 cs->timer.clk_rate_cb.notifier_call = sun5i_rate_cb_clksrc; 211 cs->timer.clk_rate_cb.next = NULL; 212 213 ret = clk_notifier_register(clk, &cs->timer.clk_rate_cb); 214 if (ret) { 215 pr_err("Unable to register clock notifier.\n"); 216 goto err_disable_clk; 217 } 218 219 writel(~0, base + TIMER_INTVAL_LO_REG(1)); 220 writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, 221 base + TIMER_CTL_REG(1)); 222 223 cs->clksrc.name = node->name; 224 cs->clksrc.rating = 340; 225 cs->clksrc.read = sun5i_clksrc_read; 226 cs->clksrc.mask = CLOCKSOURCE_MASK(32); 227 cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS; 228 229 ret = clocksource_register_hz(&cs->clksrc, rate); 230 if (ret) { 231 pr_err("Couldn't register clock source.\n"); 232 goto err_remove_notifier; 233 } 234 235 return 0; 236 237err_remove_notifier: 238 clk_notifier_unregister(clk, &cs->timer.clk_rate_cb); 239err_disable_clk: 240 clk_disable_unprepare(clk); 241err_free: 242 kfree(cs); 243 return ret; 244} 245 246static int sun5i_rate_cb_clkevt(struct notifier_block *nb, 247 unsigned long event, void *data) 248{ 249 struct clk_notifier_data *ndata = data; 250 struct sun5i_timer *timer = to_sun5i_timer(nb); 251 struct sun5i_timer_clkevt *ce = container_of(timer, struct sun5i_timer_clkevt, timer); 252 253 if (event == POST_RATE_CHANGE) { 254 clockevents_update_freq(&ce->clkevt, ndata->new_rate); 255 ce->timer.ticks_per_jiffy = DIV_ROUND_UP(ndata->new_rate, HZ); 256 } 257 258 return NOTIFY_DONE; 259} 260 261static int __init sun5i_setup_clockevent(struct device_node *node, void __iomem *base, 262 struct clk *clk, int irq) 263{ 264 struct sun5i_timer_clkevt *ce; 265 unsigned long rate; 266 int ret; 267 u32 val; 268 269 ce = kzalloc(sizeof(*ce), GFP_KERNEL); 270 if (!ce) 271 return -ENOMEM; 272 273 ret = clk_prepare_enable(clk); 274 if (ret) { 275 pr_err("Couldn't enable parent clock\n"); 276 goto err_free; 277 } 278 279 rate = clk_get_rate(clk); 280 if (!rate) { 281 pr_err("Couldn't get parent clock rate\n"); 282 ret = -EINVAL; 283 goto err_disable_clk; 284 } 285 286 ce->timer.base = base; 287 ce->timer.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); 288 ce->timer.clk = clk; 289 ce->timer.clk_rate_cb.notifier_call = sun5i_rate_cb_clkevt; 290 ce->timer.clk_rate_cb.next = NULL; 291 292 ret = clk_notifier_register(clk, &ce->timer.clk_rate_cb); 293 if (ret) { 294 pr_err("Unable to register clock notifier.\n"); 295 goto err_disable_clk; 296 } 297 298 ce->clkevt.name = node->name; 299 ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; 300 ce->clkevt.set_next_event = sun5i_clkevt_next_event; 301 ce->clkevt.set_state_shutdown = sun5i_clkevt_shutdown; 302 ce->clkevt.set_state_periodic = sun5i_clkevt_set_periodic; 303 ce->clkevt.set_state_oneshot = sun5i_clkevt_set_oneshot; 304 ce->clkevt.tick_resume = sun5i_clkevt_shutdown; 305 ce->clkevt.rating = 340; 306 ce->clkevt.irq = irq; 307 ce->clkevt.cpumask = cpu_possible_mask; 308 309 /* Enable timer0 interrupt */ 310 val = readl(base + TIMER_IRQ_EN_REG); 311 writel(val | TIMER_IRQ_EN(0), base + TIMER_IRQ_EN_REG); 312 313 clockevents_config_and_register(&ce->clkevt, rate, 314 TIMER_SYNC_TICKS, 0xffffffff); 315 316 ret = request_irq(irq, sun5i_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL, 317 "sun5i_timer0", ce); 318 if (ret) { 319 pr_err("Unable to register interrupt\n"); 320 goto err_remove_notifier; 321 } 322 323 return 0; 324 325err_remove_notifier: 326 clk_notifier_unregister(clk, &ce->timer.clk_rate_cb); 327err_disable_clk: 328 clk_disable_unprepare(clk); 329err_free: 330 kfree(ce); 331 return ret; 332} 333 334static int __init sun5i_timer_init(struct device_node *node) 335{ 336 struct reset_control *rstc; 337 void __iomem *timer_base; 338 struct clk *clk; 339 int irq, ret; 340 341 timer_base = of_io_request_and_map(node, 0, of_node_full_name(node)); 342 if (IS_ERR(timer_base)) { 343 pr_err("Can't map registers\n"); 344 return PTR_ERR(timer_base); 345 } 346 347 irq = irq_of_parse_and_map(node, 0); 348 if (irq <= 0) { 349 pr_err("Can't parse IRQ\n"); 350 return -EINVAL; 351 } 352 353 clk = of_clk_get(node, 0); 354 if (IS_ERR(clk)) { 355 pr_err("Can't get timer clock\n"); 356 return PTR_ERR(clk); 357 } 358 359 rstc = of_reset_control_get(node, NULL); 360 if (!IS_ERR(rstc)) 361 reset_control_deassert(rstc); 362 363 ret = sun5i_setup_clocksource(node, timer_base, clk, irq); 364 if (ret) 365 return ret; 366 367 return sun5i_setup_clockevent(node, timer_base, clk, irq); 368} 369TIMER_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer", 370 sun5i_timer_init); 371TIMER_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer", 372 sun5i_timer_init);