- Fix kernel panic at suspend / resume time on TI am3/am4 (Tony Lindgren)

-----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEGn3N4YVz0WNVyHskqDIjiipP6E8FAl8W9DAACgkQqDIjiipP
 6E9HUwf+Of/ePXWAO59IGMsiRdh+yYawc7blshVxtuw9vgfFfXSUXWyoAO8WH6zS
 VOzmlDoze+jdG4VKAr0elFOkXAHjdgfwsVoLAU1aJz1r/rcpt3j8oc8JPKTxck7I
 Yq5L9+I/36sULZt7Pa8VaendoswbrKDbHtQFqQaT+h2LtCdK2kEeRp44Xr3fqIPc
 fuHAzetjWJ20Iy7YRkI3jzL9DAcoXZWdctSoC8FYEWtP7RaGVZVnxBPyaoiGFVJc
 WnZApwxW6Ju03Uav6ypy7fP5A3utFi119pRuyadQYCJT1n9NlzZMmCA+fCCx09+Y
 fvuXIayg6bj7++YD1zLPPFn4rgTY/g==
 =vRtM
 -----END PGP SIGNATURE-----

Merge tag 'timers-v5.8-rc7' of https://git.linaro.org/people/daniel.lezcano/linux into timers/urgent

Pull a timer chip fix from Daniel Lezcano:

 - Fix kernel panic at suspend / resume time on TI am3/am4 (Tony Lindgren)
This commit is contained in:
Thomas Gleixner 2020-07-21 17:18:32 +02:00
commit b4a25fb0e6
2 changed files with 58 additions and 10 deletions

View File

