Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clocksource/drivers/exynos_mct: Support local-timers property

If the device tree indicates that the hardware requires that the
processor only use certain local timers, respect that.

Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Link: https://lore.kernel.org/r/20220609112738.359385-4-vincent.whitchurch@axis.com
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>

authored by

Vincent Whitchurch and committed by
Daniel Lezcano
47dbe4eb e8550f0e

+56 -6
+56 -6
drivers/clocksource/exynos_mct.c
··· 33 33 #define EXYNOS4_MCT_G_INT_ENB EXYNOS4_MCTREG(0x248) 34 34 #define EXYNOS4_MCT_G_WSTAT EXYNOS4_MCTREG(0x24C) 35 35 #define _EXYNOS4_MCT_L_BASE EXYNOS4_MCTREG(0x300) 36 - #define EXYNOS4_MCT_L_BASE(x) (_EXYNOS4_MCT_L_BASE + (0x100 * x)) 36 + #define EXYNOS4_MCT_L_BASE(x) (_EXYNOS4_MCT_L_BASE + (0x100 * (x))) 37 37 #define EXYNOS4_MCT_L_MASK (0xffffff00) 38 38 39 39 #define MCT_L_TCNTB_OFFSET (0x00) ··· 66 66 #define MCT_L0_IRQ 4 67 67 /* Max number of IRQ as per DT binding document */ 68 68 #define MCT_NR_IRQS 20 69 + /* Max number of local timers */ 70 + #define MCT_NR_LOCAL (MCT_NR_IRQS - MCT_L0_IRQ) 69 71 70 72 enum { 71 73 MCT_INT_SPI, ··· 458 456 per_cpu_ptr(&percpu_mct_tick, cpu); 459 457 struct clock_event_device *evt = &mevt->evt; 460 458 461 - mevt->base = EXYNOS4_MCT_L_BASE(cpu); 462 459 snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d", cpu); 463 460 464 461 evt->name = mevt->name; ··· 528 527 return 0; 529 528 } 530 529 530 + /** 531 + * exynos4_timer_interrupts - initialize MCT interrupts 532 + * @np: device node for MCT 533 + * @int_type: interrupt type, MCT_INT_PPI or MCT_INT_SPI 534 + * @local_idx: array mapping CPU numbers to local timer indices 535 + * @nr_local: size of @local_idx array 536 + */ 531 537 static int __init exynos4_timer_interrupts(struct device_node *np, 532 - unsigned int int_type) 538 + unsigned int int_type, 539 + const u32 *local_idx, 540 + size_t nr_local) 533 541 { 534 542 int nr_irqs, i, err, cpu; 535 543 ··· 571 561 } else { 572 562 for_each_possible_cpu(cpu) { 573 563 int mct_irq; 564 + unsigned int irq_idx; 574 565 struct mct_clock_event_device *pcpu_mevt = 575 566 per_cpu_ptr(&percpu_mct_tick, cpu); 576 567 568 + if (cpu >= nr_local) { 569 + err = -EINVAL; 570 + goto out_irq; 571 + } 572 + 573 + irq_idx = MCT_L0_IRQ + local_idx[cpu]; 574 + 577 575 pcpu_mevt->evt.irq = -1; 578 - if (MCT_L0_IRQ + cpu >= ARRAY_SIZE(mct_irqs)) 576 + if (irq_idx >= ARRAY_SIZE(mct_irqs)) 579 577 break; 580 - mct_irq = mct_irqs[MCT_L0_IRQ + cpu]; 578 + mct_irq = mct_irqs[irq_idx]; 581 579 582 580 irq_set_status_flags(mct_irq, IRQ_NOAUTOEN); 583 581 if (request_irq(mct_irq, ··· 599 581 } 600 582 pcpu_mevt->evt.irq = mct_irq; 601 583 } 584 + } 585 + 586 + for_each_possible_cpu(cpu) { 587 + struct mct_clock_event_device *mevt = per_cpu_ptr(&percpu_mct_tick, cpu); 588 + 589 + if (cpu >= nr_local) { 590 + err = -EINVAL; 591 + goto out_irq; 592 + } 593 + 594 + mevt->base = EXYNOS4_MCT_L_BASE(local_idx[cpu]); 602 595 } 603 596 604 597 /* Install hotplug callbacks which configure the timer on this CPU */ ··· 642 613 static int __init mct_init_dt(struct device_node *np, unsigned int int_type) 643 614 { 644 615 bool frc_shared = of_property_read_bool(np, "samsung,frc-shared"); 616 + u32 local_idx[MCT_NR_LOCAL] = {0}; 617 + int nr_local; 645 618 int ret; 619 + 620 + nr_local = of_property_count_u32_elems(np, "samsung,local-timers"); 621 + if (nr_local == 0) 622 + return -EINVAL; 623 + if (nr_local > 0) { 624 + if (nr_local > ARRAY_SIZE(local_idx)) 625 + return -EINVAL; 626 + 627 + ret = of_property_read_u32_array(np, "samsung,local-timers", 628 + local_idx, nr_local); 629 + if (ret) 630 + return ret; 631 + } else { 632 + int i; 633 + 634 + nr_local = ARRAY_SIZE(local_idx); 635 + for (i = 0; i < nr_local; i++) 636 + local_idx[i] = i; 637 + } 646 638 647 639 ret = exynos4_timer_resources(np); 648 640 if (ret) 649 641 return ret; 650 642 651 - ret = exynos4_timer_interrupts(np, int_type); 643 + ret = exynos4_timer_interrupts(np, int_type, local_idx, nr_local); 652 644 if (ret) 653 645 return ret; 654 646