Commit ea7a5f90 authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

Merge tag 'timers-v5.2' of http://git.linaro.org/people/daniel.lezcano/linux into timers/core

Pull clockevent updates from Daniel Lezcano:

 - Add compatible string for suniv for sun4i (Mesih Kilinc)

 - Add COMPILE_TEST option for sp804 (David Abdurachmanov)

 - Replace the compensation time when suspend happens on tegra with the one
   provided by the generic framework (Joseph Lo)

 - Cleanup, shutdown and oneshot mode fix on milbeaut timer (Sugaya Taichi)

 - Atmel TCB rework to fix boot failure on boards without PIT or misfunction
   on system using a preempt-rt kernel (Alexandre Belloni)
parents 13e792a1 8c937406
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -2,7 +2,9 @@ Allwinner A1X SoCs Timer Controller

Required properties:

- compatible : should be "allwinner,sun4i-a10-timer"
- compatible : should be one of the following:
              "allwinner,sun4i-a10-timer"
              "allwinner,suniv-f1c100s-timer"
- reg : Specifies base physical address and size of the registers.
- interrupts : The interrupt of the first timer
- clocks: phandle to the source clock (usually a 24 MHz fixed clock)
+23 −0
Original line number Diff line number Diff line
@@ -107,6 +107,29 @@ config SOC_AT91SAM9
	    AT91SAM9X35
	    AT91SAM9XE

comment "Clocksource driver selection"

config ATMEL_CLOCKSOURCE_PIT
	bool "Periodic Interval Timer (PIT) support"
	depends on SOC_AT91SAM9 || SOC_SAMA5
	default SOC_AT91SAM9 || SOC_SAMA5
	select ATMEL_PIT
	help
	  Select this to get a clocksource based on the Atmel Periodic Interval
	  Timer. It has a relatively low resolution and the TC Block clocksource
	  should be preferred.

config ATMEL_CLOCKSOURCE_TCB
	bool "Timer Counter Blocks (TCB) support"
	default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
	select ATMEL_TCB_CLKSRC
	help
	  Select this to get a high precision clocksource based on a
	  TC block with a 5+ MHz base clock rate.
	  On platforms with 16-bit counters, two timer channels are combined
	  to make a single 32-bit timer.
	  It can also be used as a clock event device supporting oneshot mode.

config HAVE_AT91_UTMI
	bool

+12 −2
Original line number Diff line number Diff line
@@ -379,7 +379,7 @@ config ARM_GLOBAL_TIMER
	  This options enables support for the ARM global timer unit

config ARM_TIMER_SP804
	bool "Support for Dual Timer SP804 module"
	bool "Support for Dual Timer SP804 module" if COMPILE_TEST
	depends on GENERIC_SCHED_CLOCK && CLKDEV_LOOKUP
	select CLKSRC_MMIO
	select TIMER_OF if OF
@@ -399,8 +399,11 @@ config ARMV7M_SYSTICK
	  This options enables support for the ARMv7M system timer unit

config ATMEL_PIT
	bool "Atmel PIT support" if COMPILE_TEST
	depends on HAS_IOMEM
	select TIMER_OF if OF
	def_bool SOC_AT91SAM9 || SOC_SAMA5
	help
	  Support for the Periodic Interval Timer found on Atmel SoCs.

config ATMEL_ST
	bool "Atmel ST timer support" if COMPILE_TEST
@@ -410,6 +413,13 @@ config ATMEL_ST
	help
	  Support for the Atmel ST timer.

config ATMEL_TCB_CLKSRC
	bool "Atmel TC Block timer driver" if COMPILE_TEST
	depends on HAS_IOMEM
	select TIMER_OF if OF
	help
	  Support for Timer Counter Blocks on Atmel SoCs.

config CLKSRC_EXYNOS_MCT
	bool "Exynos multi core timer driver" if COMPILE_TEST
	depends on ARM || ARM64
+1 −1
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@ obj-$(CONFIG_TIMER_OF) += timer-of.o
obj-$(CONFIG_TIMER_PROBE)	+= timer-probe.o
obj-$(CONFIG_ATMEL_PIT)		+= timer-atmel-pit.o
obj-$(CONFIG_ATMEL_ST)		+= timer-atmel-st.o
obj-$(CONFIG_ATMEL_TCB_CLKSRC)	+= tcb_clksrc.o
obj-$(CONFIG_ATMEL_TCB_CLKSRC)	+= timer-atmel-tcb.o
obj-$(CONFIG_X86_PM_TIMER)	+= acpi_pm.o
obj-$(CONFIG_SCx200HR_TIMER)	+= scx200_hrt.o
obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC)	+= timer-cs5535.o
+87 −43
Original line number Diff line number Diff line
@@ -9,9 +9,11 @@
#include <linux/err.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
#include <linux/syscore_ops.h>
#include <linux/atmel_tc.h>
#include <soc/at91/atmel_tcb.h>


