linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer
@ 2018-01-04 12:50 Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 01/12] clocksource/drivers/timer-of: Store the device node pointer Daniel Lezcano
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Daniel Lezcano @ 2018-01-04 12:50 UTC (permalink / raw)
  To: daniel.lezcano, tglx; +Cc: linux-kernel, benjamin.gaignard

This series fixes an issue in the stm32 driver and adds the clocksource.

Previous discussion for the stm32 changes ended up in no consensus because
of the 16bits and 32bits timers. The proposed change were removing the
16bits timers or wasn't providing the changes in a sane way.

This series fixes a bug when several timers are enabled in the DT. Now, the
DT can enable any timer 16bits or 32bits and the time framework will choose
the one with the best rating. So 16bits timer removal is no longer needed.

The fix is written in a way it can picked up for stable@.

When the driver is dealing with a 16bits timer, it computes and sets the
prescaler to a value as the timer was running at 10MHz. It is a good trade
off between wrapping interval and resolution.

The oneshot mode is implemented and the periodic mode of the timer is
replaced by the register comparison, that allows to have a free running
wheel for the clocksource.

After setting the scene by encaspulating the code, the clocksource is
added and again it relies on the time framework to choose the right one.
On this platform, the armv7_systick clocksource is better than the 16bits
timers, so if only 16bits are used, only the clockevents will be used, the
clocksource will be the armv7_systick.

In addition the timer delay is added, it saves 90ms of boot time.

A couple of trivial changes are done in timer-of in order to make the
stm32 code nicer and more self-contained.

Benjamin Gaignard (4):
  clocksource/drivers/stm32: Convert the driver to timer-of
  clocksource/drivers/stm32: Compute a prescaler value with a targeted
    rate
  clocksource/drivers/stm32: Add the oneshot mode
  clocksource/drivers/stm32: Add the clocksource

Daniel Lezcano (8):
  clocksource/drivers/timer-of: Store the device node pointer
  clocksource/drivers/timer-of: Don't request the resource by name
  clocksource/drivers/stm32: Fix kernel panic with multiple timers
  clocksource/drivers/stm32: Use the node name as timer name
  clocksource/drivers/stm32: Encapsulate the timer width sorting out
    function
  clocksource/drivers/stm32: Encapsulate more the clockevent code
  clocksource/drivers/stm32: Add the timer delay
  clocksource/drivers/stm32: Start the timer's counter sooner

 drivers/clocksource/Kconfig       |   1 +
 drivers/clocksource/timer-of.c    |  11 +-
 drivers/clocksource/timer-of.h    |   1 +
 drivers/clocksource/timer-stm32.c | 358 ++++++++++++++++++++++++++------------
 4 files changed, 260 insertions(+), 111 deletions(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 01/12] clocksource/drivers/timer-of: Store the device node pointer
  2018-01-04 12:50 [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer Daniel Lezcano
@ 2018-01-04 12:50 ` Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 02/12] clocksource/drivers/timer-of: Don't request the resource by name Daniel Lezcano
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Daniel Lezcano @ 2018-01-04 12:50 UTC (permalink / raw)
  To: daniel.lezcano, tglx; +Cc: linux-kernel, benjamin.gaignard

Under certain circumstances, some specific operations must be done with the
device node pointer, that forces the timer code to propagate the pointer to
the functions which need it. In order to consolidate the function signatures
in the different drivers by using the timer-of structure, let's store it in
the timer-of structure as a handy pointer when it is needed.

Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/clocksource/timer-of.c | 3 +++
 drivers/clocksource/timer-of.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c
index 2af8b8a..2ae348b 100644
--- a/drivers/clocksource/timer-of.c
+++ b/drivers/clocksource/timer-of.c
@@ -201,6 +201,9 @@ int __init timer_of_init(struct device_node *np, struct timer_of *to)
 
 	if (!to->clkevt.name)
 		to->clkevt.name = np->name;
+
+	to->np = np;
+
 	return ret;
 
 out_fail:
diff --git a/drivers/clocksource/timer-of.h b/drivers/clocksource/timer-of.h
index f521477..2efa8ec 100644
--- a/drivers/clocksource/timer-of.h
+++ b/drivers/clocksource/timer-of.h
@@ -32,6 +32,7 @@ struct of_timer_clk {
 
 struct timer_of {
 	unsigned int flags;
+	struct device_node *np;
 	struct clock_event_device clkevt;
 	struct of_timer_base of_base;
 	struct of_timer_irq  of_irq;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 02/12] clocksource/drivers/timer-of: Don't request the resource by name
  2018-01-04 12:50 [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 01/12] clocksource/drivers/timer-of: Store the device node pointer Daniel Lezcano
@ 2018-01-04 12:50 ` Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 03/12] clocksource/drivers/stm32: Fix kernel panic with multiple timers Daniel Lezcano
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Daniel Lezcano @ 2018-01-04 12:50 UTC (permalink / raw)
  To: daniel.lezcano, tglx; +Cc: linux-kernel, benjamin.gaignard

When the driver does not specify a name for the resource, don't use
of_io_request_and_map but of_iomap. That prevents resource name allocation
conflict on some platforms which have the same name than the node.

Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/clocksource/timer-of.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c
index 2ae348b..5aa7dcd 100644
--- a/drivers/clocksource/timer-of.c
+++ b/drivers/clocksource/timer-of.c
@@ -162,11 +162,11 @@ static __init void timer_of_base_exit(struct of_timer_base *of_base)
 static __init int timer_of_base_init(struct device_node *np,
 				     struct of_timer_base *of_base)
 {
-	const char *name = of_base->name ? of_base->name : np->full_name;
-
-	of_base->base = of_io_request_and_map(np, of_base->index, name);
+	of_base->base = of_base->name ?
+		of_io_request_and_map(np, of_base->index, of_base->name) :
+		of_iomap(np, of_base->index);
 	if (IS_ERR(of_base->base)) {
-		pr_err("Failed to iomap (%s)\n", name);
+		pr_err("Failed to iomap (%s)\n", of_base->name);
 		return PTR_ERR(of_base->base);
 	}
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 03/12] clocksource/drivers/stm32: Fix kernel panic with multiple timers
  2018-01-04 12:50 [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 01/12] clocksource/drivers/timer-of: Store the device node pointer Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 02/12] clocksource/drivers/timer-of: Don't request the resource by name Daniel Lezcano
