Skip to content

Commit b34677b

Browse files
lokeshvutladlezcano
authored andcommitted
clocksource/drivers/timer-ti-dm: Implement cpu_pm notifier for context save and restore
omap_dm_timer_enable() restores the entire context(including counter) based on 2 conditions: - If get_context_loss_count is populated and context is lost. - If get_context_loss_count is not populated update unconditionally. Case2 has a side effect of updating the counter register even though context is not lost. When timer is configured in pwm mode, this is causing undesired behaviour in the pwm period. Instead of using get_context_loss_count call back, implement cpu_pm notifier with context save and restore support. And delete the get_context_loss_count callback all together. Suggested-by: Tony Lindgren <[email protected]> Signed-off-by: Lokesh Vutla <[email protected]> [[email protected]: removed pm_runtime calls from cpuidle calls] Signed-off-by: Tony Lindgren <[email protected]> Signed-off-by: Daniel Lezcano <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 5e20931 commit b34677b

File tree

2 files changed

+58
-42
lines changed

2 files changed

+58
-42
lines changed

drivers/clocksource/timer-ti-dm.c

Lines changed: 57 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include <linux/clk.h>
2222
#include <linux/clk-provider.h>
23+
#include <linux/cpu_pm.h>
2324
#include <linux/module.h>
2425
#include <linux/io.h>
2526
#include <linux/device.h>
@@ -92,6 +93,47 @@ static void omap_timer_restore_context(struct omap_dm_timer *timer)
9293
timer->context.tclr);
9394
}
9495

96+
static void omap_timer_save_context(struct omap_dm_timer *timer)
97+
{
98+
timer->context.tclr =
99+
omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
100+
timer->context.twer =
101+
omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG);
102+
timer->context.tldr =
103+
omap_dm_timer_read_reg(timer, OMAP_TIMER_LOAD_REG);
104+
timer->context.tmar =
105+
omap_dm_timer_read_reg(timer, OMAP_TIMER_MATCH_REG);
106+
timer->context.tier = readl_relaxed(timer->irq_ena);
107+
timer->context.tsicr =
108+
omap_dm_timer_read_reg(timer, OMAP_TIMER_IF_CTRL_REG);
109+
}
110+
111+
static int omap_timer_context_notifier(struct notifier_block *nb,
112+
unsigned long cmd, void *v)
113+
{
114+
struct omap_dm_timer *timer;
115+
116+
timer = container_of(nb, struct omap_dm_timer, nb);
117+
118+
switch (cmd) {
119+
case CPU_CLUSTER_PM_ENTER:
120+
if ((timer->capability & OMAP_TIMER_ALWON) ||
121+
!atomic_read(&timer->enabled))
122+
break;
123+
omap_timer_save_context(timer);
124+
break;
125+
case CPU_CLUSTER_PM_ENTER_FAILED:
126+
case CPU_CLUSTER_PM_EXIT:
127+
if ((timer->capability & OMAP_TIMER_ALWON) ||
128+
!atomic_read(&timer->enabled))
129+
break;
130+
omap_timer_restore_context(timer);
131+
break;
132+
}
133+
134+
return NOTIFY_OK;
135+
}
136+
95137
static int omap_dm_timer_reset(struct omap_dm_timer *timer)
96138
{
97139
u32 l, timeout = 100000;
@@ -208,21 +250,7 @@ static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
208250

209251
static void omap_dm_timer_enable(struct omap_dm_timer *timer)
210252
{
211-
int c;
212-
213253
pm_runtime_get_sync(&timer->pdev->dev);
214-
215-
if (!(timer->capability & OMAP_TIMER_ALWON)) {
216-
if (timer->get_context_loss_count) {
217-
c = timer->get_context_loss_count(&timer->pdev->dev);
218-
if (c != timer->ctx_loss_count) {
219-
omap_timer_restore_context(timer);
220-
timer->ctx_loss_count = c;
221-
}
222-
} else {
223-
omap_timer_restore_context(timer);
224-
}
225-
}
226254
}
227255

228256
static void omap_dm_timer_disable(struct omap_dm_timer *timer)
@@ -515,8 +543,6 @@ static int omap_dm_timer_start(struct omap_dm_timer *timer)
515543
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
516544
}
517545

518-
/* Save the context */
519-
timer->context.tclr = l;
520546
return 0;
521547
}
522548

