Commit 7b3efb50 authored by Thomas Gleixner's avatar Thomas Gleixner

Merge tag 'timers-v5.13-rc1' of https://git.linaro.org/people/daniel.lezcano/linux into timers/core

Pull clocksource/event updates from Daniel Lezcano:

 - Add dt bindings for the wpcm450 and the timer declaration (Jonathan
   Neuschäfer)

 - Add dt bindings for the JZ4760, the timer declaration for the
   ingenic ost and timer (Paul Cercueil)

 - Add dt bindings for the cmt r8a779a0 (Wolfram Sang)

 - Add dt bindings for the cmt r8a77961 (Niklas Söderlund)

 - Add missing dt bindings for the tmu r8a7795, r8a7796, r8a77961, r8a77965,
   r8a77990 and r8a77995 (Niklas Söderlund)

 - Check pending post before writing a new post in register for the
   timer TI dm and add the stopped callback ops to prevent any
   spurious interrupt (Tony Lindgren)

 - Fix return value check at init when calling device_node_to_regmap()
   for the Ingenic OST timer (Wei Yongjun)

 - Fix a trivial typo s/overflw/overflow/ for the pistachio timer (Drew Fustini)

 - Don't use CMTOUT_IE with R-Car Gen2/3 (Wolfram Sang)

 - Fix rollback when the initialization fails on the dw_apb timer (Dinh Nguyen)

 - Switch to timer TI dm on dra7 in order to prevent using the bogus
   architected timer which fails to wrap correctly after 388 days (Tony Lindgren)

 - Add function annotation to optimize memory for the ARM architected
   timer (Jisheng Zhang)
