Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer updates from Thomas Gleixner: "The timer department delivers this time: - Support for cross clock domain timestamps in the core code plus a first user. That allows more precise timestamping for PTP and later for audio and other peripherals. The ptp/e1000e patches have been acked by the relevant maintainers and are carried in the timer tree to avoid merge ordering issues. - Support for unregistering the current clocksource watchdog. That lifts a limitation for switching clocksources which has been there from day 1 - The usual pile of fixes and updates to the core and the drivers. Nothing outstanding and exciting" * 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (26 commits) time/timekeeping: Work around false positive GCC warning e1000e: Adds hardware supported cross timestamp on e1000e nic ptp: Add PTP_SYS_OFFSET_PRECISE for driver crosstimestamping x86/tsc: Always Running Timer (ART) correlated clocksource hrtimer: Revert CLOCK_MONOTONIC_RAW support time: Add history to cross timestamp interface supporting slower devices time: Add driver cross timestamp interface for higher precision time synchronization time: Remove duplicated code in ktime_get_raw_and_real() time: Add timekeeping snapshot code capturing system time and counter time: Add cycles to nanoseconds translation jiffies: Use CLOCKSOURCE_MASK instead of constant clocksource: Introduce clocksource_freq2mult() clockevents/drivers/exynos_mct: Implement ->set_state_oneshot_stopped() clockevents/drivers/arm_global_timer: Implement ->set_state_oneshot_stopped() clockevents/drivers/arm_arch_timer: Implement ->set_state_oneshot_stopped() clocksource/drivers/arm_global_timer: Register delay timer clocksource/drivers/lpc32xx: Support timer-based ARM delay clocksource/drivers/lpc32xx: Support periodic mode clocksource/drivers/lpc32xx: Don't use the prescaler counter for clockevents clocksource/drivers/rockchip: Add err handle for rk_timer_init ...
This commit is contained in:
@@ -160,6 +160,7 @@ config CLKSRC_EFM32
|
||||
config CLKSRC_LPC32XX
|
||||
bool "Clocksource for LPC32XX" if COMPILE_TEST
|
||||
depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
|
||||
depends on ARM
|
||||
select CLKSRC_MMIO
|
||||
select CLKSRC_OF
|
||||
help
|
||||
|
@@ -32,6 +32,14 @@
|
||||
#define CNTTIDR 0x08
|
||||
#define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4))
|
||||
|
||||
#define CNTACR(n) (0x40 + ((n) * 4))
|
||||
#define CNTACR_RPCT BIT(0)
|
||||
#define CNTACR_RVCT BIT(1)
|
||||
#define CNTACR_RFRQ BIT(2)
|
||||
#define CNTACR_RVOFF BIT(3)
|
||||
#define CNTACR_RWVT BIT(4)
|
||||
#define CNTACR_RWPT BIT(5)
|
||||
|
||||
#define CNTVCT_LO 0x08
|
||||
#define CNTVCT_HI 0x0c
|
||||
#define CNTFRQ 0x10
|
||||
@@ -266,10 +274,12 @@ static void __arch_timer_setup(unsigned type,
|
||||
if (arch_timer_use_virtual) {
|
||||
clk->irq = arch_timer_ppi[VIRT_PPI];
|
||||
clk->set_state_shutdown = arch_timer_shutdown_virt;
|
||||
clk->set_state_oneshot_stopped = arch_timer_shutdown_virt;
|
||||
clk->set_next_event = arch_timer_set_next_event_virt;
|
||||
} else {
|
||||
clk->irq = arch_timer_ppi[PHYS_SECURE_PPI];
|
||||
clk->set_state_shutdown = arch_timer_shutdown_phys;
|
||||
clk->set_state_oneshot_stopped = arch_timer_shutdown_phys;
|
||||
clk->set_next_event = arch_timer_set_next_event_phys;
|
||||
}
|
||||
} else {
|
||||
@@ -279,10 +289,12 @@ static void __arch_timer_setup(unsigned type,
|
||||
clk->cpumask = cpu_all_mask;
|
||||
if (arch_timer_mem_use_virtual) {
|
||||
clk->set_state_shutdown = arch_timer_shutdown_virt_mem;
|
||||
clk->set_state_oneshot_stopped = arch_timer_shutdown_virt_mem;
|
||||
clk->set_next_event =
|
||||
arch_timer_set_next_event_virt_mem;
|
||||
} else {
|
||||
clk->set_state_shutdown = arch_timer_shutdown_phys_mem;
|
||||
clk->set_state_oneshot_stopped = arch_timer_shutdown_phys_mem;
|
||||
clk->set_next_event =
|
||||
arch_timer_set_next_event_phys_mem;
|
||||
}
|
||||
@@ -757,7 +769,6 @@ static void __init arch_timer_mem_init(struct device_node *np)
|
||||
}
|
||||
|
||||
cnttidr = readl_relaxed(cntctlbase + CNTTIDR);
|
||||
iounmap(cntctlbase);
|
||||
|
||||
/*
|
||||
* Try to find a virtual capable frame. Otherwise fall back to a
|
||||
@@ -765,20 +776,31 @@ static void __init arch_timer_mem_init(struct device_node *np)
|
||||
*/
|
||||
for_each_available_child_of_node(np, frame) {
|
||||
int n;
|
||||
u32 cntacr;
|
||||
|
||||
if (of_property_read_u32(frame, "frame-number", &n)) {
|
||||
pr_err("arch_timer: Missing frame-number\n");
|
||||
of_node_put(best_frame);
|
||||
of_node_put(frame);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (cnttidr & CNTTIDR_VIRT(n)) {
|
||||
/* Try enabling everything, and see what sticks */
|
||||
cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT |
|
||||
CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT;
|
||||
writel_relaxed(cntacr, cntctlbase + CNTACR(n));
|
||||
cntacr = readl_relaxed(cntctlbase + CNTACR(n));
|
||||
|
||||
if ((cnttidr & CNTTIDR_VIRT(n)) &&
|
||||
!(~cntacr & (CNTACR_RWVT | CNTACR_RVCT))) {
|
||||
of_node_put(best_frame);
|
||||
best_frame = frame;
|
||||
arch_timer_mem_use_virtual = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT))
|
||||
continue;
|
||||
|
||||
of_node_put(best_frame);
|
||||
best_frame = of_node_get(frame);
|
||||
}
|
||||
@@ -786,24 +808,26 @@ static void __init arch_timer_mem_init(struct device_node *np)
|
||||
base = arch_counter_base = of_iomap(best_frame, 0);
|
||||
if (!base) {
|
||||
pr_err("arch_timer: Can't map frame's registers\n");
|
||||
of_node_put(best_frame);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (arch_timer_mem_use_virtual)
|
||||
irq = irq_of_parse_and_map(best_frame, 1);
|
||||
else
|
||||
irq = irq_of_parse_and_map(best_frame, 0);
|
||||
of_node_put(best_frame);
|
||||
|
||||
if (!irq) {
|
||||
pr_err("arch_timer: Frame missing %s irq",
|
||||
arch_timer_mem_use_virtual ? "virt" : "phys");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
arch_timer_detect_rate(base, np);
|
||||
arch_timer_mem_register(base, irq);
|
||||
arch_timer_common_init();
|
||||
out:
|
||||
iounmap(cntctlbase);
|
||||
of_node_put(best_frame);
|
||||
}
|
||||
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
|
||||
arch_timer_mem_init);
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
@@ -174,6 +175,7 @@ static int gt_clockevents_init(struct clock_event_device *clk)
|
||||
clk->set_state_shutdown = gt_clockevent_shutdown;
|
||||
clk->set_state_periodic = gt_clockevent_set_periodic;
|
||||
clk->set_state_oneshot = gt_clockevent_shutdown;
|
||||
clk->set_state_oneshot_stopped = gt_clockevent_shutdown;
|
||||
clk->set_next_event = gt_clockevent_set_next_event;
|
||||
clk->cpumask = cpumask_of(cpu);
|
||||
clk->rating = 300;
|
||||
@@ -221,6 +223,21 @@ static u64 notrace gt_sched_clock_read(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned long gt_read_long(void)
|
||||
{
|
||||
return readl_relaxed(gt_base + GT_COUNTER0);
|
||||
}
|
||||
|
||||
static struct delay_timer gt_delay_timer = {
|
||||
.read_current_timer = gt_read_long,
|
||||
};
|
||||
|
||||
static void __init gt_delay_timer_init(void)
|
||||
{
|
||||
gt_delay_timer.freq = gt_clk_rate;
|
||||
register_current_timer_delay(>_delay_timer);
|
||||
}
|
||||
|
||||
static void __init gt_clocksource_init(void)
|
||||
{
|
||||
writel(0, gt_base + GT_CONTROL);
|
||||
@@ -317,6 +334,7 @@ static void __init global_timer_of_register(struct device_node *np)
|
||||
/* Immediately configure the timer on the boot CPU */
|
||||
gt_clocksource_init();
|
||||
gt_clockevents_init(this_cpu_ptr(gt_evt));
|
||||
gt_delay_timer_init();
|
||||
|
||||
return;
|
||||
|
||||
|
@@ -313,6 +313,7 @@ static struct clock_event_device mct_comp_device = {
|
||||
.set_state_periodic = mct_set_state_periodic,
|
||||
.set_state_shutdown = mct_set_state_shutdown,
|
||||
.set_state_oneshot = mct_set_state_shutdown,
|
||||
.set_state_oneshot_stopped = mct_set_state_shutdown,
|
||||
.tick_resume = mct_set_state_shutdown,
|
||||
};
|
||||
|
||||
@@ -452,6 +453,7 @@ static int exynos4_local_timer_setup(struct mct_clock_event_device *mevt)
|
||||
evt->set_state_periodic = set_state_periodic;
|
||||
evt->set_state_shutdown = set_state_shutdown;
|
||||
evt->set_state_oneshot = set_state_shutdown;
|
||||
evt->set_state_oneshot_stopped = set_state_shutdown;
|
||||
evt->tick_resume = set_state_shutdown;
|
||||
evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
|
||||
evt->rating = 450;
|
||||
|
@@ -122,23 +122,23 @@ static void __init rk_timer_init(struct device_node *np)
|
||||
pclk = of_clk_get_by_name(np, "pclk");
|
||||
if (IS_ERR(pclk)) {
|
||||
pr_err("Failed to get pclk for '%s'\n", TIMER_NAME);
|
||||
return;
|
||||
goto out_unmap;
|
||||
}
|
||||
|
||||
if (clk_prepare_enable(pclk)) {
|
||||
pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME);
|
||||
return;
|
||||
goto out_unmap;
|
||||
}
|
||||
|
||||
timer_clk = of_clk_get_by_name(np, "timer");
|
||||
if (IS_ERR(timer_clk)) {
|
||||
pr_err("Failed to get timer clock for '%s'\n", TIMER_NAME);
|
||||
return;
|
||||
goto out_timer_clk;
|
||||
}
|
||||
|
||||
if (clk_prepare_enable(timer_clk)) {
|
||||
pr_err("Failed to enable timer clock\n");
|
||||
return;
|
||||
goto out_timer_clk;
|
||||
}
|
||||
|
||||
bc_timer.freq = clk_get_rate(timer_clk);
|
||||
@@ -146,7 +146,7 @@ static void __init rk_timer_init(struct device_node *np)
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (!irq) {
|
||||
pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME);
|
||||
return;
|
||||
goto out_irq;
|
||||
}
|
||||
|
||||
ce->name = TIMER_NAME;
|
||||
@@ -164,10 +164,19 @@ static void __init rk_timer_init(struct device_node *np)
|
||||
ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
|
||||
if (ret) {
|
||||
pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret);
|
||||
return;
|
||||
goto out_irq;
|
||||
}
|
||||
|
||||
clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX);
|
||||
|
||||
return;
|
||||
|
||||
out_irq:
|
||||
clk_disable_unprepare(timer_clk);
|
||||
out_timer_clk:
|
||||
clk_disable_unprepare(pclk);
|
||||
out_unmap:
|
||||
iounmap(bc_timer.base);
|
||||
}
|
||||
|
||||
CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -43,6 +44,7 @@
|
||||
struct lpc32xx_clock_event_ddata {
|
||||
struct clock_event_device evtdev;
|
||||
void __iomem *base;
|
||||
u32 ticks_per_jiffy;
|
||||
};
|
||||
|
||||
/* Needed for the sched clock */
|
||||
@@ -53,6 +55,15 @@ static u64 notrace lpc32xx_read_sched_clock(void)
|
||||
return readl(clocksource_timer_counter);
|
||||
}
|
||||
|
||||
static unsigned long lpc32xx_delay_timer_read(void)
|
||||
{
|
||||
return readl(clocksource_timer_counter);
|
||||
}
|
||||
|
||||
static struct delay_timer lpc32xx_delay_timer = {
|
||||
.read_current_timer = lpc32xx_delay_timer_read,
|
||||
};
|
||||
|
||||
static int lpc32xx_clkevt_next_event(unsigned long delta,
|
||||
struct clock_event_device *evtdev)
|
||||
{
|
||||
@@ -60,14 +71,13 @@ static int lpc32xx_clkevt_next_event(unsigned long delta,
|
||||
container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
|
||||
|
||||
/*
|
||||
* Place timer in reset and program the delta in the prescale
|
||||
* register (PR). When the prescale counter matches the value
|
||||
* in PR the counter register is incremented and the compare
|
||||
* match will trigger. After setup the timer is released from
|
||||
* reset and enabled.
|
||||
* Place timer in reset and program the delta in the match
|
||||
* channel 0 (MR0). When the timer counter matches the value
|
||||
* in MR0 register the match will trigger an interrupt.
|
||||
* After setup the timer is released from reset and enabled.
|
||||
*/
|
||||
writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR);
|
||||
writel_relaxed(delta, ddata->base + LPC32XX_TIMER_PR);
|
||||
writel_relaxed(delta, ddata->base + LPC32XX_TIMER_MR0);
|
||||
writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR);
|
||||
|
||||
return 0;
|
||||
@@ -86,11 +96,39 @@ static int lpc32xx_clkevt_shutdown(struct clock_event_device *evtdev)
|
||||
|
||||
static int lpc32xx_clkevt_oneshot(struct clock_event_device *evtdev)
|
||||
{
|
||||
struct lpc32xx_clock_event_ddata *ddata =
|
||||
container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
|
||||
|
||||
/*
|
||||
* When using oneshot, we must also disable the timer
|
||||
* to wait for the first call to set_next_event().
|
||||
*/
|
||||
return lpc32xx_clkevt_shutdown(evtdev);
|
||||
writel_relaxed(0, ddata->base + LPC32XX_TIMER_TCR);
|
||||
|
||||
/* Enable interrupt, reset on match and stop on match (MCR). */
|
||||
writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R |
|
||||
LPC32XX_TIMER_MCR_MR0S, ddata->base + LPC32XX_TIMER_MCR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_clkevt_periodic(struct clock_event_device *evtdev)
|
||||
{
|
||||
struct lpc32xx_clock_event_ddata *ddata =
|
||||
container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
|
||||
|
||||
/* Enable interrupt and reset on match. */
|
||||
writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R,
|
||||
ddata->base + LPC32XX_TIMER_MCR);
|
||||
|
||||
/*
|
||||
* Place timer in reset and program the delta in the match
|
||||
* channel 0 (MR0).
|
||||
*/
|
||||
writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR);
|
||||
writel_relaxed(ddata->ticks_per_jiffy, ddata->base + LPC32XX_TIMER_MR0);
|
||||
writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t lpc32xx_clock_event_handler(int irq, void *dev_id)
|
||||
@@ -108,11 +146,13 @@ static irqreturn_t lpc32xx_clock_event_handler(int irq, void *dev_id)
|
||||
static struct lpc32xx_clock_event_ddata lpc32xx_clk_event_ddata = {
|
||||
.evtdev = {
|
||||
.name = "lpc3220 clockevent",
|
||||
.features = CLOCK_EVT_FEAT_ONESHOT,
|
||||
.features = CLOCK_EVT_FEAT_ONESHOT |
|
||||
CLOCK_EVT_FEAT_PERIODIC,
|
||||
.rating = 300,
|
||||
.set_next_event = lpc32xx_clkevt_next_event,
|
||||
.set_state_shutdown = lpc32xx_clkevt_shutdown,
|
||||
.set_state_oneshot = lpc32xx_clkevt_oneshot,
|
||||
.set_state_periodic = lpc32xx_clkevt_periodic,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -162,6 +202,8 @@ static int __init lpc32xx_clocksource_init(struct device_node *np)
|
||||
}
|
||||
|
||||
clocksource_timer_counter = base + LPC32XX_TIMER_TC;
|
||||
lpc32xx_delay_timer.freq = rate;
|
||||
register_current_timer_delay(&lpc32xx_delay_timer);
|
||||
sched_clock_register(lpc32xx_read_sched_clock, 32, rate);
|
||||
|
||||
return 0;
|
||||
@@ -210,18 +252,16 @@ static int __init lpc32xx_clockevent_init(struct device_node *np)
|
||||
|
||||
/*
|
||||
* Disable timer and clear any pending interrupt (IR) on match
|
||||
* channel 0 (MR0). Configure a compare match value of 1 on MR0
|
||||
* and enable interrupt, reset on match and stop on match (MCR).
|
||||
* channel 0 (MR0). Clear the prescaler as it's not used.
|
||||
*/
|
||||
writel_relaxed(0, base + LPC32XX_TIMER_TCR);
|
||||
writel_relaxed(0, base + LPC32XX_TIMER_PR);
|
||||
writel_relaxed(0, base + LPC32XX_TIMER_CTCR);
|
||||
writel_relaxed(LPC32XX_TIMER_IR_MR0INT, base + LPC32XX_TIMER_IR);
|
||||
writel_relaxed(1, base + LPC32XX_TIMER_MR0);
|
||||
writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R |
|
||||
LPC32XX_TIMER_MCR_MR0S, base + LPC32XX_TIMER_MCR);
|
||||
|
||||
rate = clk_get_rate(clk);
|
||||
lpc32xx_clk_event_ddata.base = base;
|
||||
lpc32xx_clk_event_ddata.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);
|
||||
clockevents_config_and_register(&lpc32xx_clk_event_ddata.evtdev,
|
||||
rate, 1, -1);
|
||||
|
||||
|
Reference in New Issue
Block a user