@ 2018-01-04 12:50 ` Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 04/12] clocksource/drivers/stm32: Convert the driver to timer-of Daniel Lezcano
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Daniel Lezcano @ 2018-01-04 12:50 UTC (permalink / raw)
  To: daniel.lezcano, tglx
  Cc: linux-kernel, benjamin.gaignard, stable, Maxime Coquelin,
	Alexandre Torgue, moderated list:ARM/STM32 ARCHITECTURE

The current code hides a couple of bugs.

 - The global variable 'clock_event_ddata' is overwritten each time the
   init function is invoked.

This is fixed with a kmemdup instead of assigning the global variable. That
prevents a memory corruption when several timers are defined in the DT.

 - The clockevent's event_handler is NULL if the time framework does
   not select the clockevent when registering it, this is fine but the init
   code generates in any case an interrupt leading to dereference this
   NULL pointer.

The stm32 timer works with shadow registers, a mechanism to cache the
registers. When a change is done in one buffered register, we need to
artificially generate an event to force the timer to copy the content
of the register to the shadowed register.

The auto-reload register (ARR) is one of the shadowed register as well as
the prescaler register (PSC), so in order to force the copy, we issue an
event which in turn leads to an interrupt and the NULL dereference.

This is fixed by inverting two lines where we clear the status register
before enabling the update event interrupt.

As this kernel crash is resulting from the combination of these two bugs,
the fixes are grouped into a single patch.

Cc: stable@vger.kernel.org
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/clocksource/timer-stm32.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index 8f24237..4bfeb99 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -106,6 +106,10 @@ static int __init stm32_clockevent_init(struct device_node *np)
 	unsigned long rate, max_delta;
 	int irq, ret, bits, prescaler = 1;
 
+	data = kmemdup(&clock_event_ddata, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
 	clk = of_clk_get(np, 0);
 	if (IS_ERR(clk)) {
 		ret = PTR_ERR(clk);
@@ -156,8 +160,8 @@ static int __init stm32_clockevent_init(struct device_node *np)
 
 	writel_relaxed(prescaler - 1, data->base + TIM_PSC);
 	writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR);
-	writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
 	writel_relaxed(0, data->base + TIM_SR);
+	writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
 
 	data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ);
 
@@ -184,6 +188,7 @@ static int __init stm32_clockevent_init(struct device_node *np)
 err_clk_enable:
 	clk_put(clk);
 err_clk_get:
+	kfree(data);
 	return ret;
 }
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 04/12] clocksource/drivers/stm32: Convert the driver to timer-of
  2018-01-04 12:50 [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer Daniel Lezcano
                   ` (2 preceding siblings ...)
  2018-01-04 12:50 ` [PATCH 03/12] clocksource/drivers/stm32: Fix kernel panic with multiple timers Daniel Lezcano
@ 2018-01-04 12:50 ` Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 05/12] clocksource/drivers/stm32: Use the node name as timer name Daniel Lezcano
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Daniel Lezcano @ 2018-01-04 12:50 UTC (permalink / raw)
  To: daniel.lezcano, tglx
  Cc: linux-kernel, benjamin.gaignard, Benjamin Gaignard,
	Maxime Coquelin, Alexandre Torgue,
	moderated list:ARM/STM32 ARCHITECTURE

From: Benjamin Gaignard <benjamin.gaignard@st.com>

Convert the driver to use the timer_of helpers. This allows to remove custom
proprietary structure, factors out and simplifies the code.

[Daniel Lezcano] : Respin against the critical fix patch and massaged the
		   changelog.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/clocksource/Kconfig       |   1 +
 drivers/clocksource/timer-stm32.c | 187 +++++++++++++++-----------------------
 2 files changed, 74 insertions(+), 114 deletions(-)

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 9a6b087..786db7a 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -269,6 +269,7 @@ config CLKSRC_STM32
 	bool "Clocksource for STM32 SoCs" if !ARCH_STM32
 	depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST)
 	select CLKSRC_MMIO
+	select TIMER_OF
 
 config CLKSRC_MPS2
 	bool "Clocksource for MPS2 SoCs" if COMPILE_TEST
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index 4bfeb99..3e4ab07 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -16,6 +16,9 @@
 #include <linux/of_irq.h>
 #include <linux/clk.h>
 #include <linux/reset.h>
+#include <linux/slab.h>
+
+#include "timer-of.h"
 
 #define TIM_CR1		0x00
 #define TIM_DIER	0x0c
@@ -34,162 +37,118 @@
 
 #define TIM_EGR_UG	BIT(0)
 
-struct stm32_clock_event_ddata {
-	struct clock_event_device evtdev;
-	unsigned periodic_top;
-	void __iomem *base;
-};
-
-static int stm32_clock_event_shutdown(struct clock_event_device *evtdev)
+static int stm32_clock_event_shutdown(struct clock_event_device *clkevt)
 {
-	struct stm32_clock_event_ddata *data =
-		container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
-	void *base = data->base;
+	struct timer_of *to = to_timer_of(clkevt);
+
+	writel_relaxed(0, timer_of_base(to) + TIM_CR1);
 
-	writel_relaxed(0, base + TIM_CR1);
 	return 0;
 }
 
-static int stm32_clock_event_set_periodic(struct clock_event_device *evtdev)
+static int stm32_clock_event_set_periodic(struct clock_event_device *clkevt)
 {
-	struct stm32_clock_event_ddata *data =
-		container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
-	void *base = data->base;
+	struct timer_of *to = to_timer_of(clkevt);
+
+	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);
 
