Skip to content

Commit

Permalink
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/sc…
Browse files Browse the repository at this point in the history
…m/linux/kernel/git/tip/tip

Pull clocksource updates from Ingo Molnar:
 "Misc clocksource/clockevent driver updates that came in a bit late but
  are ready for v5.2"

* 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  misc: atmel_tclib: Do not probe already used TCBs
  clocksource/drivers/timer-atmel-tcb: Convert tc_clksrc_suspend|resume() to static
  clocksource/drivers/tcb_clksrc: Rename the file for consistency
  clocksource/drivers/timer-atmel-pit: Rework Kconfig option
  clocksource/drivers/tcb_clksrc: Move Kconfig option
  ARM: at91: Implement clocksource selection
  clocksource/drivers/tcb_clksrc: Use tcb as sched_clock
  clocksource/drivers/tcb_clksrc: Stop depending on atmel_tclib
  ARM: at91: move SoC specific definitions to SoC folder
  clocksource/drivers/timer-milbeaut: Cleanup common register accesses
  clocksource/drivers/timer-milbeaut: Add shutdown function
  clocksource/drivers/timer-milbeaut: Fix to enable one-shot timer
  clocksource/drivers/tegra: Rework for compensation of suspend time
  clocksource/drivers/sp804: Add COMPILE_TEST to CONFIG_ARM_TIMER_SP804
  clocksource/drivers/sun4i: Add a compatible for suniv
  dt-bindings: timer: Add Allwinner suniv timer
  • Loading branch information
torvalds committed May 19, 2019
2 parents d9351ea + ea7a5f9 commit a13f950
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 136 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
23 changes: 23 additions & 0 deletions arch/arm/mach-at91/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,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

Expand Down
14 changes: 12 additions & 2 deletions drivers/clocksource/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,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
Expand All @@ -407,8 +407,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
Expand All @@ -418,6 +421,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
Expand Down
2 changes: 1 addition & 1 deletion drivers/clocksource/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>


/*
Expand All @@ -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.
Expand Down Expand Up @@ -112,7 +107,6 @@ static void tc_clksrc_resume(struct clocksource *cs)
}

static struct clocksource clksrc = {
.name = "tcb_clksrc",
.rating = 200,
.read = tc_get_cycles,
.mask = CLOCKSOURCE_MASK(32),
Expand All @@ -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 {
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand All @@ -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! */
Expand All @@ -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

0 comments on commit a13f950

Please sign in to comment.