1 // SPDX-License-Identifier: GPL-2.0-or-later 1 2 /* 3 * MPIC timer driver 4 * 5 * Copyright 2013 Freescale Semiconductor, Inc 6 * Author: Dongsheng Wang <Dongsheng.Wang@free 7 * Li Yang <leoli@freescale.com> 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/init.h> 12 #include <linux/module.h> 13 #include <linux/errno.h> 14 #include <linux/mm.h> 15 #include <linux/interrupt.h> 16 #include <linux/slab.h> 17 #include <linux/of.h> 18 #include <linux/of_address.h> 19 #include <linux/of_irq.h> 20 #include <linux/syscore_ops.h> 21 #include <sysdev/fsl_soc.h> 22 #include <asm/io.h> 23 24 #include <asm/mpic_timer.h> 25 26 #define FSL_GLOBAL_TIMER 0x1 27 28 /* Clock Ratio 29 * Divide by 64 0x00000300 30 * Divide by 32 0x00000200 31 * Divide by 16 0x00000100 32 * Divide by 8 0x00000000 (Hardware default d 33 */ 34 #define MPIC_TIMER_TCR_CLKDIV 0x0000 35 36 #define MPIC_TIMER_TCR_ROVR_OFFSET 24 37 38 #define TIMER_STOP 0x8000 39 #define GTCCR_TOG 0x8000 40 #define TIMERS_PER_GROUP 4 41 #define MAX_TICKS (~0U > 42 #define MAX_TICKS_CASCADE (~0U) 43 #define TIMER_OFFSET(num) (1 << 44 45 struct timer_regs { 46 u32 gtccr; 47 u32 res0[3]; 48 u32 gtbcr; 49 u32 res1[3]; 50 u32 gtvpr; 51 u32 res2[3]; 52 u32 gtdr; 53 u32 res3[3]; 54 }; 55 56 struct cascade_priv { 57 u32 tcr_value; /* TCR 58 unsigned int cascade_map; /* cas 59 unsigned int timer_num; /* cas 60 }; 61 62 struct timer_group_priv { 63 struct timer_regs __iomem *regs; 64 struct mpic_timer timer[ 65 struct list_head node; 66 unsigned int timerf 67 unsigned int idle; 68 unsigned int flags; 69 spinlock_t lock; 70 void __iomem *group 71 }; 72 73 static struct cascade_priv cascade_timer[] = { 74 /* cascade timer 0 and 1 */ 75 {0x1, 0xc, 0x1}, 76 /* cascade timer 1 and 2 */ 77 {0x2, 0x6, 0x2}, 78 /* cascade timer 2 and 3 */ 79 {0x4, 0x3, 0x3} 80 }; 81 82 static LIST_HEAD(timer_group_list); 83 84 static void convert_ticks_to_time(struct timer 85 const u64 ticks, time64_t *tim 86 { 87 *time = (u64)div_u64(ticks, priv->time 88 } 89 90 /* the time set by the user is converted to "t 91 static int convert_time_to_ticks(struct timer_ 92 time64_t time, u64 *ticks) 93 { 94 u64 max_value; /* prevent u64 95 96 max_value = div_u64(ULLONG_MAX, priv-> 97 98 if (time > max_value) 99 return -EINVAL; 100 101 *ticks = (u64)time * (u64)priv->timerf 102 103 return 0; 104 } 105 106 /* detect whether there is a cascade timer ava 107 static struct mpic_timer *detect_idle_cascade_ 108 struct 109 { 110 struct cascade_priv *casc_priv; 111 unsigned int map; 112 unsigned int array_size = ARRAY_SIZE(c 113 unsigned int num; 114 unsigned int i; 115 unsigned long flags; 116 117 casc_priv = cascade_timer; 118 for (i = 0; i < array_size; i++) { 119 spin_lock_irqsave(&priv->lock, 120 map = casc_priv->cascade_map & 121 if (map == casc_priv->cascade_ 122 num = casc_priv->timer 123 priv->timer[num].casca 124 125 /* set timer busy */ 126 priv->idle &= ~casc_pr 127 spin_unlock_irqrestore 128 return &priv->timer[nu 129 } 130 spin_unlock_irqrestore(&priv-> 131 casc_priv++; 132 } 133 134 return NULL; 135 } 136 137 static int set_cascade_timer(struct timer_grou 138 unsigned int num) 139 { 140 struct cascade_priv *casc_priv; 141 u32 tcr; 142 u32 tmp_ticks; 143 u32 rem_ticks; 144 145 /* set group tcr reg for cascade */ 146 casc_priv = priv->timer[num].cascade_h 147 if (!casc_priv) 148 return -EINVAL; 149 150 tcr = casc_priv->tcr_value | 151 (casc_priv->tcr_value << MPIC_ 152 setbits32(priv->group_tcr, tcr); 153 154 tmp_ticks = div_u64_rem(ticks, MAX_TIC 155 156 out_be32(&priv->regs[num].gtccr, 0); 157 out_be32(&priv->regs[num].gtbcr, tmp_t 158 159 out_be32(&priv->regs[num - 1].gtccr, 0 160 out_be32(&priv->regs[num - 1].gtbcr, r 161 162 return 0; 163 } 164 165 static struct mpic_timer *get_cascade_timer(st 166 u64 ti 167 { 168 struct mpic_timer *allocated_timer; 169 170 /* Two cascade timers: Support the max 171 const u64 max_ticks = (u64)MAX_TICKS * 172 int ret; 173 174 if (ticks > max_ticks) 175 return NULL; 176 177 /* detect idle timer */ 178 allocated_timer = detect_idle_cascade_ 179 if (!allocated_timer) 180 return NULL; 181 182 /* set ticks to timer */ 183 ret = set_cascade_timer(priv, ticks, a 184 if (ret < 0) 185 return NULL; 186 187 return allocated_timer; 188 } 189 190 static struct mpic_timer *get_timer(time64_t t 191 { 192 struct timer_group_priv *priv; 193 struct mpic_timer *timer; 194 195 u64 ticks; 196 unsigned int num; 197 unsigned int i; 198 unsigned long flags; 199 int ret; 200 201 list_for_each_entry(priv, &timer_group 202 ret = convert_time_to_ticks(pr 203 if (ret < 0) 204 return NULL; 205 206 if (ticks > MAX_TICKS) { 207 if (!(priv->flags & FS 208 return NULL; 209 210 timer = get_cascade_ti 211 if (!timer) 212 continue; 213 214 return timer; 215 } 216 217 for (i = 0; i < TIMERS_PER_GRO 218 /* one timer: Reverse 219 num = TIMERS_PER_GROUP 220 spin_lock_irqsave(&pri 221 if (priv->idle & (1 << 222 /* set timer b 223 priv->idle &= 224 /* set ticks & 225 out_be32(&priv 226 ticks 227 out_be32(&priv 228 priv->timer[nu 229 spin_unlock_ir 230 return &priv-> 231 } 232 spin_unlock_irqrestore 233 } 234 } 235 236 return NULL; 237 } 238 239 /** 240 * mpic_start_timer - start hardware timer 241 * @handle: the timer to be started. 242 * 243 * It will do ->fn(->dev) callback from the ha 244 * the 'time64_t' point in the future. 245 */ 246 void mpic_start_timer(struct mpic_timer *handl 247 { 248 struct timer_group_priv *priv = contai 249 struct timer_group_pri 250 251 clrbits32(&priv->regs[handle->num].gtb 252 } 253 EXPORT_SYMBOL(mpic_start_timer); 254 255 /** 256 * mpic_stop_timer - stop hardware timer 257 * @handle: the timer to be stopped 258 * 259 * The timer periodically generates an interru 260 */ 261 void mpic_stop_timer(struct mpic_timer *handle 262 { 263 struct timer_group_priv *priv = contai 264 struct timer_group_pri 265 struct cascade_priv *casc_priv; 266 267 setbits32(&priv->regs[handle->num].gtb 268 269 casc_priv = priv->timer[handle->num].c 270 if (casc_priv) { 271 out_be32(&priv->regs[handle->n 272 out_be32(&priv->regs[handle->n 273 } else { 274 out_be32(&priv->regs[handle->n 275 } 276 } 277 EXPORT_SYMBOL(mpic_stop_timer); 278 279 /** 280 * mpic_get_remain_time - get timer time 281 * @handle: the timer to be selected. 282 * @time: time for timer 283 * 284 * Query timer remaining time. 285 */ 286 void mpic_get_remain_time(struct mpic_timer *h 287 { 288 struct timer_group_priv *priv = contai 289 struct timer_group_pri 290 struct cascade_priv *casc_priv; 291 292 u64 ticks; 293 u32 tmp_ticks; 294 295 casc_priv = priv->timer[handle->num].c 296 if (casc_priv) { 297 tmp_ticks = in_be32(&priv->reg 298 tmp_ticks &= ~GTCCR_TOG; 299 ticks = ((u64)tmp_ticks & UINT 300 tmp_ticks = in_be32(&priv->reg 301 ticks += tmp_ticks; 302 } else { 303 ticks = in_be32(&priv->regs[ha 304 ticks &= ~GTCCR_TOG; 305 } 306 307 convert_ticks_to_time(priv, ticks, tim 308 } 309 EXPORT_SYMBOL(mpic_get_remain_time); 310 311 /** 312 * mpic_free_timer - free hardware timer 313 * @handle: the timer to be removed. 314 * 315 * Free the timer. 316 * 317 * Note: can not be used in interrupt context. 318 */ 319 void mpic_free_timer(struct mpic_timer *handle 320 { 321 struct timer_group_priv *priv = contai 322 struct timer_group_pri 323 324 struct cascade_priv *casc_priv; 325 unsigned long flags; 326 327 mpic_stop_timer(handle); 328 329 casc_priv = priv->timer[handle->num].c 330 331 free_irq(priv->timer[handle->num].irq, 332 333 spin_lock_irqsave(&priv->lock, flags); 334 if (casc_priv) { 335 u32 tcr; 336 tcr = casc_priv->tcr_value | ( 337 MPIC_T 338 clrbits32(priv->group_tcr, tcr 339 priv->idle |= casc_priv->casca 340 priv->timer[handle->num].casca 341 } else { 342 priv->idle |= TIMER_OFFSET(han 343 } 344 spin_unlock_irqrestore(&priv->lock, fl 345 } 346 EXPORT_SYMBOL(mpic_free_timer); 347 348 /** 349 * mpic_request_timer - get a hardware timer 350 * @fn: interrupt handler function 351 * @dev: callback function of the data 352 * @time: time for timer 353 * 354 * This executes the "request_irq", returning 355 * else "handle" on success. 356 */ 357 struct mpic_timer *mpic_request_timer(irq_hand 358 time64_t 359 { 360 struct mpic_timer *allocated_timer; 361 int ret; 362 363 if (list_empty(&timer_group_list)) 364 return NULL; 365 366 if (time < 0) 367 return NULL; 368 369 allocated_timer = get_timer(time); 370 if (!allocated_timer) 371 return NULL; 372 373 ret = request_irq(allocated_timer->irq 374 IRQF_TRIGGER_LOW, "glo 375 if (ret) { 376 mpic_free_timer(allocated_time 377 return NULL; 378 } 379 380 allocated_timer->dev = dev; 381 382 return allocated_timer; 383 } 384 EXPORT_SYMBOL(mpic_request_timer); 385 386 static int __init timer_group_get_freq(struct 387 struct timer_group_pri 388 { 389 u32 div; 390 391 if (priv->flags & FSL_GLOBAL_TIMER) { 392 struct device_node *dn; 393 394 dn = of_find_compatible_node(N 395 if (dn) { 396 of_property_read_u32(d 397 &priv- 398 of_node_put(dn); 399 } 400 } 401 402 if (priv->timerfreq <= 0) 403 return -EINVAL; 404 405 if (priv->flags & FSL_GLOBAL_TIMER) { 406 div = (1 << (MPIC_TIMER_TCR_CL 407 priv->timerfreq /= div; 408 } 409 410 return 0; 411 } 412 413 static int __init timer_group_get_irq(struct d 414 struct timer_group_priv *priv) 415 { 416 const u32 all_timer[] = { 0, TIMERS_PE 417 const u32 *p; 418 u32 offset; 419 u32 count; 420 421 unsigned int i; 422 unsigned int j; 423 unsigned int irq_index = 0; 424 unsigned int irq; 425 int len; 426 427 p = of_get_property(np, "fsl,available 428 if (p && len % (2 * sizeof(u32)) != 0) 429 pr_err("%pOF: malformed availa 430 return -EINVAL; 431 } 432 433 if (!p) { 434 p = all_timer; 435 len = sizeof(all_timer); 436 } 437 438 len /= 2 * sizeof(u32); 439 440 for (i = 0; i < len; i++) { 441 offset = p[i * 2]; 442 count = p[i * 2 + 1]; 443 for (j = 0; j < count; j++) { 444 irq = irq_of_parse_and 445 if (!irq) { 446 pr_err("%pOF: 447 return -EINVAL 448 } 449 450 /* Set timer idle */ 451 priv->idle |= TIMER_OF 452 priv->timer[offset + j 453 priv->timer[offset + j 454 irq_index++; 455 } 456 } 457 458 return 0; 459 } 460 461 static void __init timer_group_init(struct dev 462 { 463 struct timer_group_priv *priv; 464 unsigned int i = 0; 465 int ret; 466 467 priv = kzalloc(sizeof(struct timer_gro 468 if (!priv) { 469 pr_err("%pOF: cannot allocate 470 return; 471 } 472 473 if (of_device_is_compatible(np, "fsl,m 474 priv->flags |= FSL_GLOBAL_TIME 475 476 priv->regs = of_iomap(np, i++); 477 if (!priv->regs) { 478 pr_err("%pOF: cannot ioremap t 479 goto out; 480 } 481 482 if (priv->flags & FSL_GLOBAL_TIMER) { 483 priv->group_tcr = of_iomap(np, 484 if (!priv->group_tcr) { 485 pr_err("%pOF: cannot i 486 goto out; 487 } 488 } 489 490 ret = timer_group_get_freq(np, priv); 491 if (ret < 0) { 492 pr_err("%pOF: cannot get timer 493 goto out; 494 } 495 496 ret = timer_group_get_irq(np, priv); 497 if (ret < 0) { 498 pr_err("%pOF: cannot get timer 499 goto out; 500 } 501 502 spin_lock_init(&priv->lock); 503 504 /* Init FSL timer hardware */ 505 if (priv->flags & FSL_GLOBAL_TIMER) 506 setbits32(priv->group_tcr, MPI 507 508 list_add_tail(&priv->node, &timer_grou 509 510 return; 511 512 out: 513 if (priv->regs) 514 iounmap(priv->regs); 515 516 if (priv->group_tcr) 517 iounmap(priv->group_tcr); 518 519 kfree(priv); 520 } 521 522 static void mpic_timer_resume(void) 523 { 524 struct timer_group_priv *priv; 525 526 list_for_each_entry(priv, &timer_group 527 /* Init FSL timer hardware */ 528 if (priv->flags & FSL_GLOBAL_T 529 setbits32(priv->group_ 530 } 531 } 532 533 static const struct of_device_id mpic_timer_id 534 { .compatible = "fsl,mpic-global-timer 535 {}, 536 }; 537 538 static struct syscore_ops mpic_timer_syscore_o 539 .resume = mpic_timer_resume, 540 }; 541 542 static int __init mpic_timer_init(void) 543 { 544 struct device_node *np = NULL; 545 546 for_each_matching_node(np, mpic_timer_ 547 timer_group_init(np); 548 549 register_syscore_ops(&mpic_timer_sysco 550 551 if (list_empty(&timer_group_list)) 552 return -ENODEV; 553 554 return 0; 555 } 556 subsys_initcall(mpic_timer_init); 557
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.