-	writel_relaxed(data->periodic_top, base + TIM_ARR);
-	writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1);
 	return 0;
 }
 
 static int stm32_clock_event_set_next_event(unsigned long evt,
-					    struct clock_event_device *evtdev)
+					    struct clock_event_device *clkevt)
 {
-	struct stm32_clock_event_ddata *data =
-		container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
+	struct timer_of *to = to_timer_of(clkevt);
 
-	writel_relaxed(evt, data->base + TIM_ARR);
+	writel_relaxed(evt, timer_of_base(to) + TIM_ARR);
 	writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN,
-		       data->base + TIM_CR1);
+		       timer_of_base(to) + TIM_CR1);
 
 	return 0;
 }
 
 static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
 {
-	struct stm32_clock_event_ddata *data = dev_id;
+	struct clock_event_device *clkevt = (struct clock_event_device *)dev_id;
+	struct timer_of *to = to_timer_of(clkevt);
 
-	writel_relaxed(0, data->base + TIM_SR);
+	writel_relaxed(0, timer_of_base(to) + TIM_SR);
 
-	data->evtdev.event_handler(&data->evtdev);
+	clkevt->event_handler(clkevt);
 
 	return IRQ_HANDLED;
 }
 
-static struct stm32_clock_event_ddata clock_event_ddata = {
-	.evtdev = {
-		.name = "stm32 clockevent",
-		.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
-		.set_state_shutdown = stm32_clock_event_shutdown,
-		.set_state_periodic = stm32_clock_event_set_periodic,
-		.set_state_oneshot = stm32_clock_event_shutdown,
-		.tick_resume = stm32_clock_event_shutdown,
-		.set_next_event = stm32_clock_event_set_next_event,
-		.rating = 200,
-	},
-};
-
-static int __init stm32_clockevent_init(struct device_node *np)
+static void __init stm32_clockevent_init(struct timer_of *to)
 {
-	struct stm32_clock_event_ddata *data = &clock_event_ddata;
-	struct clk *clk;
-	struct reset_control *rstc;
-	unsigned long rate, max_delta;
-	int irq, ret, bits, prescaler = 1;
-
-	data = kmemdup(&clock_event_ddata, sizeof(*data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	clk = of_clk_get(np, 0);
-	if (IS_ERR(clk)) {
-		ret = PTR_ERR(clk);
-		pr_err("failed to get clock for clockevent (%d)\n", ret);
-		goto err_clk_get;
-	}
-
-	ret = clk_prepare_enable(clk);
-	if (ret) {
-		pr_err("failed to enable timer clock for clockevent (%d)\n",
-		       ret);
-		goto err_clk_enable;
-	}
-
-	rate = clk_get_rate(clk);
-
-	rstc = of_reset_control_get(np, NULL);
-	if (!IS_ERR(rstc)) {
-		reset_control_assert(rstc);
-		reset_control_deassert(rstc);
-	}
-
-	data->base = of_iomap(np, 0);
-	if (!data->base) {
-		ret = -ENXIO;
-		pr_err("failed to map registers for clockevent\n");
-		goto err_iomap;
-	}
+	unsigned long max_delta;
+	int prescaler;
 
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq) {
-		ret = -EINVAL;
-		pr_err("%pOF: failed to get irq.\n", np);
-		goto err_get_irq;
-	}
+	to->clkevt.name = "stm32_clockevent";
+	to->clkevt.features = 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.tick_resume = stm32_clock_event_shutdown;
+	to->clkevt.set_next_event = stm32_clock_event_set_next_event;
 
 	/* Detect whether the timer is 16 or 32 bits */
-	writel_relaxed(~0U, data->base + TIM_ARR);
-	max_delta = readl_relaxed(data->base + TIM_ARR);
+	writel_relaxed(~0U, timer_of_base(to) + TIM_ARR);
+	max_delta = readl_relaxed(timer_of_base(to) + TIM_ARR);
 	if (max_delta == ~0U) {
 		prescaler = 1;
-		bits = 32;
+		to->clkevt.rating = 250;
 	} else {
 		prescaler = 1024;
-		bits = 16;
+		to->clkevt.rating = 100;
 	}
-	writel_relaxed(0, data->base + TIM_ARR);
+	writel_relaxed(0, timer_of_base(to) + TIM_ARR);
 
-	writel_relaxed(prescaler - 1, data->base + TIM_PSC);
-	writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR);
-	writel_relaxed(0, data->base + TIM_SR);
-	writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
+	writel_relaxed(prescaler - 1, timer_of_base(to) + TIM_PSC);
+	writel_relaxed(TIM_EGR_UG, timer_of_base(to) + TIM_EGR);
+	writel_relaxed(0, timer_of_base(to) + TIM_SR);
+	writel_relaxed(TIM_DIER_UIE, timer_of_base(to) + TIM_DIER);
 
-	data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ);
+	/* Adjust rate and period given the prescaler value */
+	to->of_clk.rate = DIV_ROUND_CLOSEST(to->of_clk.rate, prescaler);
+	to->of_clk.period = DIV_ROUND_UP(to->of_clk.rate, HZ);
 
-	clockevents_config_and_register(&data->evtdev,
-					DIV_ROUND_CLOSEST(rate, prescaler),
-					0x1, max_delta);
-
-	ret = request_irq(irq, stm32_clock_event_handler, IRQF_TIMER,
-			"stm32 clockevent", data);
-	if (ret) {
-		pr_err("%pOF: failed to request irq.\n", np);
-		goto err_get_irq;
-	}
+	clockevents_config_and_register(&to->clkevt,
+					timer_of_rate(to), 0x1, max_delta);
 
 	pr_info("%pOF: STM32 clockevent driver initialized (%d bits)\n",
-			np, bits);
+		to->np, max_delta == UINT_MAX ? 32 : 16);
+}
 
