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/platform_device.h> 20 21 #define TIMER_IRQ_EN_REG 0x00 22 #define TIMER_IRQ_EN(val) BIT(val) 23 #define TIMER_IRQ_ST_REG 0x04 24 #define TIMER_CTL_REG(val, offset) (0x20 * (val) + 0x10 + (offset)) 25 #define TIMER_CTL_ENABLE BIT(0) 26 #define TIMER_CTL_RELOAD BIT(1) 27 #define TIMER_CTL_CLK_PRES(val) (((val) & 0x7) << 4) 28 #define TIMER_CTL_ONESHOT BIT(7) 29 #define TIMER_INTVAL_LO_REG(val, offset) (0x20 * (val) + 0x14 + (offset)) 30 #define TIMER_INTVAL_HI_REG(val, offset) (0x20 * (val) + 0x18 + (offset)) 31 #define TIMER_CNTVAL_LO_REG(val, offset) (0x20 * (val) + 0x1c + (offset)) 32 #define TIMER_CNTVAL_HI_REG(val, offset) (0x20 * (val) + 0x20 + (offset)) 33 34 #define TIMER_SYNC_TICKS 3 35 36 /** 37 * struct sunxi_timer_quirks - Differences between SoC variants. 38 * 39 * @from_ctl_base_offset: offset applied from ctl register onwards 40 */ 41 struct sunxi_timer_quirks { 42 u32 from_ctl_base_offset; 43 }; 44 45 struct sun5i_timer { 46 void __iomem *base; 47 struct clk *clk; 48 struct notifier_block clk_rate_cb; 49 u32 ticks_per_jiffy; 50 struct clocksource clksrc; 51 struct clock_event_device clkevt; 52 const struct sunxi_timer_quirks *quirks; 53 }; 54 55 #define nb_to_sun5i_timer(x) \ 56 container_of(x, struct sun5i_timer, clk_rate_cb) 57 #define clksrc_to_sun5i_timer(x) \ 58 container_of(x, struct sun5i_timer, clksrc) 59 #define clkevt_to_sun5i_timer(x) \ 60 container_of(x, struct sun5i_timer, clkevt) 61 62 /* 63 * When we disable a timer, we need to wait at least for 2 cycles of 64 * the timer source clock. We will use for that the clocksource timer 65 * that is already setup and runs at the same frequency than the other 66 * timers, and we never will be disabled. 67 */ 68 static void sun5i_clkevt_sync(struct sun5i_timer *ce) 69 { 70 u32 offset = ce->quirks->from_ctl_base_offset; 71 u32 old = readl(ce->base + TIMER_CNTVAL_LO_REG(1, offset)); 72 73 while ((old - readl(ce->base + TIMER_CNTVAL_LO_REG(1, offset))) < 74 TIMER_SYNC_TICKS) 75 cpu_relax(); 76 } 77 78 static void sun5i_clkevt_time_stop(struct sun5i_timer *ce, u8 timer) 79 { 80 u32 offset = ce->quirks->from_ctl_base_offset; 81 u32 val = readl(ce->base + TIMER_CTL_REG(timer, offset)); 82 83 writel(val & ~TIMER_CTL_ENABLE, 84 ce->base + TIMER_CTL_REG(timer, offset)); 85 86 sun5i_clkevt_sync(ce); 87 } 88 89 static void sun5i_clkevt_time_setup(struct sun5i_timer *ce, u8 timer, u32 delay) 90 { 91 u32 offset = ce->quirks->from_ctl_base_offset; 92 93 writel(delay, ce->base + TIMER_INTVAL_LO_REG(timer, offset)); 94 } 95 96 static void sun5i_clkevt_time_start(struct sun5i_timer *ce, u8 timer, bool periodic) 97 { 98 u32 offset = ce->quirks->from_ctl_base_offset; 99 u32 val = readl(ce->base + TIMER_CTL_REG(timer, offset)); 100 101 if (periodic) 102 val &= ~TIMER_CTL_ONESHOT; 103 else 104 val |= TIMER_CTL_ONESHOT; 105 106 writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, 107 ce->base + TIMER_CTL_REG(timer, offset)); 108 } 109 110 static int sun5i_clkevt_shutdown(struct clock_event_device *clkevt) 111 { 112 struct sun5i_timer *ce = clkevt_to_sun5i_timer(clkevt); 113 114 sun5i_clkevt_time_stop(ce, 0); 115 return 0; 116 } 117 118 static int sun5i_clkevt_set_oneshot(struct clock_event_device *clkevt) 119 { 120 struct sun5i_timer *ce = clkevt_to_sun5i_timer(clkevt); 121 122 sun5i_clkevt_time_stop(ce, 0); 123 sun5i_clkevt_time_start(ce, 0, false); 124 return 0; 125 } 126 127 static int sun5i_clkevt_set_periodic(struct clock_event_device *clkevt) 128 { 129 struct sun5i_timer *ce = clkevt_to_sun5i_timer(clkevt); 130 131 sun5i_clkevt_time_stop(ce, 0); 132 sun5i_clkevt_time_setup(ce, 0, ce->ticks_per_jiffy); 133 sun5i_clkevt_time_start(ce, 0, true); 134 return 0; 135 } 136 137 static int sun5i_clkevt_next_event(unsigned long evt, 138 struct clock_event_device *clkevt) 139 { 140 struct sun5i_timer *ce = clkevt_to_sun5i_timer(clkevt); 141 142 sun5i_clkevt_time_stop(ce, 0); 143 sun5i_clkevt_time_setup(ce, 0, evt - TIMER_SYNC_TICKS); 144 sun5i_clkevt_time_start(ce, 0, false); 145 146 return 0; 147 } 148 149 static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id) 150 { 151 struct sun5i_timer *ce = dev_id; 152 153 writel(0x1, ce->base + TIMER_IRQ_ST_REG); 154 ce->clkevt.event_handler(&ce->clkevt); 155 156 return IRQ_HANDLED; 157 } 158 159 static u64 sun5i_clksrc_read(struct clocksource *clksrc) 160 { 161 struct sun5i_timer *cs = clksrc_to_sun5i_timer(clksrc); 162 u32 offset = cs->quirks->from_ctl_base_offset; 163 164 return ~readl(cs->base + TIMER_CNTVAL_LO_REG(1, offset)); 165 } 166 167 static int sun5i_rate_cb(struct notifier_block *nb, 168 unsigned long event, void *data) 169 { 170 struct clk_notifier_data *ndata = data; 171 struct sun5i_timer *cs = nb_to_sun5i_timer(nb); 172 173 switch (event) { 174 case PRE_RATE_CHANGE: 175 clocksource_unregister(&cs->clksrc); 176 break; 177 178 case POST_RATE_CHANGE: 179 clocksource_register_hz(&cs->clksrc, ndata->new_rate); 180 clockevents_update_freq(&cs->clkevt, ndata->new_rate); 181 cs->ticks_per_jiffy = DIV_ROUND_UP(ndata->new_rate, HZ); 182 break; 183 184 default: 185 break; 186 } 187 188 return NOTIFY_DONE; 189 } 190 191 static int sun5i_setup_clocksource(struct platform_device *pdev, 192 unsigned long rate) 193 { 194 struct sun5i_timer *cs = platform_get_drvdata(pdev); 195 u32 offset = cs->quirks->from_ctl_base_offset; 196 void __iomem *base = cs->base; 197 int ret; 198 199 writel(~0, base + TIMER_INTVAL_LO_REG(1, offset)); 200 writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, 201 base + TIMER_CTL_REG(1, offset)); 202 203 cs->clksrc.name = pdev->dev.of_node->name; 204 cs->clksrc.rating = 340; 205 cs->clksrc.read = sun5i_clksrc_read; 206 cs->clksrc.mask = CLOCKSOURCE_MASK(32); 207 cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS; 208 cs->clksrc.owner = THIS_MODULE; 209 210 ret = clocksource_register_hz(&cs->clksrc, rate); 211 if (ret) { 212 dev_err(&pdev->dev, "Couldn't register clock source.\n"); 213 return ret; 214 } 215 216 return 0; 217 } 218 219 static int sun5i_setup_clockevent(struct platform_device *pdev, 220 unsigned long rate, int irq) 221 { 222 struct device *dev = &pdev->dev; 223 struct sun5i_timer *ce = platform_get_drvdata(pdev); 224 void __iomem *base = ce->base; 225 int ret; 226 u32 val; 227 228 ce->clkevt.name = dev->of_node->name; 229 ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; 230 ce->clkevt.set_next_event = sun5i_clkevt_next_event; 231 ce->clkevt.set_state_shutdown = sun5i_clkevt_shutdown; 232 ce->clkevt.set_state_periodic = sun5i_clkevt_set_periodic; 233 ce->clkevt.set_state_oneshot = sun5i_clkevt_set_oneshot; 234 ce->clkevt.tick_resume = sun5i_clkevt_shutdown; 235 ce->clkevt.rating = 340; 236 ce->clkevt.irq = irq; 237 ce->clkevt.cpumask = cpu_possible_mask; 238 ce->clkevt.owner = THIS_MODULE; 239 240 /* Enable timer0 interrupt */ 241 val = readl(base + TIMER_IRQ_EN_REG); 242 writel(val | TIMER_IRQ_EN(0), base + TIMER_IRQ_EN_REG); 243 244 clockevents_config_and_register(&ce->clkevt, rate, 245 TIMER_SYNC_TICKS, 0xffffffff); 246 247 ret = devm_request_irq(dev, irq, sun5i_timer_interrupt, 248 IRQF_TIMER | IRQF_IRQPOLL, 249 "sun5i_timer0", ce); 250 if (ret) { 251 dev_err(dev, "Unable to register interrupt\n"); 252 return ret; 253 } 254 255 return 0; 256 } 257 258 static int sun5i_timer_probe(struct platform_device *pdev) 259 { 260 const struct sunxi_timer_quirks *quirks; 261 struct device *dev = &pdev->dev; 262 struct sun5i_timer *st; 263 struct reset_control *rstc; 264 void __iomem *timer_base; 265 struct clk *clk; 266 unsigned long rate; 267 int irq, ret; 268 269 st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); 270 if (!st) 271 return -ENOMEM; 272 273 platform_set_drvdata(pdev, st); 274 275 timer_base = devm_platform_ioremap_resource(pdev, 0); 276 if (IS_ERR(timer_base)) { 277 dev_err(dev, "Can't map registers\n"); 278 return PTR_ERR(timer_base); 279 } 280 281 irq = platform_get_irq(pdev, 0); 282 if (irq < 0) 283 return irq; 284 285 clk = devm_clk_get_enabled(dev, NULL); 286 if (IS_ERR(clk)) { 287 dev_err(dev, "Can't get timer clock\n"); 288 return PTR_ERR(clk); 289 } 290 291 rate = clk_get_rate(clk); 292 if (!rate) { 293 dev_err(dev, "Couldn't get parent clock rate\n"); 294 return -EINVAL; 295 } 296 297 quirks = of_device_get_match_data(&pdev->dev); 298 if (!quirks) { 299 dev_err(&pdev->dev, "Failed to determine the quirks to use\n"); 300 return -ENODEV; 301 } 302 303 st->base = timer_base; 304 st->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); 305 st->clk = clk; 306 st->clk_rate_cb.notifier_call = sun5i_rate_cb; 307 st->clk_rate_cb.next = NULL; 308 st->quirks = quirks; 309 310 ret = devm_clk_notifier_register(dev, clk, &st->clk_rate_cb); 311 if (ret) { 312 dev_err(dev, "Unable to register clock notifier.\n"); 313 return ret; 314 } 315 316 rstc = devm_reset_control_get_optional_exclusive(dev, NULL); 317 if (IS_ERR(rstc)) 318 return dev_err_probe(dev, PTR_ERR(rstc), 319 "failed to get reset\n"); 320 if (rstc) 321 reset_control_deassert(rstc); 322 323 ret = sun5i_setup_clocksource(pdev, rate); 324 if (ret) 325 return ret; 326 327 ret = sun5i_setup_clockevent(pdev, rate, irq); 328 if (ret) 329 goto err_unreg_clocksource; 330 331 return 0; 332 333 err_unreg_clocksource: 334 clocksource_unregister(&st->clksrc); 335 return ret; 336 } 337 338 static void sun5i_timer_remove(struct platform_device *pdev) 339 { 340 struct sun5i_timer *st = platform_get_drvdata(pdev); 341 342 clocksource_unregister(&st->clksrc); 343 } 344 345 static const struct sunxi_timer_quirks sun5i_sun7i_hstimer_quirks = { 346 .from_ctl_base_offset = 0x0, 347 }; 348 349 static const struct sunxi_timer_quirks sun20i_d1_hstimer_quirks = { 350 .from_ctl_base_offset = 0x10, 351 }; 352 353 static const struct of_device_id sun5i_timer_of_match[] = { 354 { 355 .compatible = "allwinner,sun5i-a13-hstimer", 356 .data = &sun5i_sun7i_hstimer_quirks, 357 }, 358 { 359 .compatible = "allwinner,sun7i-a20-hstimer", 360 .data = &sun5i_sun7i_hstimer_quirks, 361 }, 362 { 363 .compatible = "allwinner,sun20i-d1-hstimer", 364 .data = &sun20i_d1_hstimer_quirks, 365 }, 366 {}, 367 }; 368 MODULE_DEVICE_TABLE(of, sun5i_timer_of_match); 369 370 static struct platform_driver sun5i_timer_driver = { 371 .probe = sun5i_timer_probe, 372 .remove = sun5i_timer_remove, 373 .driver = { 374 .name = "sun5i-timer", 375 .of_match_table = sun5i_timer_of_match, 376 .suppress_bind_attrs = true, 377 }, 378 }; 379 module_platform_driver(sun5i_timer_driver); 380