@@ -532,13 +558,6 @@ static int omap_dm_timer_stop(struct omap_dm_timer *timer)
532558

533559
__omap_dm_timer_stop(timer, timer->posted, rate);
534560

535-
/*
536-
* Since the register values are computed and written within
537-
* __omap_dm_timer_stop, we need to use read to retrieve the
538-
* context.
539-
*/
540-
timer->context.tclr =
541-
omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
542561
omap_dm_timer_disable(timer);
543562
return 0;
544563
}
@@ -561,9 +580,6 @@ static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
561580
omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
562581

563582
omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
564-
/* Save the context */
565-
timer->context.tclr = l;
566-
timer->context.tldr = load;
567583
omap_dm_timer_disable(timer);
568584
return 0;
569585
}
@@ -585,9 +601,6 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
585601
omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
586602
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
587603

588-
/* Save the context */
589-
timer->context.tclr = l;
590-
timer->context.tmar = match;
591604
omap_dm_timer_disable(timer);
592605
return 0;
593606
}
@@ -611,8 +624,6 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
611624
l |= trigger << 10;
612625
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
613626

614-
/* Save the context */
615-
timer->context.tclr = l;
616627
omap_dm_timer_disable(timer);
617628
return 0;
618629
}
@@ -634,8 +645,6 @@ static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer,
634645
}
635646
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
636647

637-
/* Save the context */
638-
timer->context.tclr = l;
639648
omap_dm_timer_disable(timer);
640649
return 0;
641650
}
@@ -649,9 +658,6 @@ static int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
649658
omap_dm_timer_enable(timer);
650659
__omap_dm_timer_int_enable(timer, value);
651660

652-
/* Save the context */
653-
timer->context.tier = value;
654-
timer->context.twer = value;
655661
omap_dm_timer_disable(timer);
656662
return 0;
657663
}
@@ -679,9 +685,6 @@ static int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
679685
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;
680686
omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l);
681687

682-
/* Save the context */
683-
timer->context.tier &= ~mask;
684-
timer->context.twer &= ~mask;
685688
omap_dm_timer_disable(timer);
686689
return 0;
687690
}
@@ -756,13 +759,21 @@ static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev)
756759

757760
atomic_set(&timer->enabled, 0);
758761

762+
if (timer->capability & OMAP_TIMER_ALWON || !timer->func_base)
763+
return 0;
764+
765+
omap_timer_save_context(timer);
766+
759767
return 0;
760768
}
761769

762770
static int __maybe_unused omap_dm_timer_runtime_resume(struct device *dev)
763771
{
764772
struct omap_dm_timer *timer = dev_get_drvdata(dev);
765773

774+
if (!(timer->capability & OMAP_TIMER_ALWON) && timer->func_base)
775+
omap_timer_restore_context(timer);
776+
766777
atomic_set(&timer->enabled, 1);
767778

768779
return 0;
@@ -829,7 +840,11 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
829840
timer->id = pdev->id;
830841
timer->capability = pdata->timer_capability;
831842
timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
832-
timer->get_context_loss_count = pdata->get_context_loss_count;
843+
}
844+
845+
if (!(timer->capability & OMAP_TIMER_ALWON)) {
846+
timer->nb.notifier_call = omap_timer_context_notifier;
847+
cpu_pm_register_notifier(&timer->nb);
833848
}
834849

835850
if (pdata)
@@ -883,6 +898,8 @@ static int omap_dm_timer_remove(struct platform_device *pdev)
883898
list_for_each_entry(timer, &omap_timer_list, node)
884899
if (!strcmp(dev_name(&timer->pdev->dev),
885900
dev_name(&pdev->dev))) {
901+
if (!(timer->capability & OMAP_TIMER_ALWON))
902+
cpu_pm_unregister_notifier(&timer->nb);
886903
list_del(&timer->node);
887904
ret = 0;
888905
break;

include/clocksource/timer-ti-dm.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,12 @@ struct omap_dm_timer {
110110
unsigned reserved:1;
111111
unsigned posted:1;
112112
struct timer_regs context;
113-
int (*get_context_loss_count)(struct device *);
114-
int ctx_loss_count;
115113
int revision;
116114
u32 capability;
117115
u32 errata;
118116
struct platform_device *pdev;
119117
struct list_head node;
118+
struct notifier_block nb;
120119
};
121120

122121
int omap_dm_timer_reserve_systimer(int id);

0 commit comments

Comments
 (0)