-	return ret;
+static int __init stm32_timer_init(struct device_node *node)
+{
+	struct reset_control *rstc;
+	struct timer_of *to;
+	int ret;
+
+	to = kzalloc(sizeof(*to), GFP_KERNEL);
+	if (!to)
+		return -ENOMEM;
+
+	to->flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE;
+	to->of_irq.handler = stm32_clock_event_handler;
+
+	ret = timer_of_init(node, to);
+	if (ret)
+		goto err;
 
-err_get_irq:
-	iounmap(data->base);
-err_iomap:
-	clk_disable_unprepare(clk);
-err_clk_enable:
-	clk_put(clk);
-err_clk_get:
-	kfree(data);
+	rstc = of_reset_control_get(node, NULL);
+	if (!IS_ERR(rstc)) {
+		reset_control_assert(rstc);
+		reset_control_deassert(rstc);
+	}
+
+	stm32_clockevent_init(to);
+	return 0;
+err:
+	kfree(to);
 	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

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 05/12] clocksource/drivers/stm32: Use the node name as timer name
  2018-01-04 12:50 [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer Daniel Lezcano
                   ` (3 preceding siblings ...)
  2018-01-04 12:50 ` [PATCH 04/12] clocksource/drivers/stm32: Convert the driver to timer-of Daniel Lezcano
@ 2018-01-04 12:50 ` Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 06/12] clocksource/drivers/stm32: Encapsulate the timer width sorting out function Daniel Lezcano
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Daniel Lezcano @ 2018-01-04 12:50 UTC (permalink / raw)
  To: daniel.lezcano, tglx
  Cc: linux-kernel, benjamin.gaignard, Maxime Coquelin,
	Alexandre Torgue, moderated list:ARM/STM32 ARCHITECTURE

As there are different timers on the stm32, use the node name for the timer
name in order to give the indication of which timer the kernel is using.

The /proc/timer_list gives all the information with the right name, otherwise
we end up digging in the kernel log and /proc/interrupt to do the connection
between the used timer.

Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/clocksource/timer-stm32.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index 3e4ab07..14b7a2b 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -85,7 +85,7 @@ static void __init stm32_clockevent_init(struct timer_of *to)
 	unsigned long max_delta;
 	int prescaler;
 
-	to->clkevt.name = "stm32_clockevent";
+	to->clkevt.name = to->np->full_name;
 	to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC;
 	to->clkevt.set_state_shutdown = stm32_clock_event_shutdown;
 	to->clkevt.set_state_periodic = stm32_clock_event_set_periodic;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 06/12] clocksource/drivers/stm32: Encapsulate the timer width sorting out function
  2018-01-04 12:50 [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer Daniel Lezcano
                   ` (4 preceding siblings ...)
  2018-01-04 12:50 ` [PATCH 05/12] clocksource/drivers/stm32: Use the node name as timer name Daniel Lezcano
@ 2018-01-04 12:50 ` Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 07/12] clocksource/drivers/stm32: Compute a prescaler value with a targeted rate Daniel Lezcano
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Daniel Lezcano @ 2018-01-04 12:50 UTC (permalink / raw)
  To: daniel.lezcano, tglx
  Cc: linux-kernel, benjamin.gaignard, Maxime Coquelin,
	Alexandre Torgue, moderated list:ARM/STM32 ARCHITECTURE

In order to clarify and encapsulate the code for the next changes move the
timer width check into a function and add some documentation.

Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/clocksource/timer-stm32.c | 30 +++++++++++++++++++++++-------
 1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index 14b7a2b..862134e 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -80,9 +80,27 @@ static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+/**
+ * stm32_timer_width - Sort out the timer width (32/16)
+ * @to: a pointer to a timer-of structure
+ *
+ * Write the 32bits max value and read/return the result. If the timer
+ * is a 32bits width, the result will be UINT_MAX, otherwise it will
+ * be truncated by the 16bits register to USHRT_MAX.
+ *
+ * Returns UINT_MAX if the timer is 32bits width, USHRT_MAX if it is a
+ * 16bits width.
+ */
+static u32 __init stm32_timer_width(struct timer_of *to)
+{
+	writel_relaxed(UINT_MAX, timer_of_base(to) + TIM_ARR);
+
+	return readl_relaxed(timer_of_base(to) + TIM_ARR);
+}
+
 static void __init stm32_clockevent_init(struct timer_of *to)
 {
-	unsigned long max_delta;
+	u32 width = 0;
 	int prescaler;
 
 	to->clkevt.name = to->np->full_name;
@@ -93,10 +111,8 @@ static void __init stm32_clockevent_init(struct timer_of *to)
 	to->clkevt.tick_resume = stm32_clock_event_shutdown;
 	to->clkevt.set_next_event = stm32_clock_event_set_next_event;
 
-	/* Detect whether the timer is 16 or 32 bits */
-	writel_relaxed(~0U, timer_of_base(to) + TIM_ARR);
-	max_delta = readl_relaxed(timer_of_base(to) + TIM_ARR);
-	if (max_delta == ~0U) {
+	width = stm32_timer_width(to);
+	if (width == UINT_MAX) {
 		prescaler = 1;
 		to->clkevt.rating = 250;
 	} else {
@@ -115,10 +131,10 @@ static void __init stm32_clockevent_init(struct timer_of *to)
 	to->of_clk.period = DIV_ROUND_UP(to->of_clk.rate, HZ);
 
 	clockevents_config_and_register(&to->clkevt,
-					timer_of_rate(to), 0x1, max_delta);
+					timer_of_rate(to), 0x1, width);
 
 	pr_info("%pOF: STM32 clockevent driver initialized (%d bits)\n",
-		to->np, max_delta == UINT_MAX ? 32 : 16);
+		to->np, width == UINT_MAX ? 32 : 16);
 }
 
 static int __init stm32_timer_init(struct device_node *node)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 07/12] clocksource/drivers/stm32: Compute a prescaler value with a targeted rate
  2018-01-04 12:50 [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer Daniel Lezcano
                   ` (5 preceding siblings ...)
  2018-01-04 12:50 ` [PATCH 06/12] clocksource/drivers/stm32: Encapsulate the timer width sorting out function Daniel Lezcano
@ 2018-01-04 12:50 ` Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 08/12] clocksource/drivers/stm32: Add the oneshot mode Daniel Lezcano
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Daniel Lezcano @ 2018-01-04 12:50 UTC (permalink / raw)
  To: daniel.lezcano, tglx
  Cc: linux-kernel, benjamin.gaignard, Benjamin Gaignard,
	Maxime Coquelin, Alexandre Torgue,
	moderated list:ARM/STM32 ARCHITECTURE

From: Benjamin Gaignard <benjamin.gaignard@st.com>

The prescaler value is arbitrarily set to 1024 without any regard to the
timer frequency. For 32bits timers, there is no need to set a prescaler
value as they wrap in an acceptable interval and give the opportunity to
have precise timers on this platform. However, for 16bits timers a prescaler
value is needed if we don't want to wrap too often per second which is
unefficient and adds more and more error margin. With a targeted clock
of 10MHz, the 16bits are precise enough whatever the timer frequency is
as we will compute the prescaler.

[Daniel Lezcano]: Massaged the changelog and added comment.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/clocksource/timer-stm32.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index 862134e..ac55896 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -37,6 +37,9 @@
 
 #define TIM_EGR_UG	BIT(0)
 
+#define TIM_PSC_MAX	USHRT_MAX
+#define TIM_PSC_CLKRATE	10000
+
 static int stm32_clock_event_shutdown(struct clock_event_device *clkevt)
 {
 	struct timer_of *to = to_timer_of(clkevt);
@@ -116,7 +119,14 @@ static void __init stm32_clockevent_init(struct timer_of *to)
 		prescaler = 1;
 		to->clkevt.rating = 250;
 	} else {
-		prescaler = 1024;
+		prescaler = DIV_ROUND_CLOSEST(timer_of_rate(to),
+					      TIM_PSC_CLKRATE);
+		/*
+		 * The prescaler register is an u16, the variable
+		 * can't be greater than TIM_PSC_MAX, let's cap it in
+		 * this case.
+		 */
+		prescaler = prescaler < TIM_PSC_MAX ? prescaler : TIM_PSC_MAX;
 		to->clkevt.rating = 100;
 	}
 	writel_relaxed(0, timer_of_base(to) + TIM_ARR);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 08/12] clocksource/drivers/stm32: Add the oneshot mode
  2018-01-04 12:50 [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer Daniel Lezcano
                   ` (6 preceding siblings ...)
  2018-01-04 12:50 ` [PATCH 07/12] clocksource/drivers/stm32: Compute a prescaler value with a targeted rate Daniel Lezcano
@ 2018-01-04 12:50 ` Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 09/12] clocksource/drivers/stm32: Encapsulate more the clockevent code Daniel Lezcano
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Daniel Lezcano @ 2018-01-04 12:50 UTC (permalink / raw)
  To: daniel.lezcano, tglx
  Cc: linux-kernel, benjamin.gaignard, Benjamin Gaignard,
	Maxime Coquelin, Alexandre Torgue,
	moderated list:ARM/STM32 ARCHITECTURE