parents d4c7c288 81208911
......@@ -20,6 +20,8 @@ select:
enum:
- ingenic,jz4740-tcu
- ingenic,jz4725b-tcu
- ingenic,jz4760-tcu
- ingenic,jz4760b-tcu
- ingenic,jz4770-tcu
- ingenic,jz4780-tcu
- ingenic,x1000-tcu
......@@ -52,12 +54,15 @@ properties:
- enum:
- ingenic,jz4740-tcu
- ingenic,jz4725b-tcu
- ingenic,jz4770-tcu
- ingenic,jz4760-tcu
- ingenic,x1000-tcu
- const: simple-mfd
- items:
- const: ingenic,jz4780-tcu
- const: ingenic,jz4770-tcu
- enum:
- ingenic,jz4780-tcu
- ingenic,jz4770-tcu
- ingenic,jz4760b-tcu
- const: ingenic,jz4760-tcu
- const: simple-mfd
reg:
......@@ -118,6 +123,8 @@ patternProperties:
- items:
- enum:
- ingenic,jz4770-watchdog
- ingenic,jz4760b-watchdog
- ingenic,jz4760-watchdog
- ingenic,jz4725b-watchdog
- const: ingenic,jz4740-watchdog
......@@ -147,6 +154,8 @@ patternProperties:
- ingenic,jz4725b-pwm
- items:
- enum:
- ingenic,jz4760-pwm
- ingenic,jz4760b-pwm
- ingenic,jz4770-pwm
- ingenic,jz4780-pwm
- const: ingenic,jz4740-pwm
......@@ -183,10 +192,15 @@ patternProperties:
oneOf:
- enum:
- ingenic,jz4725b-ost
- ingenic,jz4770-ost
- ingenic,jz4760b-ost
- items:
- const: ingenic,jz4760-ost
- const: ingenic,jz4725b-ost
- items:
- const: ingenic,jz4780-ost
- const: ingenic,jz4770-ost
- enum:
- ingenic,jz4780-ost
- ingenic,jz4770-ost
- const: ingenic,jz4760b-ost
reg:
maxItems: 1
......@@ -226,7 +240,7 @@ examples:
#include <dt-bindings/clock/jz4770-cgu.h>
#include <dt-bindings/clock/ingenic,tcu.h>
tcu: timer@10002000 {
compatible = "ingenic,jz4770-tcu", "simple-mfd";
compatible = "ingenic,jz4770-tcu", "ingenic,jz4760-tcu", "simple-mfd";
reg = <0x10002000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
......@@ -272,7 +286,7 @@ examples:
};
ost: timer@e0 {
compatible = "ingenic,jz4770-ost";
compatible = "ingenic,jz4770-ost", "ingenic,jz4760b-ost";
reg = <0xe0 0x20>;
clocks = <&tcu TCU_CLK_OST>;
......
......@@ -4,7 +4,8 @@ Nuvoton NPCM7xx have three timer modules, each timer module provides five 24-bit
timer counters.
Required properties:
- compatible : "nuvoton,npcm750-timer" for Poleg NPCM750.
- compatible : "nuvoton,npcm750-timer" for Poleg NPCM750, or
"nuvoton,wpcm450-timer" for Hermon WPCM450.
- reg : Offset and length of the register set for the device.
- interrupts : Contain the timer interrupt of timer 0.
- clocks : phandle of timer reference clock (usually a 25 MHz clock).
......
......@@ -74,11 +74,13 @@ properties:
- renesas,r8a774e1-cmt0 # 32-bit CMT0 on RZ/G2H
- renesas,r8a7795-cmt0 # 32-bit CMT0 on R-Car H3
- renesas,r8a7796-cmt0 # 32-bit CMT0 on R-Car M3-W
- renesas,r8a77961-cmt0 # 32-bit CMT0 on R-Car M3-W+
- renesas,r8a77965-cmt0 # 32-bit CMT0 on R-Car M3-N
- renesas,r8a77970-cmt0 # 32-bit CMT0 on R-Car V3M
- renesas,r8a77980-cmt0 # 32-bit CMT0 on R-Car V3H
- renesas,r8a77990-cmt0 # 32-bit CMT0 on R-Car E3
- renesas,r8a77995-cmt0 # 32-bit CMT0 on R-Car D3
- renesas,r8a779a0-cmt0 # 32-bit CMT0 on R-Car V3U
- const: renesas,rcar-gen3-cmt0 # 32-bit CMT0 on R-Car Gen3 and RZ/G2
- items:
......@@ -89,11 +91,13 @@ properties:
- renesas,r8a774e1-cmt1 # 48-bit CMT on RZ/G2H
- renesas,r8a7795-cmt1 # 48-bit CMT on R-Car H3
- renesas,r8a7796-cmt1 # 48-bit CMT on R-Car M3-W
- renesas,r8a77961-cmt1 # 48-bit CMT on R-Car M3-W+
- renesas,r8a77965-cmt1 # 48-bit CMT on R-Car M3-N
- renesas,r8a77970-cmt1 # 48-bit CMT on R-Car V3M
- renesas,r8a77980-cmt1 # 48-bit CMT on R-Car V3H
- renesas,r8a77990-cmt1 # 48-bit CMT on R-Car E3
- renesas,r8a77995-cmt1 # 48-bit CMT on R-Car D3
- renesas,r8a779a0-cmt1 # 48-bit CMT on R-Car V3U
- const: renesas,rcar-gen3-cmt1 # 48-bit CMT on R-Car Gen3 and RZ/G2
reg:
......
......@@ -28,8 +28,14 @@ properties:
- renesas,tmu-r8a774e1 # RZ/G2H
- renesas,tmu-r8a7778 # R-Car M1A
- renesas,tmu-r8a7779 # R-Car H1
- renesas,tmu-r8a7795 # R-Car H3
- renesas,tmu-r8a7796 # R-Car M3-W
- renesas,tmu-r8a77961 # R-Car M3-W+
- renesas,tmu-r8a77965 # R-Car M3-N
- renesas,tmu-r8a77970 # R-Car V3M
- renesas,tmu-r8a77980 # R-Car V3H
- renesas,tmu-r8a77990 # R-Car E3
- renesas,tmu-r8a77995 # R-Car D3
- const: renesas,tmu
reg:
......
......@@ -1168,7 +1168,7 @@ timer2: timer@0 {
};
};
target-module@34000 { /* 0x48034000, ap 7 46.0 */
timer3_target: target-module@34000 { /* 0x48034000, ap 7 46.0 */
compatible = "ti,sysc-omap4-timer", "ti,sysc";
reg = <0x34000 0x4>,
<0x34010 0x4>;
......@@ -1195,7 +1195,7 @@ timer3: timer@0 {
};
};
target-module@36000 { /* 0x48036000, ap 9 4e.0 */
timer4_target: target-module@36000 { /* 0x48036000, ap 9 4e.0 */
compatible = "ti,sysc-omap4-timer", "ti,sysc";
reg = <0x36000 0x4>,
<0x36010 0x4>;
......
......@@ -46,6 +46,7 @@ aliases {
timer {
compatible = "arm,armv7-timer";
status = "disabled"; /* See ARM architected timer wrap erratum i940 */
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
......@@ -1241,3 +1242,22 @@ timer@0 {
assigned-clock-parents = <&sys_32k_ck>;
};
};
/* Local timers, see ARM architected timer wrap erratum i940 */
&timer3_target {
ti,no-reset-on-init;
ti,no-idle;
timer@0 {
assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER3_CLKCTRL 24>;
assigned-clock-parents = <&timer_sys_clk_div>;
};
};
&timer4_target {
ti,no-reset-on-init;
ti,no-idle;
timer@0 {
assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER4_CLKCTRL 24>;
assigned-clock-parents = <&timer_sys_clk_div>;
};
};
......@@ -51,7 +51,7 @@
static unsigned arch_timers_present __initdata;
static void __iomem *arch_counter_base;
static void __iomem *arch_counter_base __ro_after_init;
struct arch_timer {
void __iomem *base;
......@@ -60,15 +60,16 @@ struct arch_timer {
#define to_arch_timer(e) container_of(e, struct arch_timer, evt)
static u32 arch_timer_rate;
static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI];
static u32 arch_timer_rate __ro_after_init;
u32 arch_timer_rate1 __ro_after_init;
static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI] __ro_after_init;
static struct clock_event_device __percpu *arch_timer_evt;
static enum arch_timer_ppi_nr arch_timer_uses_ppi = ARCH_TIMER_VIRT_PPI;
static bool arch_timer_c3stop;
static bool arch_timer_mem_use_virtual;
static bool arch_counter_suspend_stop;
static enum arch_timer_ppi_nr arch_timer_uses_ppi __ro_after_init = ARCH_TIMER_VIRT_PPI;
static bool arch_timer_c3stop __ro_after_init;
static bool arch_timer_mem_use_virtual __ro_after_init;
static bool arch_counter_suspend_stop __ro_after_init;
#ifdef CONFIG_GENERIC_GETTIMEOFDAY
static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_ARCHTIMER;
#else
......@@ -76,7 +77,7 @@ static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_NONE;
#endif /* CONFIG_GENERIC_GETTIMEOFDAY */
static cpumask_t evtstrm_available = CPU_MASK_NONE;
static bool evtstrm_enable = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM);
static bool evtstrm_enable __ro_after_init = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM);
static int __init early_evtstrm_cfg(char *buf)
{
......@@ -176,7 +177,7 @@ static notrace u64 arch_counter_get_cntvct(void)
* to exist on arm64. arm doesn't use this before DT is probed so even
* if we don't have the cp15 accessors we won't have a problem.
*/
u64 (*arch_timer_read_counter)(void) = arch_counter_get_cntvct;
u64 (*arch_timer_read_counter)(void) __ro_after_init = arch_counter_get_cntvct;
EXPORT_SYMBOL_GPL(arch_timer_read_counter);
static u64 arch_counter_read(struct clocksource *cs)
......@@ -925,7 +926,7 @@ static int validate_timer_rate(void)
* rate was probed first, and don't verify that others match. If the first node
* probed has a clock-frequency property, this overrides the HW register.
*/
static void arch_timer_of_configure_rate(u32 rate, struct device_node *np)
static void __init arch_timer_of_configure_rate(u32 rate, struct device_node *np)
{
/* Who has more than one independent system counter? */
if (arch_timer_rate)
......@@ -939,7 +940,7 @@ static void arch_timer_of_configure_rate(u32 rate, struct device_node *np)
pr_warn("frequency not available\n");
}
static void arch_timer_banner(unsigned type)
static void __init arch_timer_banner(unsigned type)
{
pr_info("%s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n",
type & ARCH_TIMER_TYPE_CP15 ? "cp15" : "",
......
......@@ -52,18 +52,34 @@ static int __init timer_get_base_and_rate(struct device_node *np,
return 0;
timer_clk = of_clk_get_by_name(np, "timer");
if (IS_ERR(timer_clk))
return PTR_ERR(timer_clk);
if (IS_ERR(timer_clk)) {
ret = PTR_ERR(timer_clk);
goto out_pclk_disable;
}
ret = clk_prepare_enable(timer_clk);
if (ret)
return ret;
goto out_timer_clk_put;
*rate = clk_get_rate(timer_clk);
if (!(*rate))
return -EINVAL;
if (!(*rate)) {
ret = -EINVAL;
goto out_timer_clk_disable;
}
return 0;
out_timer_clk_disable:
clk_disable_unprepare(timer_clk);
out_timer_clk_put:
clk_put(timer_clk);
out_pclk_disable:
if (!IS_ERR(pclk)) {
clk_disable_unprepare(pclk);
clk_put(pclk);
}
iounmap(*base);
return ret;
}
static int __init add_clockevent(struct device_node *event_timer)
......
......@@ -88,9 +88,9 @@ static int __init ingenic_ost_probe(struct platform_device *pdev)
return PTR_ERR(ost->regs);
map = device_node_to_regmap(dev->parent->of_node);
if (!map) {
if (IS_ERR(map)) {
dev_err(dev, "regmap not found");
return -EINVAL;
return PTR_ERR(map);
}
ost->clk = devm_clk_get(dev, "ost");
......@@ -167,13 +167,14 @@ static const struct ingenic_ost_soc_info jz4725b_ost_soc_info = {
.is64bit = false,
};
static const struct ingenic_ost_soc_info jz4770_ost_soc_info = {
static const struct ingenic_ost_soc_info jz4760b_ost_soc_info = {
.is64bit = true,
};
static const struct of_device_id ingenic_ost_of_match[] = {
{ .compatible = "ingenic,jz4725b-ost", .data = &jz4725b_ost_soc_info, },
{ .compatible = "ingenic,jz4770-ost", .data = &jz4770_ost_soc_info, },
{ .compatible = "ingenic,jz4760b-ost", .data = &jz4760b_ost_soc_info, },
{ .compatible = "ingenic,jz4770-ost", .data = &jz4760b_ost_soc_info, },
{ }
};
......
......@@ -264,6 +264,7 @@ static const struct ingenic_soc_info jz4725b_soc_info = {
static const struct of_device_id ingenic_tcu_of_match[] = {
{ .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, },
{ .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, },
{ .compatible = "ingenic,jz4760-tcu", .data = &jz4740_soc_info, },
{ .compatible = "ingenic,jz4770-tcu", .data = &jz4740_soc_info, },
{ .compatible = "ingenic,x1000-tcu", .data = &jz4740_soc_info, },
{ /* sentinel */ }
......@@ -358,6 +359,7 @@ static int __init ingenic_tcu_init(struct device_node *np)
TIMER_OF_DECLARE(jz4740_tcu_intc, "ingenic,jz4740-tcu", ingenic_tcu_init);
TIMER_OF_DECLARE(jz4725b_tcu_intc, "ingenic,jz4725b-tcu", ingenic_tcu_init);
TIMER_OF_DECLARE(jz4760_tcu_intc, "ingenic,jz4760-tcu", ingenic_tcu_init);
TIMER_OF_DECLARE(jz4770_tcu_intc, "ingenic,jz4770-tcu", ingenic_tcu_init);
TIMER_OF_DECLARE(x1000_tcu_intc, "ingenic,x1000-tcu", ingenic_tcu_init);
......
......@@ -339,8 +339,9 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch)
sh_cmt_write_cmcsr(ch, SH_CMT16_CMCSR_CMIE |
SH_CMT16_CMCSR_CKS512);
} else {
sh_cmt_write_cmcsr(ch, SH_CMT32_CMCSR_CMM |
SH_CMT32_CMCSR_CMTOUT_IE |
u32 cmtout = ch->cmt->info->model <= SH_CMT_48BIT ?
SH_CMT32_CMCSR_CMTOUT_IE : 0;
sh_cmt_write_cmcsr(ch, cmtout | SH_CMT32_CMCSR_CMM |
SH_CMT32_CMCSR_CMR_IRQ |
SH_CMT32_CMCSR_CKS_RCLK8);
}
......
......@@ -208,5 +208,6 @@ static int __init npcm7xx_timer_init(struct device_node *np)
return 0;
}
TIMER_OF_DECLARE(wpcm450, "nuvoton,wpcm450-timer", npcm7xx_timer_init);
TIMER_OF_DECLARE(npcm7xx, "nuvoton,npcm750-timer", npcm7xx_timer_init);
......@@ -71,7 +71,7 @@ static u64 notrace
pistachio_clocksource_read_cycles(struct clocksource *cs)
{
struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs);
u32 counter, overflw;
u32 counter, overflow;
unsigned long flags;
/*
......@@ -80,7 +80,7 @@ pistachio_clocksource_read_cycles(struct clocksource *cs)
*/
raw_spin_lock_irqsave(&pcs->lock, flags);
overflw = gpt_readl(pcs->base, TIMER_CURRENT_OVERFLOW_VALUE, 0);
overflow = gpt_readl(pcs->base, TIMER_CURRENT_OVERFLOW_VALUE, 0);
counter = gpt_readl(pcs->base, TIMER_CURRENT_VALUE, 0);
raw_spin_unlock_irqrestore(&pcs->lock, flags);
......
......@@ -2,6 +2,7 @@
#include <linux/clk.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/cpuhotplug.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
......@@ -449,13 +450,13 @@ static int dmtimer_set_next_event(unsigned long cycles,
struct dmtimer_systimer *t = &clkevt->t;
void __iomem *pend = t->base + t->pend;
writel_relaxed(0xffffffff - cycles, t->base + t->counter);
while (readl_relaxed(pend) & WP_TCRR)
cpu_relax();
writel_relaxed(0xffffffff - cycles, t->base + t->counter);
writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl);
while (readl_relaxed(pend) & WP_TCLR)
cpu_relax();
writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl);
return 0;
}
......@@ -490,18 +491,18 @@ static int dmtimer_set_periodic(struct clock_event_device *evt)
dmtimer_clockevent_shutdown(evt);
/* Looks like we need to first set the load value separately */
writel_relaxed(clkevt->period, t->base + t->load);
while (readl_relaxed(pend) & WP_TLDR)
cpu_relax();
writel_relaxed(clkevt->period, t->base + t->load);
writel_relaxed(clkevt->period, t->base + t->counter);
while (readl_relaxed(pend) & WP_TCRR)
cpu_relax();
writel_relaxed(clkevt->period, t->base + t->counter);
writel_relaxed(OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
t->base + t->ctrl);
while (readl_relaxed(pend) & WP_TCLR)
cpu_relax();
writel_relaxed(OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
t->base + t->ctrl);
return 0;
}
......@@ -530,17 +531,17 @@ static void omap_clockevent_unidle(struct clock_event_device *evt)
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 dmtimer_systimer *t;
int error;
clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL);
if (!clkevt)
return -ENOMEM;
t = &clkevt->t;
dev = &clkevt->dev;
......@@ -548,24 +549,23 @@ static int __init dmtimer_clockevent_init(struct device_node *np)
* We mostly use cpuidle_coupled with ARM local timers for runtime,
* so there's probably no use for CLOCK_EVT_FEAT_DYNIRQ here.
*/
dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
dev->rating = 300;
dev->features = features;
dev->rating = rating;
dev->set_next_event = dmtimer_set_next_event;
dev->set_state_shutdown = dmtimer_clockevent_shutdown;
dev->set_state_periodic = dmtimer_set_periodic;
dev->set_state_oneshot = dmtimer_clockevent_shutdown;
dev->set_state_oneshot_stopped = 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);
if (!dev->irq) {
error = -ENXIO;
goto err_out_free;
}
if (!dev->irq)
return -ENXIO;
error = dmtimer_systimer_setup(np, &clkevt->t);
if (error)
goto err_out_free;
return error;
clkevt->period = 0xffffffff - DIV_ROUND_CLOSEST(t->rate, HZ);
......@@ -577,38 +577,132 @@ static int __init dmtimer_clockevent_init(struct device_node *np)
writel_relaxed(OMAP_TIMER_CTRL_POSTED, t->base + t->ifctrl);
error = request_irq(dev->irq, dmtimer_clockevent_interrupt,
IRQF_TIMER, "clockevent", clkevt);
IRQF_TIMER, name, clkevt);
if (error)
goto err_out_unmap;
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena);
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup);
pr_info("TI gptimer clockevent: %s%lu Hz at %pOF\n",
of_find_property(np, "ti,timer-alwon", NULL) ?
pr_info("TI gptimer %s: %s%lu Hz at %pOF\n",
name, of_find_property(np, "ti,timer-alwon", NULL) ?
"always-on " : "", t->rate, np->parent);
clockevents_config_and_register(dev, t->rate,
return 0;
err_out_unmap:
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")) {
dev->suspend = omap_clockevent_idle;
dev->resume = omap_clockevent_unidle;
clkevt->dev.suspend = omap_clockevent_idle;
clkevt->dev.resume = omap_clockevent_unidle;
}
return 0;
err_out_unmap:
iounmap(t->base);
err_out_free:
kfree(clkevt);
return error;
}
/* Dmtimer as percpu timer. See dra7 ARM architected timer wrap erratum i940 */
static DEFINE_PER_CPU(struct dmtimer_clockevent, dmtimer_percpu_timer);
static int __init dmtimer_percpu_timer_init(struct device_node *np, int cpu)
{
struct dmtimer_clockevent *clkevt;
int error;
if (!cpu_possible(cpu))
return -EINVAL;
if (!of_property_read_bool(np->parent, "ti,no-reset-on-init") ||
!of_property_read_bool(np->parent, "ti,no-idle"))
pr_warn("Incomplete dtb for percpu dmtimer %pOF\n", np->parent);
clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
error = dmtimer_clkevt_init_common(clkevt, np, CLOCK_EVT_FEAT_ONESHOT,
cpumask_of(cpu), "percpu-dmtimer",
500);
if (error)
return error;
return 0;
}
/* See TRM for timer internal resynch latency */
static int omap_dmtimer_starting_cpu(unsigned int cpu)
{
struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
struct clock_event_device *dev = &clkevt->dev;
struct dmtimer_systimer *t = &clkevt->t;
clockevents_config_and_register(dev, t->rate, 3, ULONG_MAX);
irq_force_affinity(dev->irq, cpumask_of(cpu));
return 0;
}
static int __init dmtimer_percpu_timer_startup(void)
{
struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, 0);
struct dmtimer_systimer *t = &clkevt->t;
if (t->sysc) {
cpuhp_setup_state(CPUHP_AP_TI_GP_TIMER_STARTING,
"clockevents/omap/gptimer:starting",
omap_dmtimer_starting_cpu, NULL);
}
return 0;
}
subsys_initcall(dmtimer_percpu_timer_startup);
static int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa)
{
struct device_node *arm_timer;
arm_timer = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
if (of_device_is_available(arm_timer)) {
pr_warn_once("ARM architected timer wrap issue i940 detected\n");
return 0;
}
if (pa == 0x48034000) /* dra7 dmtimer3 */
return dmtimer_percpu_timer_init(np, 0);
else if (pa == 0x48036000) /* dra7 dmtimer4 */
return dmtimer_percpu_timer_init(np, 1);
return 0;
}
/* Clocksource */
static struct dmtimer_clocksource *
to_dmtimer_clocksource(struct clocksource *cs)
......@@ -742,6 +836,9 @@ static int __init dmtimer_systimer_init(struct device_node *np)
if (clockevent == pa)
return dmtimer_clockevent_init(np);
if (of_machine_is_compatible("ti,dra7"))
return dmtimer_percpu_quirk_init(np, pa);
return 0;
}
......
......@@ -135,6 +135,7 @@ enum cpuhp_state {
CPUHP_AP_RISCV_TIMER_STARTING,
CPUHP_AP_CLINT_TIMER_STARTING,
CPUHP_AP_CSKY_TIMER_STARTING,
CPUHP_AP_TI_GP_TIMER_STARTING,
CPUHP_AP_HYPERV_TIMER_STARTING,
CPUHP_AP_KVM_STARTING,
CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment