Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b09ca1ec authored by Hanjun Guo's avatar Hanjun Guo Committed by Will Deacon
Browse files

clocksource / arch_timer: Parse GTDT to initialize arch timer



Using the information presented by GTDT (Generic Timer Description Table)
to initialize the arch timer (not memory-mapped).

CC: Daniel Lezcano <daniel.lezcano@linaro.org>
CC: Thomas Gleixner <tglx@linutronix.de>
Originally-by: default avatarAmit Daniel Kachhap <amit.daniel@samsung.com>
Tested-by: default avatarSuravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Tested-by: default avatarYijing Wang <wangyijing@huawei.com>
Tested-by: default avatarMark Langsdorf <mlangsdo@redhat.com>
Tested-by: default avatarJon Masters <jcm@redhat.com>
Tested-by: default avatarTimur Tabi <timur@codeaurora.org>
Tested-by: default avatarRobert Richter <rrichter@cavium.com>
Acked-by: default avatarRobert Richter <rrichter@cavium.com>
Acked-by: default avatarDaniel Lezcano <daniel.lezcano@linaro.org>
Reviewed-by: default avatarGrant Likely <grant.likely@linaro.org>
Signed-off-by: default avatarHanjun Guo <hanjun.guo@linaro.org>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent d60fc389
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include <linux/delay.h>
#include <linux/clocksource.h>
#include <linux/clk-provider.h>
#include <linux/acpi.h>

#include <clocksource/arm_arch_timer.h>

@@ -72,6 +73,12 @@ void __init time_init(void)

	tick_setup_hrtimer_broadcast();

	/*
	 * Since ACPI or FDT will only one be available in the system,
	 * we can use acpi_generic_timer_init() here safely
	 */
	acpi_generic_timer_init();

	arch_timer_rate = arch_timer_get_rate();
	if (!arch_timer_rate)
		panic("Unable to initialise architected timer.\n");
+105 −27
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/sched_clock.h>
#include <linux/acpi.h>

#include <asm/arch_timer.h>
#include <asm/virt.h>
@@ -371,8 +372,12 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
	if (arch_timer_rate)
		return;

	/* Try to determine the frequency from the device tree or CNTFRQ */
	if (of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
	/*
	 * Try to determine the frequency from the device tree or CNTFRQ,
	 * if ACPI is enabled, get the frequency from CNTFRQ ONLY.
	 */
	if (!acpi_disabled ||
	    of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
		if (cntbase)
			arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
		else
@@ -691,28 +696,8 @@ static void __init arch_timer_common_init(void)
	arch_timer_arch_init();
}

static void __init arch_timer_init(struct device_node *np)
static void __init arch_timer_init(void)
{
	int i;

	if (arch_timers_present & ARCH_CP15_TIMER) {
		pr_warn("arch_timer: multiple nodes in dt, skipping\n");
		return;
	}

	arch_timers_present |= ARCH_CP15_TIMER;
	for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
		arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
	arch_timer_detect_rate(NULL, np);

	/*
	 * If we cannot rely on firmware initializing the timer registers then
	 * we should use the physical timers instead.
	 */
	if (IS_ENABLED(CONFIG_ARM) &&
	    of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
			arch_timer_use_virtual = false;

	/*
	 * If HYP mode is available, we know that the physical timer
	 * has been configured to be accessible from PL1. Use it, so
@@ -731,13 +716,39 @@ static void __init arch_timer_init(struct device_node *np)
		}
	}

	arch_timer_c3stop = !of_property_read_bool(np, "always-on");

	arch_timer_register();
	arch_timer_common_init();
}
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init);
CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init);

static void __init arch_timer_of_init(struct device_node *np)
{
	int i;

	if (arch_timers_present & ARCH_CP15_TIMER) {
		pr_warn("arch_timer: multiple nodes in dt, skipping\n");
		return;
	}

	arch_timers_present |= ARCH_CP15_TIMER;
	for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
		arch_timer_ppi[i] = irq_of_parse_and_map(np, i);

	arch_timer_detect_rate(NULL, np);

	arch_timer_c3stop = !of_property_read_bool(np, "always-on");

	/*
	 * If we cannot rely on firmware initializing the timer registers then
	 * we should use the physical timers instead.
	 */
	if (IS_ENABLED(CONFIG_ARM) &&
	    of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
			arch_timer_use_virtual = false;

	arch_timer_init();
}
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);

static void __init arch_timer_mem_init(struct device_node *np)
{
@@ -804,3 +815,70 @@ static void __init arch_timer_mem_init(struct device_node *np)
}
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
		       arch_timer_mem_init);

#ifdef CONFIG_ACPI
static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags)
{
	int trigger, polarity;

	if (!interrupt)
		return 0;

	trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE
			: ACPI_LEVEL_SENSITIVE;

	polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW
			: ACPI_ACTIVE_HIGH;

	return acpi_register_gsi(NULL, interrupt, trigger, polarity);
}

/* Initialize per-processor generic timer */
static int __init arch_timer_acpi_init(struct acpi_table_header *table)
{
	struct acpi_table_gtdt *gtdt;

	if (arch_timers_present & ARCH_CP15_TIMER) {
		pr_warn("arch_timer: already initialized, skipping\n");
		return -EINVAL;
	}

	gtdt = container_of(table, struct acpi_table_gtdt, header);

	arch_timers_present |= ARCH_CP15_TIMER;

	arch_timer_ppi[PHYS_SECURE_PPI] =
		map_generic_timer_interrupt(gtdt->secure_el1_interrupt,
		gtdt->secure_el1_flags);

	arch_timer_ppi[PHYS_NONSECURE_PPI] =
		map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt,
		gtdt->non_secure_el1_flags);

	arch_timer_ppi[VIRT_PPI] =
		map_generic_timer_interrupt(gtdt->virtual_timer_interrupt,
		gtdt->virtual_timer_flags);

	arch_timer_ppi[HYP_PPI] =
		map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,
		gtdt->non_secure_el2_flags);

	/* Get the frequency from CNTFRQ */
	arch_timer_detect_rate(NULL, NULL);

	/* Always-on capability */
	arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);

	arch_timer_init();
	return 0;
}

/* Initialize all the generic timers presented in GTDT */
void __init acpi_generic_timer_init(void)
{
	if (acpi_disabled)
		return;

	acpi_table_parse(ACPI_SIG_GTDT, arch_timer_acpi_init);
}
#endif
+6 −0
Original line number Diff line number Diff line
@@ -244,4 +244,10 @@ extern void clocksource_of_init(void);
static inline void clocksource_of_init(void) {}
#endif

#ifdef CONFIG_ACPI
void acpi_generic_timer_init(void);
#else
static inline void acpi_generic_timer_init(void) { }
#endif

#endif /* _LINUX_CLOCKSOURCE_H */