From: Benjamin Gaignard <benjamin.gaignard@st.com>

The stm32 timer block is able to have a counter and a comparator.

Instead of using the auto-reload register for periodic event, we switch
to the oneshot mode by using the comparator register.

The timer is able to generate an interrupt when the counter overflows but
we don't want that as this counter will be use as a clocksource in the next
patches. So it is disabled by the UDIS bit of the control register.

[Daniel Lezcano]: Modified the changelog and splitted the oneshot mode from
		the original patch in order to provide one feature at a time.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/clocksource/timer-stm32.c | 56 ++++++++++++++++++++++++++++++---------
 1 file changed, 44 insertions(+), 12 deletions(-)

diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index ac55896..baca42c 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -24,14 +24,18 @@
 #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_UDIS	BIT(1)
 #define TIM_CR1_OPM	BIT(3)
 #define TIM_CR1_ARPE	BIT(7)
 
 #define TIM_DIER_UIE	BIT(0)
+#define TIM_DIER_CC1IE	BIT(1)
 
 #define TIM_SR_UIF	BIT(0)
 
@@ -40,33 +44,57 @@
 #define TIM_PSC_MAX	USHRT_MAX
 #define TIM_PSC_CLKRATE	10000
 
+static void stm32_clock_event_disable(struct timer_of *to)
+{
+	writel_relaxed(0, timer_of_base(to) + TIM_DIER);
+}
+
+static void stm32_clock_event_enable(struct timer_of *to)
+{
+	writel_relaxed(TIM_CR1_UDIS | TIM_CR1_CEN, timer_of_base(to) + TIM_CR1);
+}
+
 static int stm32_clock_event_shutdown(struct clock_event_device *clkevt)
 {
 	struct timer_of *to = to_timer_of(clkevt);
 
-	writel_relaxed(0, timer_of_base(to) + TIM_CR1);
+	stm32_clock_event_disable(to);
 
 	return 0;
 }
 
-static int stm32_clock_event_set_periodic(struct clock_event_device *clkevt)
+static int stm32_clock_event_set_next_event(unsigned long evt,
+					    struct clock_event_device *clkevt)
 {
 	struct timer_of *to = to_timer_of(clkevt);
+	unsigned long now, next;
+
+	next = readl_relaxed(timer_of_base(to) + TIM_CNT) + evt;
+	writel_relaxed(next, timer_of_base(to) + TIM_CCR1);
+	now = readl_relaxed(timer_of_base(to) + TIM_CNT);
+
+	if ((next - now) > evt)
+		return -ETIME;
 
-	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);
+	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 *clkevt)
+{
+	struct timer_of *to = to_timer_of(clkevt);
+
+	stm32_clock_event_enable(to);
+
+	return stm32_clock_event_set_next_event(timer_of_period(to), clkevt);
+}
+
+static int stm32_clock_event_set_oneshot(struct clock_event_device *clkevt)
 {
 	struct timer_of *to = to_timer_of(clkevt);
 
-	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);
+	stm32_clock_event_enable(to);
 
 	return 0;
 }
@@ -78,6 +106,11 @@ 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(clkevt))
+		stm32_clock_event_set_periodic(clkevt);
+	else
+		stm32_clock_event_shutdown(clkevt);
+
 	clkevt->event_handler(clkevt);
 
 	return IRQ_HANDLED;
@@ -108,9 +141,10 @@ static void __init stm32_clockevent_init(struct timer_of *to)
 
 	to->clkevt.name = to->np->full_name;
 	to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC;
