mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-02 15:18:19 +00:00
clocksource/drivers/timer-ti-dm: Prepare to handle dra7 timer wrap issue
There is a timer wrap issue on dra7 for the ARM architected timer. In a typical clock configuration the timer fails to wrap after 388 days. To work around the issue, we need to use timer-ti-dm timers instead. Let's prepare for adding support for percpu timers by adding a common dmtimer_clkevt_init_common() and call it from dmtimer_clockevent_init(). This patch makes no intentional functional changes. Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> Link: https://lore.kernel.org/r/20210323074326.28302-2-tony@atomide.com
This commit is contained in:
parent
397dc6f7ca
commit
3efe7a878a
1 changed files with 47 additions and 27 deletions
|
@ -530,17 +530,17 @@ static void omap_clockevent_unidle(struct clock_event_device *evt)
|
||||||
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup);
|
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init dmtimer_clockevent_init(struct device_node *np)
|
static int __init dmtimer_clkevt_init_common(struct dmtimer_clockevent *clkevt,
|
||||||
|
struct device_node *np,
|
||||||
|
unsigned int features,
|
||||||
|
const struct cpumask *cpumask,
|
||||||
|
const char *name,
|
||||||
|
int rating)
|
||||||
{
|
{
|
||||||
struct dmtimer_clockevent *clkevt;
|
|
||||||
struct clock_event_device *dev;
|
struct clock_event_device *dev;
|
||||||
struct dmtimer_systimer *t;
|
struct dmtimer_systimer *t;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL);
|
|
||||||
if (!clkevt)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
t = &clkevt->t;
|
t = &clkevt->t;
|
||||||
dev = &clkevt->dev;
|
dev = &clkevt->dev;
|
||||||
|
|
||||||
|
@ -548,25 +548,23 @@ static int __init dmtimer_clockevent_init(struct device_node *np)
|
||||||
* We mostly use cpuidle_coupled with ARM local timers for runtime,
|
* We mostly use cpuidle_coupled with ARM local timers for runtime,
|
||||||
* so there's probably no use for CLOCK_EVT_FEAT_DYNIRQ here.
|
* so there's probably no use for CLOCK_EVT_FEAT_DYNIRQ here.
|
||||||
*/
|
*/
|
||||||
dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
|
dev->features = features;
|
||||||
dev->rating = 300;
|
dev->rating = rating;
|
||||||
dev->set_next_event = dmtimer_set_next_event;
|
dev->set_next_event = dmtimer_set_next_event;
|
||||||
dev->set_state_shutdown = dmtimer_clockevent_shutdown;
|
dev->set_state_shutdown = dmtimer_clockevent_shutdown;
|
||||||
dev->set_state_periodic = dmtimer_set_periodic;
|
dev->set_state_periodic = dmtimer_set_periodic;
|
||||||
dev->set_state_oneshot = dmtimer_clockevent_shutdown;
|
dev->set_state_oneshot = dmtimer_clockevent_shutdown;
|
||||||
dev->set_state_oneshot_stopped = dmtimer_clockevent_shutdown;
|
dev->set_state_oneshot_stopped = dmtimer_clockevent_shutdown;
|
||||||
dev->tick_resume = dmtimer_clockevent_shutdown;
|
dev->tick_resume = dmtimer_clockevent_shutdown;
|
||||||
dev->cpumask = cpu_possible_mask;
|
dev->cpumask = cpumask;
|
||||||
|
|
||||||
dev->irq = irq_of_parse_and_map(np, 0);
|
dev->irq = irq_of_parse_and_map(np, 0);
|
||||||
if (!dev->irq) {
|
if (!dev->irq)
|
||||||
error = -ENXIO;
|
return -ENXIO;
|
||||||
goto err_out_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = dmtimer_systimer_setup(np, &clkevt->t);
|
error = dmtimer_systimer_setup(np, &clkevt->t);
|
||||||
if (error)
|
if (error)
|
||||||
goto err_out_free;
|
return error;
|
||||||
|
|
||||||
clkevt->period = 0xffffffff - DIV_ROUND_CLOSEST(t->rate, HZ);
|
clkevt->period = 0xffffffff - DIV_ROUND_CLOSEST(t->rate, HZ);
|
||||||
|
|
||||||
|
@ -578,32 +576,54 @@ static int __init dmtimer_clockevent_init(struct device_node *np)
|
||||||
writel_relaxed(OMAP_TIMER_CTRL_POSTED, t->base + t->ifctrl);
|
writel_relaxed(OMAP_TIMER_CTRL_POSTED, t->base + t->ifctrl);
|
||||||
|
|
||||||
error = request_irq(dev->irq, dmtimer_clockevent_interrupt,
|
error = request_irq(dev->irq, dmtimer_clockevent_interrupt,
|
||||||
IRQF_TIMER, "clockevent", clkevt);
|
IRQF_TIMER, name, clkevt);
|
||||||
if (error)
|
if (error)
|
||||||
goto err_out_unmap;
|
goto err_out_unmap;
|
||||||
|
|
||||||
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena);
|
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena);
|
||||||
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup);
|
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup);
|
||||||
|
|
||||||
pr_info("TI gptimer clockevent: %s%lu Hz at %pOF\n",
|
pr_info("TI gptimer %s: %s%lu Hz at %pOF\n",
|
||||||
of_find_property(np, "ti,timer-alwon", NULL) ?
|
name, of_find_property(np, "ti,timer-alwon", NULL) ?
|
||||||
"always-on " : "", t->rate, np->parent);
|
"always-on " : "", t->rate, np->parent);
|
||||||
|
|
||||||
clockevents_config_and_register(dev, t->rate,
|
|
||||||
3, /* Timer internal resync latency */
|
|
||||||
0xffffffff);
|
|
||||||
|
|
||||||
if (of_machine_is_compatible("ti,am33xx") ||
|
|
||||||
of_machine_is_compatible("ti,am43")) {
|
|
||||||
dev->suspend = omap_clockevent_idle;
|
|
||||||
dev->resume = omap_clockevent_unidle;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_out_unmap:
|
err_out_unmap:
|
||||||
iounmap(t->base);
|
iounmap(t->base);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init dmtimer_clockevent_init(struct device_node *np)
|
||||||
|
{
|
||||||
|
struct dmtimer_clockevent *clkevt;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL);
|
||||||
|
if (!clkevt)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
error = dmtimer_clkevt_init_common(clkevt, np,
|
||||||
|
CLOCK_EVT_FEAT_PERIODIC |
|
||||||
|
CLOCK_EVT_FEAT_ONESHOT,
|
||||||
|
cpu_possible_mask, "clockevent",
|
||||||
|
300);
|
||||||
|
if (error)
|
||||||
|
goto err_out_free;
|
||||||
|
|
||||||
|
clockevents_config_and_register(&clkevt->dev, clkevt->t.rate,
|
||||||
|
3, /* Timer internal resync latency */
|
||||||
|
0xffffffff);
|
||||||
|
|
||||||
|
if (of_machine_is_compatible("ti,am33xx") ||
|
||||||
|
of_machine_is_compatible("ti,am43")) {
|
||||||
|
clkevt->dev.suspend = omap_clockevent_idle;
|
||||||
|
clkevt->dev.resume = omap_clockevent_unidle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
err_out_free:
|
err_out_free:
|
||||||
kfree(clkevt);
|
kfree(clkevt);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue