diff options
author | ziv.xu <ziv.xu@starfive.com> | 2022-10-27 10:52:50 +0800 |
---|---|---|
committer | mason.huo <mason.huo@starfivetech.com> | 2023-01-05 13:27:24 +0800 |
commit | cc625321ba259cd732eded12304f76397b42cce8 (patch) | |
tree | e6390ee5a5bde4388399dc5b03b30c20bc5e7c1c | |
parent | 9e7fafcab3249f6a2d611c19af3132bb312c3265 (diff) | |
download | linux-starfive-cc625321ba259cd732eded12304f76397b42cce8.tar.gz linux-starfive-cc625321ba259cd732eded12304f76397b42cce8.tar.bz2 linux-starfive-cc625321ba259cd732eded12304f76397b42cce8.zip |
timer-starfive:add pm ops for timer
add system pm ops for timer
Signed-off-by: ziv.xu <ziv.xu@starfive.com>
-rw-r--r--[-rwxr-xr-x] | drivers/clocksource/timer-starfive.c | 142 | ||||
-rw-r--r--[-rwxr-xr-x] | drivers/clocksource/timer-starfive.h | 9 |
2 files changed, 113 insertions, 38 deletions
diff --git a/drivers/clocksource/timer-starfive.c b/drivers/clocksource/timer-starfive.c index 62399f86ad6e..46003d13fa1d 100755..100644 --- a/drivers/clocksource/timer-starfive.c +++ b/drivers/clocksource/timer-starfive.c @@ -44,12 +44,23 @@ struct starfive_timer __initdata jh7110_starfive_timer = { TIMER_BASE(6), TIMER_BASE(7)}, }; +struct starfive_timer_misc_count sfcmisc = { + .clk_count = 0, + .flg_init_clk = false, +}; + static inline struct starfive_clkevt * to_starfive_clkevt(struct clock_event_device *evt) { return container_of(evt, struct starfive_clkevt, evt); } +static inline struct starfive_clkevt * +to_starfive_clksrc(struct clocksource *cs) +{ + return container_of(cs, struct starfive_clkevt, cs); +} + static inline void timer_set_mod(struct starfive_clkevt *clkevt, int mod) { writel(mod, clkevt->ctrl); @@ -96,6 +107,11 @@ static inline u32 timer_get_val(struct starfive_clkevt *clkevt) return readl(clkevt->value); } +static inline u32 timer_get_load_val(struct starfive_clkevt *clkevt) +{ + return readl(clkevt->load); +} + /* * Write RELOAD register to reload preset value to counter. * (Write 0 and write 1 are both ok) @@ -120,39 +136,71 @@ static void timer_shutdown(struct starfive_clkevt *clkevt) { timer_int_disable(clkevt); timer_disable(clkevt); - timer_int_clear(clkevt); } -static void starfive_timer_suspend(struct clock_event_device *evt) +#ifdef CONFIG_PM_SLEEP + +static void starfive_timer_suspend(struct clocksource *cs) { struct starfive_clkevt *clkevt; + struct clk *pclk; - clkevt = to_starfive_clkevt(evt); - - clkevt->reload_val = timer_get_val(clkevt); + clkevt = to_starfive_clksrc(cs); + clkevt->reload_val = timer_get_load_val(clkevt); timer_disable(clkevt); timer_int_disable(clkevt); - timer_int_clear(clkevt); + + clkevt->misc->clk_count--; + + if (clkevt->misc->clk_count < 1) + pclk = of_clk_get_by_name(clkevt->device_node, "apb_clk"); + + if (!clkevt->misc->flg_init_clk) { + const char *name = NULL; + + of_property_read_string_index(clkevt->device_node, + "clock-names", clkevt->index, &name); + clkevt->clk = of_clk_get_by_name(clkevt->device_node, name); + clk_prepare_enable(clkevt->clk); + clk_disable_unprepare(clkevt->clk); + + if (clkevt->misc->clk_count < 1) { + clk_prepare_enable(pclk); + clk_disable_unprepare(pclk); + } + } else { + clk_disable_unprepare(clkevt->clk); + + if (clkevt->misc->clk_count < 1) + clk_disable_unprepare(pclk); + } } -static void starfive_timer_resume(struct clock_event_device *evt) +static void starfive_timer_resume(struct clocksource *cs) { struct starfive_clkevt *clkevt; - clkevt = to_starfive_clkevt(evt); + clkevt = to_starfive_clksrc(cs); + + clkevt->misc->flg_init_clk = true; + + if (clkevt->misc->clk_count < 1) { + struct clk *pclk; + + pclk = of_clk_get_by_name(clkevt->device_node, "apb_clk"); + clk_prepare_enable(pclk); + } + clk_prepare_enable(clkevt->clk); + clkevt->misc->clk_count++; + timer_set_val(clkevt, clkevt->reload_val); timer_set_reload(clkevt); timer_int_enable(clkevt); timer_enable(clkevt); } -static int starfive_timer_tick_resume(struct clock_event_device *evt) -{ - starfive_timer_resume(evt); - - return 0; -} +#endif /*CONIFG PM SLEEP*/ static int starfive_timer_shutdown(struct clock_event_device *evt) { @@ -191,9 +239,26 @@ starfive_get_clock_rate(struct starfive_clkevt *clkevt, struct device_node *np) return -ENOENT; } +static u64 starfive_clocksource_mmio_readl_down(struct clocksource *c) +{ + return ~(u64)readl_relaxed(to_starfive_clksrc(c)->value) & c->mask; +} + static int starfive_clocksource_init(struct starfive_clkevt *clkevt, const char *name, struct device_node *np) { + + if (VALID_BITS > 64 || VALID_BITS < 16) + return -EINVAL; + + clkevt->cs.name = name; + clkevt->cs.rating = CLOCK_SOURCE_RATE; + clkevt->cs.read = starfive_clocksource_mmio_readl_down; + clkevt->cs.mask = CLOCKSOURCE_MASK(VALID_BITS); + clkevt->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; + clkevt->cs.suspend = starfive_timer_suspend; + clkevt->cs.resume = starfive_timer_resume; + timer_set_mod(clkevt, MOD_CONTIN); timer_set_val(clkevt, MAX_TICKS); /* val = rate --> 1s */ timer_int_disable(clkevt); @@ -201,9 +266,7 @@ static int starfive_clocksource_init(struct starfive_clkevt *clkevt, timer_int_enable(clkevt); timer_enable(clkevt); - clocksource_mmio_init(clkevt->value, name, clkevt->rate, - CLOCK_SOURCE_RATE, VALID_BITS, - clocksource_mmio_readl_down); + clocksource_register_hz(&clkevt->cs, clkevt->rate); return 0; } @@ -217,7 +280,6 @@ static irqreturn_t starfive_timer_interrupt(int irq, void *priv) struct starfive_clkevt *clkevt = to_starfive_clkevt(evt); timer_int_clear(clkevt); - if (evt->event_handler) evt->event_handler(evt); @@ -282,10 +344,7 @@ static void starfive_set_clockevent(struct clock_event_device *evt) evt->set_state_periodic = starfive_timer_set_periodic; evt->set_state_oneshot = starfive_timer_set_oneshot; evt->set_state_oneshot_stopped = starfive_timer_shutdown; - evt->tick_resume = starfive_timer_tick_resume; evt->set_next_event = starfive_timer_set_next_event; - evt->suspend = starfive_timer_suspend; - evt->resume = starfive_timer_resume; evt->rating = CLOCKEVENT_RATING; } @@ -342,7 +401,7 @@ static int __init do_starfive_timer_of_init(struct device_node *np, struct clk *pclk; struct reset_control *prst; struct reset_control *rst; - struct starfive_clkevt *clkevt; + struct starfive_clkevt *clkevt[4]; void __iomem *base; base = of_iomap(np, 0); @@ -378,25 +437,32 @@ static int __init do_starfive_timer_of_init(struct device_node *np, if (strncmp(name, "timer", strlen("timer"))) continue; - clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL); - if (!clkevt) { + clkevt[index] = kzalloc(sizeof(*clkevt[index]), GFP_KERNEL); + if (!clkevt[index]) { ret = -ENOMEM; goto clkevt_err; } + clkevt[index]->device_node = np; + clkevt[index]->index = index; + clkevt[index]->misc = &sfcmisc; - starfive_clkevt_init(timer, clkevt, base, index); + starfive_clkevt_init(timer, clkevt[index], base, index); /* Ensure timers are disabled */ - timer_disable(clkevt); + timer_disable(clkevt[index]); clk = of_clk_get_by_name(np, name); if (!IS_ERR(clk)) { - clkevt->clk = clk; - if (clk_prepare_enable(clk)) + clkevt[index]->clk = clk; + + if (clk_prepare_enable(clk)) { pr_warn("clk for %pOFn is present," "but could not be activated\n", np); + } } + clkevt[index]->misc->clk_count++; + rst = of_reset_control_get(np, name); if (!IS_ERR(rst)) { reset_control_assert(rst); @@ -409,17 +475,17 @@ static int __init do_starfive_timer_of_init(struct device_node *np, goto irq_err; } - snprintf(clkevt->name, sizeof(clkevt->name), "%s.ch%d", + snprintf(clkevt[index]->name, sizeof(clkevt[index]->name), "%s.ch%d", np->full_name, index); - ret = starfive_clockevents_register(clkevt, irq, np, clkevt->name); + ret = starfive_clockevents_register(clkevt[index], irq, np, clkevt[index]->name); if (ret) { - pr_err("%s: init clockevents failed.\n", clkevt->name); + pr_err("%s: init clockevents failed.\n", clkevt[index]->name); goto register_err; } - clkevt->irq = irq; + clkevt[index]->irq = irq; - ret = starfive_clocksource_init(clkevt, clkevt->name, np); + ret = starfive_clocksource_init(clkevt[index], clkevt[index]->name, np); if (ret) goto init_err; } @@ -430,17 +496,17 @@ static int __init do_starfive_timer_of_init(struct device_node *np, init_err: register_err: - free_irq(clkevt->irq, &clkevt->evt); + free_irq(clkevt[index]->irq, &clkevt[index]->evt); irq_err: if (!rst) { reset_control_assert(rst); reset_control_put(rst); } - if (!clkevt->clk) { - clk_disable_unprepare(clkevt->clk); - clk_put(clkevt->clk); + if (!clkevt[index]->clk) { + clk_disable_unprepare(clkevt[index]->clk); + clk_put(clkevt[index]->clk); } - kfree(clkevt); + kfree(clkevt[index]); clkevt_err: count_err: if (!IS_ERR(pclk)) { diff --git a/drivers/clocksource/timer-starfive.h b/drivers/clocksource/timer-starfive.h index 7315a0f3d567..f2ccc07d0e22 100755..100644 --- a/drivers/clocksource/timer-starfive.h +++ b/drivers/clocksource/timer-starfive.h @@ -81,10 +81,19 @@ struct starfive_timer { u32 timer_base[NR_TIMERS]; }; +struct starfive_timer_misc_count { + u8 clk_count; + bool flg_init_clk; +}; + struct starfive_clkevt { struct clock_event_device evt; + struct clocksource cs; + struct device_node *device_node; + struct starfive_timer_misc_count *misc; struct clk *clk; char name[20]; + int index; int irq; u64 periodic; u64 rate; |