+	to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
 	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;
 
@@ -129,12 +163,10 @@ static void __init stm32_clockevent_init(struct timer_of *to)
 		prescaler = prescaler < TIM_PSC_MAX ? prescaler : TIM_PSC_MAX;
 		to->clkevt.rating = 100;
 	}
-	writel_relaxed(0, timer_of_base(to) + TIM_ARR);
 
 	writel_relaxed(prescaler - 1, timer_of_base(to) + TIM_PSC);
 	writel_relaxed(TIM_EGR_UG, timer_of_base(to) + TIM_EGR);
 	writel_relaxed(0, timer_of_base(to) + TIM_SR);
-	writel_relaxed(TIM_DIER_UIE, timer_of_base(to) + TIM_DIER);
 
 	/* Adjust rate and period given the prescaler value */
 	to->of_clk.rate = DIV_ROUND_CLOSEST(to->of_clk.rate, prescaler);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 09/12] clocksource/drivers/stm32: Encapsulate more the clockevent code
  2018-01-04 12:50 [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer Daniel Lezcano
                   ` (7 preceding siblings ...)
  2018-01-04 12:50 ` [PATCH 08/12] clocksource/drivers/stm32: Add the oneshot mode Daniel Lezcano
@ 2018-01-04 12:50 ` Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 10/12] clocksource/drivers/stm32: Add the clocksource Daniel Lezcano
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Daniel Lezcano @ 2018-01-04 12:50 UTC (permalink / raw)
  To: daniel.lezcano, tglx
  Cc: linux-kernel, benjamin.gaignard, Maxime Coquelin,
	Alexandre Torgue, moderated list:ARM/STM32 ARCHITECTURE

In order to prepare the clocksource code, let's encapsulate the clockevent
code, split the prescaler and timer width code into separate functions.

Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/clocksource/timer-stm32.c | 107 +++++++++++++++++++++++++++++---------
 1 file changed, 82 insertions(+), 25 deletions(-)

diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index baca42c..1891924 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -44,6 +44,42 @@
 #define TIM_PSC_MAX	USHRT_MAX
 #define TIM_PSC_CLKRATE	10000
 
+struct stm32_timer_private {
+	int bits;
+};
+
+/**
+ * stm32_timer_of_bits_set - set accessor helper
+ * @to: a timer_of structure pointer
+ * @bits: the number of bits (16 or 32)
+ *
+ * Accessor helper to set the number of bits in the timer-of private
+ * structure.
+ *
+ */
+static void stm32_timer_of_bits_set(struct timer_of *to, int bits)
+{
+	struct stm32_timer_private *pd = to->private_data;
+
+	pd->bits = bits;
+}
+
+/**
+ * stm32_timer_of_bits_get - get accessor helper
+ * @to: a timer_of structure pointer
+ *
+ * Accessor helper to get the number of bits in the timer-of private
+ * structure.
+ *
+ * Returns an integer corresponding to the number of bits.
+ */
+static int stm32_timer_of_bits_get(struct timer_of *to)
+{
+	struct stm32_timer_private *pd = to->private_data;
+
+	return pd->bits;
+}
+
 static void stm32_clock_event_disable(struct timer_of *to)
 {
 	writel_relaxed(0, timer_of_base(to) + TIM_DIER);
@@ -124,35 +160,31 @@ static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
  * is a 32bits width, the result will be UINT_MAX, otherwise it will
  * be truncated by the 16bits register to USHRT_MAX.
  *
- * Returns UINT_MAX if the timer is 32bits width, USHRT_MAX if it is a
- * 16bits width.
  */
-static u32 __init stm32_timer_width(struct timer_of *to)
+static void __init stm32_timer_set_width(struct timer_of *to)
 {
+	u32 width;
+
 	writel_relaxed(UINT_MAX, timer_of_base(to) + TIM_ARR);
 
-	return readl_relaxed(timer_of_base(to) + TIM_ARR);
+	width = readl_relaxed(timer_of_base(to) + TIM_ARR);
+
+	stm32_timer_of_bits_set(to, width == UINT_MAX ? 32 : 16);
 }
 
-static void __init stm32_clockevent_init(struct timer_of *to)
+/**
+ * stm32_timer_set_prescaler - Compute and set the prescaler register
+ * @to: a pointer to a timer-of structure
+ *
+ * Depending on the timer width, compute the prescaler to always
+ * target a 10MHz timer rate for the 16bits. 32bits timers are
+ * considered precise and long enough to not use the prescaler.
+ */
+static void __init stm32_timer_set_prescaler(struct timer_of *to)
 {
-	u32 width = 0;
-	int prescaler;
+	int prescaler = 1;
 
-	to->clkevt.name = to->np->full_name;
-	to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC;
-	to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
-	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_set_oneshot;
-	to->clkevt.tick_resume = stm32_clock_event_shutdown;
-	to->clkevt.set_next_event = stm32_clock_event_set_next_event;
-
-	width = stm32_timer_width(to);
-	if (width == UINT_MAX) {
-		prescaler = 1;
-		to->clkevt.rating = 250;
-	} else {
+	if (stm32_timer_of_bits_get(to) != 32) {
 		prescaler = DIV_ROUND_CLOSEST(timer_of_rate(to),
 					      TIM_PSC_CLKRATE);
 		/*
@@ -161,7 +193,6 @@ static void __init stm32_clockevent_init(struct timer_of *to)
 		 * this case.
 		 */
 		prescaler = prescaler < TIM_PSC_MAX ? prescaler : TIM_PSC_MAX;
-		to->clkevt.rating = 100;
 	}
 
 	writel_relaxed(prescaler - 1, timer_of_base(to) + TIM_PSC);
@@ -171,12 +202,26 @@ static void __init stm32_clockevent_init(struct timer_of *to)
 	/* Adjust rate and period given the prescaler value */
 	to->of_clk.rate = DIV_ROUND_CLOSEST(to->of_clk.rate, prescaler);
 	to->of_clk.period = DIV_ROUND_UP(to->of_clk.rate, HZ);
+}
+
+static void __init stm32_clockevent_init(struct timer_of *to)
+{
+	u32 bits = stm32_timer_of_bits_get(to);
 
-	clockevents_config_and_register(&to->clkevt,
-					timer_of_rate(to), 0x1, width);
+	to->clkevt.name = to->np->full_name;
+	to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+	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_set_oneshot;
+	to->clkevt.tick_resume = stm32_clock_event_shutdown;
+	to->clkevt.set_next_event = stm32_clock_event_set_next_event;
+	to->clkevt.rating = bits == 32 ? 250 : 100;
+
+	clockevents_config_and_register(&to->clkevt, timer_of_rate(to), 0x1,
+					(1 <<  bits) - 1);
 
 	pr_info("%pOF: STM32 clockevent driver initialized (%d bits)\n",
-		to->np, width == UINT_MAX ? 32 : 16);
+		to->np, bits);
 }
 
 static int __init stm32_timer_init(struct device_node *node)
@@ -196,14 +241,26 @@ static int __init stm32_timer_init(struct device_node *node)
 	if (ret)
 		goto err;
 
+	to->private_data = kzalloc(sizeof(struct stm32_timer_private),
+				   GFP_KERNEL);
+	if (!to->private_data)
+		goto deinit;
+
 	rstc = of_reset_control_get(node, NULL);
 	if (!IS_ERR(rstc)) {
 		reset_control_assert(rstc);
 		reset_control_deassert(rstc);
 	}
 
+	stm32_timer_set_width(to);
+
+	stm32_timer_set_prescaler(to);
+
 	stm32_clockevent_init(to);
 	return 0;
+
+deinit:
+	timer_of_cleanup(to);
 err:
 	kfree(to);
 	return ret;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 10/12] clocksource/drivers/stm32: Add the clocksource
  2018-01-04 12:50 [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer Daniel Lezcano
                   ` (8 preceding siblings ...)
  2018-01-04 12:50 ` [PATCH 09/12] clocksource/drivers/stm32: Encapsulate more the clockevent code Daniel Lezcano
@ 2018-01-04 12:50 ` Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 11/12] clocksource/drivers/stm32: Add the timer delay Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 12/12] clocksource/drivers/stm32: Start the timer's counter sooner Daniel Lezcano
  11 siblings, 0 replies; 13+ messages in thread
