Skip to content

Commit 6cfcd55

Browse files
tmlinddlezcano
authored andcommitted
clocksource/drivers/timer-ti-dm: Fix suspend and resume for am3 and am4
Carlos Hernandez <[email protected]> reported that we now have a suspend and resume regresssion on am3 and am4 compared to the earlier kernels. While suspend and resume works with v5.8-rc3, we now get errors with rtcwake: pm33xx pm33xx: PM: Could not transition all powerdomains to target state ... rtcwake: write error This is because we now fail to idle the system timer clocks that the idle code checks and the error gets propagated to the rtcwake. Turns out there are several issues that need to be fixed: 1. Ignore no-idle and no-reset configured timers for the ti-sysc interconnect target driver as otherwise it will keep the system timer clocks enabled 2. Toggle the system timer functional clock for suspend for am3 and am4 (but not for clocksource on am3) 3. Only reconfigure type1 timers in dmtimer_systimer_disable() 4. Use of_machine_is_compatible() instead of of_device_is_compatible() for checking the SoC type Fixes: 52762fb ("clocksource/drivers/timer-ti-dm: Add clockevent and clocksource support") Reported-by: Carlos Hernandez <[email protected]> Signed-off-by: Tony Lindgren <[email protected]> Tested-by: Carlos Hernandez <[email protected]> Signed-off-by: Daniel Lezcano <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 30c66fc commit 6cfcd55

File tree

2 files changed

+58
-10
lines changed

2 files changed

+58
-10
lines changed

drivers/bus/ti-sysc.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2864,6 +2864,24 @@ static int sysc_check_disabled_devices(struct sysc *ddata)
28642864
return error;
28652865
}
28662866

2867+
/*
2868+
* Ignore timers tagged with no-reset and no-idle. These are likely in use,
2869+
* for example by drivers/clocksource/timer-ti-dm-systimer.c. If more checks
2870+
* are needed, we could also look at the timer register configuration.
2871+
*/
2872+
static int sysc_check_active_timer(struct sysc *ddata)
2873+
{
2874+
if (ddata->cap->type != TI_SYSC_OMAP2_TIMER &&
2875+
ddata->cap->type != TI_SYSC_OMAP4_TIMER)
2876+
return 0;
2877+
2878+
if ((ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) &&
2879+
(ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE))
2880+
return -EBUSY;
2881+
2882+
return 0;
2883+
}
2884+
28672885
static const struct of_device_id sysc_match_table[] = {
28682886
{ .compatible = "simple-bus", },
28692887
{ /* sentinel */ },
@@ -2920,6 +2938,10 @@ static int sysc_probe(struct platform_device *pdev)
29202938
if (error)
29212939
return error;
29222940

2941+
error = sysc_check_active_timer(ddata);
2942+
if (error)
2943+
return error;
2944+
29232945
error = sysc_get_clocks(ddata);
29242946
if (error)
29252947
return error;

drivers/clocksource/timer-ti-dm-systimer.c

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
/* For type1, set SYSC_OMAP2_CLOCKACTIVITY for fck off on idle, l4 clock on */
2020
#define DMTIMER_TYPE1_ENABLE ((1 << 9) | (SYSC_IDLE_SMART << 3) | \
2121
SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_AUTOIDLE)
22-
22+
#define DMTIMER_TYPE1_DISABLE (SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE)
2323
#define DMTIMER_TYPE2_ENABLE (SYSC_IDLE_SMART_WKUP << 2)
2424
#define DMTIMER_RESET_WAIT 100000
2525

@@ -44,6 +44,8 @@ struct dmtimer_systimer {
4444
u8 ctrl;
4545
u8 wakeup;
4646
u8 ifctrl;
47+
struct clk *fck;
48+
struct clk *ick;
4749
unsigned long rate;
4850
};
4951

@@ -298,16 +300,20 @@ static void __init dmtimer_systimer_select_best(void)
298300
}
299301

