mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 22:02:28 +00:00
- 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:
commit
b4a25fb0e6
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user