Skip to content

Commit

Permalink
clocksource/drivers/exynos_mct: Support local-timers property
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Vincent Whitchurch authored and Daniel Lezcano committed Sep 20, 2022
1 parent e8550f0 commit 47dbe4e
Showing 1 changed file with 56 additions and 6 deletions.
62 changes: 56 additions & 6 deletions drivers/clocksource/exynos_mct.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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,
Expand All @@ -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",
Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit 47dbe4e

Please sign in to comment.