From: Daniel Lezcano @ 2018-01-04 12:50 UTC (permalink / raw)
  To: daniel.lezcano, tglx
  Cc: linux-kernel, benjamin.gaignard, Benjamin Gaignard,
	Maxime Coquelin, Alexandre Torgue,
	moderated list:ARM/STM32 ARCHITECTURE

From: Benjamin Gaignard <benjamin.gaignard@st.com>

The scene is set for the clocksource, let's add it for this driver.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/clocksource/timer-stm32.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index 1891924..4634f4d 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -16,6 +16,7 @@
 #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"
@@ -80,6 +81,13 @@ static int stm32_timer_of_bits_get(struct timer_of *to)
 	return pd->bits;
 }
 
+static void __iomem *stm32_timer_cnt __read_mostly;
+
+static u64 notrace stm32_read_sched_clock(void)
+{
+	return readl_relaxed(stm32_timer_cnt);
+}
+
 static void stm32_clock_event_disable(struct timer_of *to)
 {
 	writel_relaxed(0, timer_of_base(to) + TIM_DIER);
@@ -204,6 +212,31 @@ static void __init stm32_timer_set_prescaler(struct timer_of *to)
 	to->of_clk.period = DIV_ROUND_UP(to->of_clk.rate, HZ);
 }
 
+static int __init stm32_clocksource_init(struct timer_of *to)
+{
+        u32 bits = stm32_timer_of_bits_get(to);
+	const char *name = to->np->full_name;
+
+	/*
+	 * This driver allows to register several timers and relies on
+	 * the generic time framework to select the right one.
+	 * However, nothing allows to do the same for the
+	 * sched_clock. We are not interested in a sched_clock for the
+	 * 16bits timers but only for the 32bits, so if no 32bits
+	 * timer registered yet, we select this 32bits timer as a
+	 * sched_clock.
+	 */
+	if (bits == 32 && !stm32_timer_cnt) {
+		stm32_timer_cnt = timer_of_base(to) + TIM_CNT;
+		sched_clock_register(stm32_read_sched_clock, bits, timer_of_rate(to));
+		pr_info("%s: STM32 sched_clock registered\n", name);
+	}
+
+	return clocksource_mmio_init(timer_of_base(to) + TIM_CNT, name,
+				     timer_of_rate(to), bits == 32 ? 250 : 100,
+				     bits, clocksource_mmio_readl_up);
+}
+
 static void __init stm32_clockevent_init(struct timer_of *to)
 {
 	u32 bits = stm32_timer_of_bits_get(to);
@@ -256,6 +289,10 @@ static int __init stm32_timer_init(struct device_node *node)
 
 	stm32_timer_set_prescaler(to);
 
+	ret = stm32_clocksource_init(to);
+	if (ret)
+		goto deinit;
+
 	stm32_clockevent_init(to);
 	return 0;
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 11/12] clocksource/drivers/stm32: Add the timer delay
  2018-01-04 12:50 [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer Daniel Lezcano
                   ` (9 preceding siblings ...)
  2018-01-04 12:50 ` [PATCH 10/12] clocksource/drivers/stm32: Add the clocksource Daniel Lezcano
@ 2018-01-04 12:50 ` Daniel Lezcano
  2018-01-04 12:50 ` [PATCH 12/12] clocksource/drivers/stm32: Start the timer's counter sooner Daniel Lezcano
  11 siblings, 0 replies; 13+ messages in thread
From: Daniel Lezcano @ 2018-01-04 12:50 UTC (permalink / raw)
  To: daniel.lezcano, tglx
  Cc: linux-kernel, benjamin.gaignard, Maxime Coquelin,
	Alexandre Torgue, moderated list:ARM/STM32 ARCHITECTURE

Add the timer delay, that saves us ~90ms of boot time.

Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/clocksource/timer-stm32.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index 4634f4d..dcf8445 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
@@ -88,6 +89,13 @@ static u64 notrace stm32_read_sched_clock(void)
 	return readl_relaxed(stm32_timer_cnt);
 }
 
