From: Benjamin Gaignard <benjamin.gaignard@linaro.org>
To: robh+dt@kernel.org, mark.rutland@arm.com, linux@armlinux.org.uk,
mcoquelin.stm32@gmail.com, alexandre.torgue@st.com,
daniel.lezcano@linaro.org, tglx@linutronix.de,
ludovic.barre@st.com, julien.thierry@arm.com
Cc: devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org,
Benjamin Gaignard <benjamin.gaignard@linaro.org>
Subject: [PATCH v6 4/5] clocksource: stm32: add clocksource support
Date: Wed, 18 Oct 2017 14:58:25 +0200 [thread overview]
Message-ID: <1508331506-23782-5-git-send-email-benjamin.gaignard@linaro.org> (raw)
In-Reply-To: <1508331506-23782-1-git-send-email-benjamin.gaignard@linaro.org>
Rework driver code to be able to implement clocksource and clockevent
on the same hardware block.
Before this patch only the counter of the hardware block was used to
generate clock events. Now counter will be used to provide a 32 bits
clock source and a comparator will provide clock events.
Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
---
drivers/clocksource/timer-stm32.c | 104 ++++++++++++++++++++++++++++----------
1 file changed, 76 insertions(+), 28 deletions(-)
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index c834648..461b3ba 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -16,6 +16,8 @@
#include <linux/of_irq.h>
#include <linux/clk.h>
#include <linux/reset.h>
+#include <linux/sched_clock.h>
+#include <linux/slab.h>
#include "timer-of.h"
@@ -23,16 +25,16 @@
#define TIM_DIER 0x0c
#define TIM_SR 0x10
#define TIM_EGR 0x14
+#define TIM_CNT 0x24
#define TIM_PSC 0x28
#define TIM_ARR 0x2c
+#define TIM_CCR1 0x34
#define TIM_CR1_CEN BIT(0)
-#define TIM_CR1_OPM BIT(3)
+#define TIM_CR1_UDIS BIT(1)
#define TIM_CR1_ARPE BIT(7)
-#define TIM_DIER_UIE BIT(0)
-
-#define TIM_SR_UIF BIT(0)
+#define TIM_DIER_CC1IE BIT(1)
#define TIM_EGR_UG BIT(0)
@@ -40,30 +42,34 @@ static int stm32_clock_event_shutdown(struct clock_event_device *evt)
{
struct timer_of *to = to_timer_of(evt);
- writel_relaxed(0, timer_of_base(to) + TIM_CR1);
+ writel_relaxed(0, timer_of_base(to) + TIM_DIER);
+
return 0;
}
-static int stm32_clock_event_set_periodic(struct clock_event_device *evt)
+static int stm32_clock_event_set_next_event(unsigned long evt,
+ struct clock_event_device *clkevt)
{
- struct timer_of *to = to_timer_of(evt);
+ struct timer_of *to = to_timer_of(clkevt);
+ unsigned long cnt;
- writel_relaxed(timer_of_period(to), timer_of_base(to) + TIM_ARR);
- writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, timer_of_base(to) + TIM_CR1);
+ cnt = readl_relaxed(timer_of_base(to) + TIM_CNT);
+ writel_relaxed(cnt + evt, timer_of_base(to) + TIM_CCR1);
+ writel_relaxed(TIM_DIER_CC1IE, timer_of_base(to) + TIM_DIER);
return 0;
}
-static int stm32_clock_event_set_next_event(unsigned long evt,
- struct clock_event_device *clkevt)
+static int stm32_clock_event_set_periodic(struct clock_event_device *evt)
{
- struct timer_of *to = to_timer_of(clkevt);
+ struct timer_of *to = to_timer_of(evt);
- writel_relaxed(evt, timer_of_base(to) + TIM_ARR);
- writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN,
- timer_of_base(to) + TIM_CR1);
+ return stm32_clock_event_set_next_event(timer_of_period(to), evt);
+}
- return 0;
+static int stm32_clock_event_set_oneshot(struct clock_event_device *evt)
+{
+ return stm32_clock_event_set_next_event(0, evt);
}
static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
@@ -73,12 +79,57 @@ static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
writel_relaxed(0, timer_of_base(to) + TIM_SR);
+ if (clockevent_state_periodic(evt))
+ stm32_clock_event_set_periodic(evt);
+ else
+ stm32_clock_event_shutdown(evt);
+
evt->event_handler(evt);
return IRQ_HANDLED;
}
-static int __init stm32_clockevent_init(struct device_node *node)
+static void __init stm32_clockevent_init(struct timer_of *to)
+{
+ writel_relaxed(0, timer_of_base(to) + TIM_DIER);
+ writel_relaxed(0, timer_of_base(to) + TIM_SR);
+
+ clockevents_config_and_register(&to->clkevt,
+ timer_of_rate(to), 0x60, ~0U);
+}
+
+static void __iomem *stm32_timer_cnt __read_mostly;
+static u64 notrace stm32_read_sched_clock(void)
+{
+ return readl_relaxed(stm32_timer_cnt);
+}
+
+static int __init stm32_clocksource_init(struct timer_of *to)
+{
+ writel_relaxed(~0U, timer_of_base(to) + TIM_ARR);
+ writel_relaxed(0, timer_of_base(to) + TIM_PSC);
+ writel_relaxed(0, timer_of_base(to) + TIM_SR);
+ writel_relaxed(0, timer_of_base(to) + TIM_DIER);
+ writel_relaxed(0, timer_of_base(to) + TIM_SR);
+ writel_relaxed(TIM_CR1_ARPE | TIM_CR1_UDIS,
+ timer_of_base(to) + TIM_CR1);
+
+ /* Make sure that registers are updated */
+ writel_relaxed(TIM_EGR_UG, timer_of_base(to) + TIM_EGR);
+
+ /* Enable controller */
+ writel_relaxed(TIM_CR1_ARPE | TIM_CR1_UDIS | TIM_CR1_CEN,
+ timer_of_base(to) + TIM_CR1);
+
+ stm32_timer_cnt = timer_of_base(to) + TIM_CNT;
+ sched_clock_register(stm32_read_sched_clock, 32, timer_of_rate(to));
+
+ return clocksource_mmio_init(stm32_timer_cnt, "stm32_timer",
+ timer_of_rate(to), 250, 32,
+ clocksource_mmio_readl_up);
+}
+
+static int __init stm32_timer_init(struct device_node *node)
{
struct reset_control *rstc;
unsigned long max_arr;
@@ -90,12 +141,13 @@ static int __init stm32_clockevent_init(struct device_node *node)
return -ENOMEM;
to->flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE;
+
to->clkevt.name = "stm32_clockevent";
to->clkevt.rating = 200;
- to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC;
+ to->clkevt.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC;
to->clkevt.set_state_shutdown = stm32_clock_event_shutdown;
to->clkevt.set_state_periodic = stm32_clock_event_set_periodic;
- to->clkevt.set_state_oneshot = stm32_clock_event_shutdown;
+ to->clkevt.set_state_oneshot = stm32_clock_event_set_oneshot;
to->clkevt.tick_resume = stm32_clock_event_shutdown;
to->clkevt.set_next_event = stm32_clock_event_set_next_event;
@@ -120,15 +172,11 @@ static int __init stm32_clockevent_init(struct device_node *node)
goto deinit;
}
- writel_relaxed(0, timer_of_base(to) + TIM_ARR);
-
- writel_relaxed(0, timer_of_base(to) + TIM_PSC);
- writel_relaxed(TIM_EGR_UG, timer_of_base(to) + TIM_EGR);
- writel_relaxed(TIM_DIER_UIE, timer_of_base(to) + TIM_DIER);
- writel_relaxed(0, timer_of_base(to) + TIM_SR);
+ ret = stm32_clocksource_init(to);
+ if (ret)
+ goto deinit;
- clockevents_config_and_register(&to->clkevt,
- timer_of_period(to), 0x60, ~0U);
+ stm32_clockevent_init(to);
return 0;
@@ -139,4 +187,4 @@ static int __init stm32_clockevent_init(struct device_node *node)
return ret;
}
-TIMER_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init);
+TIMER_OF_DECLARE(stm32, "st,stm32-timer", stm32_timer_init);
--
2.7.4
next prev parent reply other threads:[~2017-10-18 12:58 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-10-18 12:58 [PATCH v6 0/5] stm32 clocksource driver rework Benjamin Gaignard
2017-10-18 12:58 ` [PATCH v6 1/5] timer: add timer_of_deinit function Benjamin Gaignard
[not found] ` <1508331506-23782-1-git-send-email-benjamin.gaignard-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2017-10-18 12:58 ` [PATCH v6 2/5] clocksource: stm32: convert driver to timer_of Benjamin Gaignard
2017-10-18 18:31 ` Thomas Gleixner
2017-10-18 19:32 ` Benjamin Gaignard
[not found] ` <CA+M3ks4Eg2-S8yDZuMd-jqZ6g2efvveU_WwQEh0rPZW0fGDt3w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-10-19 9:07 ` Daniel Lezcano
2017-10-18 12:58 ` [PATCH v6 5/5] arm: dts: stm32: remove useless clocksource nodes Benjamin Gaignard
2017-10-18 13:21 ` Rob Herring
[not found] ` <CABGGisx1mrf8xSWAXSm9sevE16HgCT72RhcpH6J44ECQnCd3Jw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-10-18 13:38 ` Benjamin Gaignard
2017-10-18 12:58 ` [PATCH v6 3/5] clocksource: stm32: only use 32 bits timers Benjamin Gaignard
2017-10-18 18:35 ` Thomas Gleixner
2017-10-18 12:58 ` Benjamin Gaignard [this message]
[not found] ` <1508331506-23782-5-git-send-email-benjamin.gaignard-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2017-10-18 18:59 ` [PATCH v6 4/5] clocksource: stm32: add clocksource support Thomas Gleixner
2017-10-19 8:06 ` Benjamin Gaignard
[not found] ` <CA+M3ks5K6+XnK1KDuSwAx1DF=jSJuWuGbvn64cWXrGnOTOPcCQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-10-19 8:18 ` Thomas Gleixner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1508331506-23782-5-git-send-email-benjamin.gaignard@linaro.org \
--to=benjamin.gaignard@linaro.org \
--cc=alexandre.torgue@st.com \
--cc=daniel.lezcano@linaro.org \
--cc=devicetree@vger.kernel.org \
--cc=julien.thierry@arm.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=ludovic.barre@st.com \
--cc=mark.rutland@arm.com \
--cc=mcoquelin.stm32@gmail.com \
--cc=robh+dt@kernel.org \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).