300302
/* Interface clocks are only available on some SoCs variants */
301-
static int __init dmtimer_systimer_init_clock(struct device_node *np,
303+
static int __init dmtimer_systimer_init_clock(struct dmtimer_systimer *t,
304+
struct device_node *np,
302305
const char *name,
303306
unsigned long *rate)
304307
{
305308
struct clk *clock;
306309
unsigned long r;
310+
bool is_ick = false;
307311
int error;
308312

313+
is_ick = !strncmp(name, "ick", 3);
314+
309315
clock = of_clk_get_by_name(np, name);
310-
if ((PTR_ERR(clock) == -EINVAL) && !strncmp(name, "ick", 3))
316+
if ((PTR_ERR(clock) == -EINVAL) && is_ick)
311317
return 0;
312318
else if (IS_ERR(clock))
313319
return PTR_ERR(clock);
@@ -320,6 +326,11 @@ static int __init dmtimer_systimer_init_clock(struct device_node *np,
320326
if (!r)
321327
return -ENODEV;
322328

329+
if (is_ick)
330+
t->ick = clock;
331+
else
332+
t->fck = clock;
333+
323334
*rate = r;
324335

325336
return 0;
@@ -339,7 +350,10 @@ static void dmtimer_systimer_enable(struct dmtimer_systimer *t)
339350

340351
static void dmtimer_systimer_disable(struct dmtimer_systimer *t)
341352
{
342-
writel_relaxed(0, t->base + t->sysc);
353+
if (!dmtimer_systimer_revision1(t))
354+
return;
355+
356+
writel_relaxed(DMTIMER_TYPE1_DISABLE, t->base + t->sysc);
343357
}
344358

345359
static int __init dmtimer_systimer_setup(struct device_node *np,
@@ -366,13 +380,13 @@ static int __init dmtimer_systimer_setup(struct device_node *np,
366380
pr_err("%s: clock source init failed: %i\n", __func__, error);
367381

368382
/* For ti-sysc, we have timer clocks at the parent module level */
369-
error = dmtimer_systimer_init_clock(np->parent, "fck", &rate);
383+
error = dmtimer_systimer_init_clock(t, np->parent, "fck", &rate);
370384
if (error)
371385
goto err_unmap;
372386

373387
t->rate = rate;
374388

375-
error = dmtimer_systimer_init_clock(np->parent, "ick", &rate);
389+
error = dmtimer_systimer_init_clock(t, np->parent, "ick", &rate);
376390
if (error)
377391
goto err_unmap;
378392

@@ -496,12 +510,18 @@ static void omap_clockevent_idle(struct clock_event_device *evt)
496510
struct dmtimer_systimer *t = &clkevt->t;
497511

498512
dmtimer_systimer_disable(t);
513+
clk_disable(t->fck);
499514
}
500515

501516
static void omap_clockevent_unidle(struct clock_event_device *evt)
502517
{
503518
struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
504519
struct dmtimer_systimer *t = &clkevt->t;
520+
int error;
521+
522+
error = clk_enable(t->fck);
523+
if (error)
524+
pr_err("could not enable timer fck on resume: %i\n", error);
505525

506526
dmtimer_systimer_enable(t);
507527
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)
570590
3, /* Timer internal resynch latency */
571591
0xffffffff);
572592

573-
if (of_device_is_compatible(np, "ti,am33xx") ||
574-
of_device_is_compatible(np, "ti,am43")) {
593+
if (of_machine_is_compatible("ti,am33xx") ||
594+
of_machine_is_compatible("ti,am43")) {
575595
dev->suspend = omap_clockevent_idle;
576596
dev->resume = omap_clockevent_unidle;
577597
}
@@ -616,12 +636,18 @@ static void dmtimer_clocksource_suspend(struct clocksource *cs)
616636

617637
clksrc->loadval = readl_relaxed(t->base + t->counter);
618638
dmtimer_systimer_disable(t);
639+
clk_disable(t->fck);
619640
}
620641

621642
static void dmtimer_clocksource_resume(struct clocksource *cs)
622643
{
623644
struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs);
624645
struct dmtimer_systimer *t = &clksrc->t;
646+
int error;
647+
648+
error = clk_enable(t->fck);
649+
if (error)
650+
pr_err("could not enable timer fck on resume: %i\n", error);
625651

626652
dmtimer_systimer_enable(t);
627653
writel_relaxed(clksrc->loadval, t->base + t->counter);
@@ -653,8 +679,8 @@ static int __init dmtimer_clocksource_init(struct device_node *np)
653679
dev->mask = CLOCKSOURCE_MASK(32);
654680
dev->flags = CLOCK_SOURCE_IS_CONTINUOUS;
655681

656-
if (of_device_is_compatible(np, "ti,am33xx") ||
657-
of_device_is_compatible(np, "ti,am43")) {
682+
/* Unlike for clockevent, legacy code sets suspend only for am4 */
683+
if (of_machine_is_compatible("ti,am43")) {
658684
dev->suspend = dmtimer_clocksource_suspend;
659685
dev->resume = dmtimer_clocksource_resume;
660686
}

0 commit comments

Comments
 (0)