@ -2864,6 +2864,24 @@ static int sysc_check_disabled_devices(struct sysc *ddata)
return error;
}
/*
* Ignore timers tagged with no-reset and no-idle. These are likely in use,
* for example by drivers/clocksource/timer-ti-dm-systimer.c. If more checks
* are needed, we could also look at the timer register configuration.
*/
static int sysc_check_active_timer(struct sysc *ddata)
{
if (ddata->cap->type != TI_SYSC_OMAP2_TIMER &&
ddata->cap->type != TI_SYSC_OMAP4_TIMER)
return 0;
if ((ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) &&
(ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE))
return -EBUSY;
return 0;
}
static const struct of_device_id sysc_match_table[] = {
{ .compatible = "simple-bus", },
{ /* sentinel */ },
@ -2920,6 +2938,10 @@ static int sysc_probe(struct platform_device *pdev)
if (error)
return error;
error = sysc_check_active_timer(ddata);
if (error)
return error;
error = sysc_get_clocks(ddata);
if (error)
return error;

View File

@ -19,7 +19,7 @@
/* For type1, set SYSC_OMAP2_CLOCKACTIVITY for fck off on idle, l4 clock on */
#define DMTIMER_TYPE1_ENABLE ((1 << 9) | (SYSC_IDLE_SMART << 3) | \
SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_AUTOIDLE)
#define DMTIMER_TYPE1_DISABLE (SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE)
#define DMTIMER_TYPE2_ENABLE (SYSC_IDLE_SMART_WKUP << 2)
#define DMTIMER_RESET_WAIT 100000
@ -44,6 +44,8 @@ struct dmtimer_systimer {
u8 ctrl;
u8 wakeup;
u8 ifctrl;
struct clk *fck;
struct clk *ick;
unsigned long rate;
};
@ -298,16 +300,20 @@ static void __init dmtimer_systimer_select_best(void)
}
/* Interface clocks are only available on some SoCs variants */
static int __init dmtimer_systimer_init_clock(struct device_node *np,
static int __init dmtimer_systimer_init_clock(struct dmtimer_systimer *t,
struct device_node *np,
const char *name,
unsigned long *rate)
{
struct clk *clock;
unsigned long r;
bool is_ick = false;
int error;
is_ick = !strncmp(name, "ick", 3);
clock = of_clk_get_by_name(np, name);
if ((PTR_ERR(clock) == -EINVAL) && !strncmp(name, "ick", 3))
if ((PTR_ERR(clock) == -EINVAL) && is_ick)
return 0;
else if (IS_ERR(clock))
return PTR_ERR(clock);
@ -320,6 +326,11 @@ static int __init dmtimer_systimer_init_clock(struct device_node *np,
if (!r)
return -ENODEV;
if (is_ick)
t->ick = clock;
else
t->fck = clock;
*rate = r;
return 0;
@ -339,7 +350,10 @@ static void dmtimer_systimer_enable(struct dmtimer_systimer *t)
static void dmtimer_systimer_disable(struct dmtimer_systimer *t)
{
writel_relaxed(0, t->base + t->sysc);
if (!dmtimer_systimer_revision1(t))
return;
writel_relaxed(DMTIMER_TYPE1_DISABLE, t->base + t->sysc);
}
static int __init dmtimer_systimer_setup(struct device_node *np,
@ -366,13 +380,13 @@ static int __init dmtimer_systimer_setup(struct device_node *np,
pr_err("%s: clock source init failed: %i\n", __func__, error);
/* For ti-sysc, we have timer clocks at the parent module level */
error = dmtimer_systimer_init_clock(np->parent, "fck", &rate);
error = dmtimer_systimer_init_clock(t, np->parent, "fck", &rate);
if (error)
goto err_unmap;
t->rate = rate;
error = dmtimer_systimer_init_clock(np->parent, "ick", &rate);
error = dmtimer_systimer_init_clock(t, np->parent, "ick", &rate);
if (error)
goto err_unmap;
@ -496,12 +510,18 @@ static void omap_clockevent_idle(struct clock_event_device *evt)
struct dmtimer_systimer *t = &clkevt->t;
dmtimer_systimer_disable(t);
clk_disable(t->fck);
}
static void omap_clockevent_unidle(struct clock_event_device *evt)
{
struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
struct dmtimer_systimer *t = &clkevt->t;
int error;
error = clk_enable(t->fck);
if (error)
pr_err("could not enable timer fck on resume: %i\n", error);
dmtimer_systimer_enable(t);
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena);
@ -570,8 +590,8 @@ static int __init dmtimer_clockevent_init(struct device_node *np)
3, /* Timer internal resynch latency */
0xffffffff);
if (of_device_is_compatible(np, "ti,am33xx") ||
of_device_is_compatible(np, "ti,am43")) {
if (of_machine_is_compatible("ti,am33xx") ||
of_machine_is_compatible("ti,am43")) {
dev->suspend = omap_clockevent_idle;
dev->resume = omap_clockevent_unidle;
}
@ -616,12 +636,18 @@ static void dmtimer_clocksource_suspend(struct clocksource *cs)
clksrc->loadval = readl_relaxed(t->base + t->counter);
dmtimer_systimer_disable(t);
clk_disable(t->fck);
}
static void dmtimer_clocksource_resume(struct clocksource *cs)
{
struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs);
struct dmtimer_systimer *t = &clksrc->t;
int error;
error = clk_enable(t->fck);
if (error)
pr_err("could not enable timer fck on resume: %i\n", error);
dmtimer_systimer_enable(t);
writel_relaxed(clksrc->loadval, t->base + t->counter);
@ -653,8 +679,8 @@ static int __init dmtimer_clocksource_init(struct device_node *np)
dev->mask = CLOCKSOURCE_MASK(32);
dev->flags = CLOCK_SOURCE_IS_CONTINUOUS;
if (of_device_is_compatible(np, "ti,am33xx") ||
of_device_is_compatible(np, "ti,am43")) {
/* Unlike for clockevent, legacy code sets suspend only for am4 */
if (of_machine_is_compatible("ti,am43")) {
dev->suspend = dmtimer_clocksource_suspend;
dev->resume = dmtimer_clocksource_resume;
}