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>
This commit is contained in:
Vincent Whitchurch 2022-06-09 13:27:37 +02:00 committed by Daniel Lezcano
parent e8550f0e7b
commit 47dbe4eb98

View file

@ -33,7 +33,7 @@
#define EXYNOS4_MCT_G_INT_ENB EXYNOS4_MCTREG(0x248)
#define EXYNOS4_MCT_G_WSTAT EXYNOS4_MCTREG(0x24C)
#define _EXYNOS4_MCT_L_BASE EXYNOS4_MCTREG(0x300)
#define EXYNOS4_MCT_L_BASE(x) (_EXYNOS4_MCT_L_BASE + (0x100 * x))
#define EXYNOS4_MCT_L_BASE(x) (_EXYNOS4_MCT_L_BASE + (0x100 * (x)))
#define EXYNOS4_MCT_L_MASK (0xffffff00)
#define MCT_L_TCNTB_OFFSET (0x00)
@ -66,6 +66,8 @@
#define MCT_L0_IRQ 4
/* Max number of IRQ as per DT binding document */
#define MCT_NR_IRQS 20
/* Max number of local timers */
#define MCT_NR_LOCAL (MCT_NR_IRQS - MCT_L0_IRQ)
enum {
MCT_INT_SPI,
@ -456,7 +458,6 @@ static int exynos4_mct_starting_cpu(unsigned int cpu)
per_cpu_ptr(&percpu_mct_tick, cpu);
struct clock_event_device *evt = &mevt->evt;
mevt->base = EXYNOS4_MCT_L_BASE(cpu);
snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d", cpu);
evt->name = mevt->name;
@ -527,8 +528,17 @@ static int __init exynos4_timer_resources(struct device_node *np)
return 0;
}
/**
* exynos4_timer_interrupts - initialize MCT interrupts
* @np: device node for MCT
* @int_type: interrupt type, MCT_INT_PPI or MCT_INT_SPI
* @local_idx: array mapping CPU numbers to local timer indices
* @nr_local: size of @local_idx array
*/
static int __init exynos4_timer_interrupts(struct device_node *np,
unsigned int int_type)
unsigned int int_type,
const u32 *local_idx,
size_t nr_local)
{
int nr_irqs, i, err, cpu;
@ -561,13 +571,21 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
} else {
for_each_possible_cpu(cpu) {
int mct_irq;
unsigned int irq_idx;
struct mct_clock_event_device *pcpu_mevt =
per_cpu_ptr(&percpu_mct_tick, cpu);
if (cpu >= nr_local) {
err = -EINVAL;
goto out_irq;
}
irq_idx = MCT_L0_IRQ + local_idx[cpu];
pcpu_mevt->evt.irq = -1;
if (MCT_L0_IRQ + cpu >= ARRAY_SIZE(mct_irqs))
if (irq_idx >= ARRAY_SIZE(mct_irqs))
break;
mct_irq = mct_irqs[MCT_L0_IRQ + cpu];
mct_irq = mct_irqs[irq_idx];
irq_set_status_flags(mct_irq, IRQ_NOAUTOEN);
if (request_irq(mct_irq,
@ -583,6 +601,17 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
}
}
for_each_possible_cpu(cpu) {
struct mct_clock_event_device *mevt = per_cpu_ptr(&percpu_mct_tick, cpu);
if (cpu >= nr_local) {
err = -EINVAL;
goto out_irq;
}
mevt->base = EXYNOS4_MCT_L_BASE(local_idx[cpu]);
}
/* Install hotplug callbacks which configure the timer on this CPU */
err = cpuhp_setup_state(CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING,
"clockevents/exynos4/mct_timer:starting",
@ -613,13 +642,34 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
static int __init mct_init_dt(struct device_node *np, unsigned int int_type)
{
bool frc_shared = of_property_read_bool(np, "samsung,frc-shared");
u32 local_idx[MCT_NR_LOCAL] = {0};
int nr_local;
int ret;
nr_local = of_property_count_u32_elems(np, "samsung,local-timers");
if (nr_local == 0)
return -EINVAL;
if (nr_local > 0) {
if (nr_local > ARRAY_SIZE(local_idx))
return -EINVAL;
ret = of_property_read_u32_array(np, "samsung,local-timers",
local_idx, nr_local);
if (ret)
return ret;
} else {
int i;
nr_local = ARRAY_SIZE(local_idx);
for (i = 0; i < nr_local; i++)
local_idx[i] = i;
}
ret = exynos4_timer_resources(np);
if (ret)
return ret;
ret = exynos4_timer_interrupts(np, int_type);
ret = exynos4_timer_interrupts(np, int_type, local_idx, nr_local);
if (ret)
return ret;