+static struct delay_timer stm32_timer_delay;
+
+static unsigned long stm32_read_delay(void)
+{
+	return readl_relaxed(stm32_timer_cnt);
+}
+
 static void stm32_clock_event_disable(struct timer_of *to)
 {
 	writel_relaxed(0, timer_of_base(to) + TIM_DIER);
@@ -230,6 +238,11 @@ static int __init stm32_clocksource_init(struct timer_of *to)
 		stm32_timer_cnt = timer_of_base(to) + TIM_CNT;
 		sched_clock_register(stm32_read_sched_clock, bits, timer_of_rate(to));
 		pr_info("%s: STM32 sched_clock registered\n", name);
+
+		stm32_timer_delay.read_current_timer = stm32_read_delay;
+		stm32_timer_delay.freq = timer_of_rate(to);
+		register_current_timer_delay(&stm32_timer_delay);
+		pr_info("%s: STM32 delay timer registered\n", name);
 	}
 
 	return clocksource_mmio_init(timer_of_base(to) + TIM_CNT, name,
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 12/12] clocksource/drivers/stm32: Start the timer's counter sooner
  2018-01-04 12:50 [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer Daniel Lezcano
                   ` (10 preceding siblings ...)
  2018-01-04 12:50 ` [PATCH 11/12] clocksource/drivers/stm32: Add the timer delay Daniel Lezcano
@ 2018-01-04 12:50 ` Daniel Lezcano
  11 siblings, 0 replies; 13+ messages in thread
From: Daniel Lezcano @ 2018-01-04 12:50 UTC (permalink / raw)
  To: daniel.lezcano, tglx
  Cc: linux-kernel, benjamin.gaignard, Maxime Coquelin,
	Alexandre Torgue, moderated list:ARM/STM32 ARCHITECTURE

As we have a lot of timers on this platform, we can have potentially all the
timers enabled in the DT, so we don't want to start the timer for every probe
otherwise they will be running for nothing as only one will be used.

Start the timer only when setting the mode or when the clocksource is
enabled.

Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/clocksource/timer-stm32.c | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index dcf8445..4ce2345 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -101,7 +101,15 @@ static void stm32_clock_event_disable(struct timer_of *to)
 	writel_relaxed(0, timer_of_base(to) + TIM_DIER);
 }
 
-static void stm32_clock_event_enable(struct timer_of *to)
+/**
+ * stm32_timer_start - Start the counter without event
+ * @to: a timer_of structure pointer
+ *
+ * Start the timer in order to have the counter reset and start
+ * incrementing but disable interrupt event when there is a counter
+ * overflow. By default, the counter direction is used as upcounter.
+ */
+static void stm32_timer_start(struct timer_of *to)
 {
 	writel_relaxed(TIM_CR1_UDIS | TIM_CR1_CEN, timer_of_base(to) + TIM_CR1);
 }
@@ -137,7 +145,7 @@ static int stm32_clock_event_set_periodic(struct clock_event_device *clkevt)
 {
 	struct timer_of *to = to_timer_of(clkevt);
 
-	stm32_clock_event_enable(to);
+	stm32_timer_start(to);
 
 	return stm32_clock_event_set_next_event(timer_of_period(to), clkevt);
 }
@@ -146,7 +154,7 @@ static int stm32_clock_event_set_oneshot(struct clock_event_device *clkevt)
 {
 	struct timer_of *to = to_timer_of(clkevt);
 
-	stm32_clock_event_enable(to);
+	stm32_timer_start(to);
 
 	return 0;
 }
@@ -235,6 +243,13 @@ static int __init stm32_clocksource_init(struct timer_of *to)
 	 * sched_clock.
 	 */
 	if (bits == 32 && !stm32_timer_cnt) {
+
+		/*
+		 * Start immediately the counter as we will be using
+		 * it right after.
+		 */
+		stm32_timer_start(to);
+
 		stm32_timer_cnt = timer_of_base(to) + TIM_CNT;
 		sched_clock_register(stm32_read_sched_clock, bits, timer_of_rate(to));
 		pr_info("%s: STM32 sched_clock registered\n", name);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2018-01-04 12:53 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-04 12:50 [PATCH 00/12] clocksource/drivers/stm32: Consolidate the timer Daniel Lezcano
2018-01-04 12:50 ` [PATCH 01/12] clocksource/drivers/timer-of: Store the device node pointer Daniel Lezcano
2018-01-04 12:50 ` [PATCH 02/12] clocksource/drivers/timer-of: Don't request the resource by name Daniel Lezcano
2018-01-04 12:50 ` [PATCH 03/12] clocksource/drivers/stm32: Fix kernel panic with multiple timers Daniel Lezcano
2018-01-04 12:50 ` [PATCH 04/12] clocksource/drivers/stm32: Convert the driver to timer-of Daniel Lezcano
2018-01-04 12:50 ` [PATCH 05/12] clocksource/drivers/stm32: Use the node name as timer name Daniel Lezcano
2018-01-04 12:50 ` [PATCH 06/12] clocksource/drivers/stm32: Encapsulate the timer width sorting out function Daniel Lezcano
2018-01-04 12:50 ` [PATCH 07/12] clocksource/drivers/stm32: Compute a prescaler value with a targeted rate Daniel Lezcano
2018-01-04 12:50 ` [PATCH 08/12] clocksource/drivers/stm32: Add the oneshot mode Daniel Lezcano
2018-01-04 12:50 ` [PATCH 09/12] clocksource/drivers/stm32: Encapsulate more the clockevent code Daniel Lezcano
2018-01-04 12:50 ` [PATCH 10/12] clocksource/drivers/stm32: Add the clocksource Daniel Lezcano
2018-01-04 12:50 ` [PATCH 11/12] clocksource/drivers/stm32: Add the timer delay Daniel Lezcano
2018-01-04 12:50 ` [PATCH 12/12] clocksource/drivers/stm32: Start the timer's counter sooner Daniel Lezcano

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).