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 return ret; 252 253 return 0; 254 } 255 256 static int sun5i_timer_probe(struct platform_device *pdev) 257 { 258 const struct sunxi_timer_quirks *quirks; 259 struct device *dev = &pdev->dev; 260 struct sun5i_timer *st; 261 struct reset_control *rstc; 262 void __iomem *timer_base; 263 struct clk *clk; 264 unsigned long rate; 265 int irq, ret; 266 267 st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); 268 if (!st) 269 return -ENOMEM; 270 271 platform_set_drvdata(pdev, st); 272 273 timer_base = devm_platform_ioremap_resource(pdev, 0); 274 if (IS_ERR(timer_base)) { 275 dev_err(dev, "Can't map registers\n"); 276 return PTR_ERR(timer_base); 277 } 278 279 irq = platform_get_irq(pdev, 0); 280 if (irq < 0) 281 return irq; 282 283 clk = devm_clk_get_enabled(dev, NULL); 284 if (IS_ERR(clk)) { 285 dev_err(dev, "Can't get timer clock\n"); 286 return PTR_ERR(clk); 287 } 288 289 rate = clk_get_rate(clk); 290 if (!rate) { 291 dev_err(dev, "Couldn't get parent clock rate\n"); 292 return -EINVAL; 293 } 294 295 quirks = of_device_get_match_data(&pdev->dev); 296 if (!quirks) { 297 dev_err(&pdev->dev, "Failed to determine the quirks to use\n"); 298 return -ENODEV; 299 } 300 301 st->base = timer_base; 302 st->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); 303 st->clk = clk; 304 st->clk_rate_cb.notifier_call = sun5i_rate_cb; 305 st->clk_rate_cb.next = NULL; 306 st->quirks = quirks; 307 308 ret = devm_clk_notifier_register(dev, clk, &st->clk_rate_cb); 309 if (ret) { 310 dev_err(dev, "Unable to register clock notifier.\n"); 311 return ret; 312 } 313 314 rstc = devm_reset_control_get_optional_exclusive(dev, NULL); 315 if (IS_ERR(rstc)) 316 return dev_err_probe(dev, PTR_ERR(rstc), 317 "failed to get reset\n"); 318 if (rstc) 319 reset_control_deassert(rstc); 320 321 ret = sun5i_setup_clocksource(pdev, rate); 322 if (ret) 323 return ret; 324 325 ret = sun5i_setup_clockevent(pdev, rate, irq); 326 if (ret) 327 goto err_unreg_clocksource; 328 329 return 0; 330 331 err_unreg_clocksource: 332 clocksource_unregister(&st->clksrc); 333 return ret; 334 } 335 336 static void sun5i_timer_remove(struct platform_device *pdev) 337 { 338 struct sun5i_timer *st = platform_get_drvdata(pdev); 339 340 clocksource_unregister(&st->clksrc); 341 } 342 343 static const struct sunxi_timer_quirks sun5i_sun7i_hstimer_quirks = { 344 .from_ctl_base_offset = 0x0, 345 }; 346 347 static const struct sunxi_timer_quirks sun20i_d1_hstimer_quirks = { 348 .from_ctl_base_offset = 0x10, 349 }; 350 351 static const struct of_device_id sun5i_timer_of_match[] = { 352 { 353 .compatible = "allwinner,sun5i-a13-hstimer", 354 .data = &sun5i_sun7i_hstimer_quirks, 355 }, 356 { 357 .compatible = "allwinner,sun7i-a20-hstimer", 358 .data = &sun5i_sun7i_hstimer_quirks, 359 }, 360 { 361 .compatible = "allwinner,sun20i-d1-hstimer", 362 .data = &sun20i_d1_hstimer_quirks, 363 }, 364 {}, 365 }; 366 MODULE_DEVICE_TABLE(of, sun5i_timer_of_match); 367 368 static struct platform_driver sun5i_timer_driver = { 369 .probe = sun5i_timer_probe, 370 .remove = sun5i_timer_remove, 371 .driver = { 372 .name = "sun5i-timer", 373 .of_match_table = sun5i_timer_of_match, 374 .suppress_bind_attrs = true, 375 }, 376 }; 377 module_platform_driver(sun5i_timer_driver); 378