Commit 47dbe4eb authored by Vincent Whitchurch's avatar Vincent Whitchurch Committed by Daniel Lezcano
Browse files

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: default avatarVincent Whitchurch <vincent.whitchurch@axis.com>
Reviewed-by: default avatarKrzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Link: https://lore.kernel.org/r/20220609112738.359385-4-vincent.whitchurch@axis.com


Signed-off-by: default avatarDaniel Lezcano <daniel.lezcano@linaro.org>
parent e8550f0e
Loading
Loading
Loading
Loading
+56 −6
Original line number Diff line number Diff line
@@ -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;