/*
@@ -28,13 +30,6 @@
 *     source, used in either periodic or oneshot mode.  This runs
 *     at 32 KiHZ, and can handle delays of up to two seconds.
 *
 * A boot clocksource and clockevent source are also currently needed,
 * unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so
 * this code can be used when init_timers() is called, well before most
 * devices are set up.  (Some low end AT91 parts, which can run uClinux,
 * have only the timers in one TC block... they currently don't support
 * the tclib code, because of that initialization issue.)
 *
 * REVISIT behavior during system suspend states... we should disable
 * all clocks and save the power.  Easily done for clockevent devices,
 * but clocksources won't necessarily get the needed notifications.
@@ -71,7 +66,7 @@ static u64 tc_get_cycles32(struct clocksource *cs)
	return readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV));
}

void tc_clksrc_suspend(struct clocksource *cs)
static void tc_clksrc_suspend(struct clocksource *cs)
{
	int i;

@@ -86,7 +81,7 @@ void tc_clksrc_suspend(struct clocksource *cs)
	bmr_cache = readl(tcaddr + ATMEL_TC_BMR);
}

void tc_clksrc_resume(struct clocksource *cs)
static void tc_clksrc_resume(struct clocksource *cs)
{
	int i;

@@ -112,7 +107,6 @@ void tc_clksrc_resume(struct clocksource *cs)
}

static struct clocksource clksrc = {
	.name           = "tcb_clksrc",
	.rating         = 200,
	.read           = tc_get_cycles,
	.mask           = CLOCKSOURCE_MASK(32),
@@ -121,6 +115,16 @@ static struct clocksource clksrc = {
	.resume		= tc_clksrc_resume,
};

static u64 notrace tc_sched_clock_read(void)
{
	return tc_get_cycles(&clksrc);
}

static u64 notrace tc_sched_clock_read32(void)
{
	return tc_get_cycles32(&clksrc);
}

#ifdef CONFIG_GENERIC_CLOCKEVENTS

struct tc_clkevt_device {
@@ -214,7 +218,6 @@ static int tc_next_event(unsigned long delta, struct clock_event_device *d)

static struct tc_clkevt_device clkevt = {
	.clkevt	= {
		.name			= "tc_clkevt",
		.features		= CLOCK_EVT_FEAT_PERIODIC |
					  CLOCK_EVT_FEAT_ONESHOT,
		/* Should be lower than at91rm9200's system timer */
@@ -330,39 +333,74 @@ static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_id
	writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
}

static int __init tcb_clksrc_init(void)
{
	static char bootinfo[] __initdata
		= KERN_DEBUG "%s: tc%d at %d.%03d MHz\n";
static const u8 atmel_tcb_divisors[5] = { 2, 8, 32, 128, 0, };

static const struct of_device_id atmel_tcb_of_match[] = {
	{ .compatible = "atmel,at91rm9200-tcb", .data = (void *)16, },
	{ .compatible = "atmel,at91sam9x5-tcb", .data = (void *)32, },
	{ /* sentinel */ }
};

	struct platform_device *pdev;
	struct atmel_tc *tc;
static int __init tcb_clksrc_init(struct device_node *node)
{
	struct atmel_tc tc;
	struct clk *t0_clk;
	const struct of_device_id *match;
	u64 (*tc_sched_clock)(void);
	u32 rate, divided_rate = 0;
	int best_divisor_idx = -1;
	int clk32k_divisor_idx = -1;
	int bits;
	int i;
	int ret;

	tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK);
	if (!tc) {
		pr_debug("can't alloc TC for clocksource\n");
		return -ENODEV;
	/* Protect against multiple calls */
	if (tcaddr)
		return 0;

	tc.regs = of_iomap(node->parent, 0);
	if (!tc.regs)
		return -ENXIO;

	t0_clk = of_clk_get_by_name(node->parent, "t0_clk");
	if (IS_ERR(t0_clk))
		return PTR_ERR(t0_clk);

	tc.slow_clk = of_clk_get_by_name(node->parent, "slow_clk");
	if (IS_ERR(tc.slow_clk))
		return PTR_ERR(tc.slow_clk);

	tc.clk[0] = t0_clk;
	tc.clk[1] = of_clk_get_by_name(node->parent, "t1_clk");
	if (IS_ERR(tc.clk[1]))
		tc.clk[1] = t0_clk;
	tc.clk[2] = of_clk_get_by_name(node->parent, "t2_clk");
	if (IS_ERR(tc.clk[2]))
		tc.clk[2] = t0_clk;

	tc.irq[2] = of_irq_get(node->parent, 2);
	if (tc.irq[2] <= 0) {
		tc.irq[2] = of_irq_get(node->parent, 0);
		if (tc.irq[2] <= 0)
			return -EINVAL;
	}
	tcaddr = tc->regs;
	pdev = tc->pdev;

	t0_clk = tc->clk[0];
	match = of_match_node(atmel_tcb_of_match, node->parent);
	bits = (uintptr_t)match->data;

	for (i = 0; i < ARRAY_SIZE(tc.irq); i++)
		writel(ATMEL_TC_ALL_IRQ, tc.regs + ATMEL_TC_REG(i, IDR));

	ret = clk_prepare_enable(t0_clk);
	if (ret) {
		pr_debug("can't enable T0 clk\n");
		goto err_free_tc;
		return ret;
	}

	/* How fast will we be counting?  Pick something over 5 MHz.  */
	rate = (u32) clk_get_rate(t0_clk);
	for (i = 0; i < 5; i++) {
		unsigned divisor = atmel_tc_divisors[i];
	for (i = 0; i < ARRAY_SIZE(atmel_tcb_divisors); i++) {
		unsigned divisor = atmel_tcb_divisors[i];
		unsigned tmp;

		/* remember 32 KiHz clock for later */
@@ -381,27 +419,31 @@ static int __init tcb_clksrc_init(void)
		best_divisor_idx = i;
	}


	printk(bootinfo, clksrc.name, CONFIG_ATMEL_TCB_CLKSRC_BLOCK,
			divided_rate / 1000000,
	clksrc.name = kbasename(node->parent->full_name);
	clkevt.clkevt.name = kbasename(node->parent->full_name);
	pr_debug("%s at %d.%03d MHz\n", clksrc.name, divided_rate / 1000000,
			((divided_rate % 1000000) + 500) / 1000);

	if (tc->tcb_config && tc->tcb_config->counter_width == 32) {
	tcaddr = tc.regs;

	if (bits == 32) {
		/* use apropriate function to read 32 bit counter */
		clksrc.read = tc_get_cycles32;
		/* setup ony channel 0 */
		tcb_setup_single_chan(tc, best_divisor_idx);
		tcb_setup_single_chan(&tc, best_divisor_idx);
		tc_sched_clock = tc_sched_clock_read32;
	} else {
		/* tclib will give us three clocks no matter what the
		/* we have three clocks no matter what the
		 * underlying platform supports.
		 */
		ret = clk_prepare_enable(tc->clk[1]);
		ret = clk_prepare_enable(tc.clk[1]);
		if (ret) {
			pr_debug("can't enable T1 clk\n");
			goto err_disable_t0;
		}
		/* setup both channel 0 & 1 */
		tcb_setup_dual_chan(tc, best_divisor_idx);
		tcb_setup_dual_chan(&tc, best_divisor_idx);
		tc_sched_clock = tc_sched_clock_read;
	}

	/* and away we go! */
@@ -410,24 +452,26 @@ static int __init tcb_clksrc_init(void)
		goto err_disable_t1;

	/* channel 2:  periodic and oneshot timer support */
	ret = setup_clkevents(tc, clk32k_divisor_idx);
	ret = setup_clkevents(&tc, clk32k_divisor_idx);
	if (ret)
		goto err_unregister_clksrc;

	sched_clock_register(tc_sched_clock, 32, divided_rate);

	return 0;

err_unregister_clksrc:
	clocksource_unregister(&clksrc);

err_disable_t1:
	if (!tc->tcb_config || tc->tcb_config->counter_width != 32)
		clk_disable_unprepare(tc->clk[1]);
	if (bits != 32)
		clk_disable_unprepare(tc.clk[1]);

err_disable_t0:
	clk_disable_unprepare(t0_clk);

err_free_tc:
	atmel_tc_free(tc);
	tcaddr = NULL;

	return ret;
}
arch_initcall(tcb_clksrc_init);
TIMER_OF_DECLARE(atmel_tcb_clksrc, "atmel,tcb-timer", tcb_clksrc_init);
Loading