2018-01-08 13:27:34

by Daniel Lezcano

[permalink] [raw]
Subject: [PULL] clockevents for 4.16


Hi Thomas,

here are the changes for 4.16 synced with tip/timers/core:

- Change the macro name to TIMER_OF_DECLARE for the owl driver (Andreas
Färber)

- Add the S700 definition and the compatible string for the owl driver
(Andreas Färber)

- Add the new spreadtrum timer driver for the SC9860 platform (Baolin Wang)

- Use the timer-of API, compute the prescaler based on the target
frequency, add the oneshot mode and the clocksource for the stm32
(Benjamin Gaignard)

- Fix the clock speed message for the tcb clocksource (Romain Izard)

- Improve the timer-of code by adding documentation and unifying the
function names (Daniel Lezcano)

- Fix a kernel panic with multiple timers defined in the DT for the
stm32 (Daniel Lezcano)

- Consolidate and add the delay timer for the stm32 (Daniel Lezcano)

Thanks!

-- Daniel

The following changes since commit 29f1b2b0fecfae69e31833836f1da3136696eee5:

posix-timers: Prevent UB from shifting negative signed value
(2018-01-04 14:57:10 +0100)

are available in the git repository at:

https://git.linaro.org/people/daniel.lezcano/linux.git clockevents/4.16

for you to fetch changes up to 322fd24f5e67c396f04bef01ed33ac6bfca46bcd:

clocksource/drivers/stm32: Start the timer's counter sooner
(2018-01-08 12:10:02 +0100)

----------------------------------------------------------------
Andreas Färber (3):
dt-bindings: timer: Add Actions Semi S700
clocksource/drivers/owl: Adopt TIMER_OF_DECLARE()
clocksource/drivers/owl: Add the S700

Baolin Wang (2):
dt-bindings: clocksource: Add Spreadtrum SC9860 timer
clocksource/drivers/spreadtrum: Add timer driver for Spreadtrum
SC9860 platform

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 (10):
clocksource/drivers/timer-of: Fix function names
clocksource/drivers/timer-of: Add kernel documentation
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

Romain Izard (1):
clocksource/drivers/tcb_clksrc: Fix clock speed message

.../bindings/timer/actions,owl-timer.txt | 1 +
.../bindings/timer/spreadtrum,sprd-timer.txt | 20 ++
drivers/clocksource/Kconfig | 8 +
drivers/clocksource/Makefile | 1 +
drivers/clocksource/owl-timer.c | 5 +-
drivers/clocksource/tcb_clksrc.c | 2 +-
drivers/clocksource/timer-of.c | 85 +++--
drivers/clocksource/timer-of.h | 1 +
drivers/clocksource/timer-sprd.c | 159 +++++++++
drivers/clocksource/timer-stm32.c | 358
+++++++++++++++------
10 files changed, 508 insertions(+), 132 deletions(-)
create mode 100644
Documentation/devicetree/bindings/timer/spreadtrum,sprd-timer.txt
create mode 100644 drivers/clocksource/timer-sprd.c


2018-01-08 13:29:26

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 01/20] dt-bindings: timer: Add Actions Semi S700

From: Andreas Färber <[email protected]>

Define a compatible string for the Actions Semi S700 SoC timer.

Acked-by: Rob Herring <[email protected]>
Signed-off-by: Andreas Färber <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
---
Documentation/devicetree/bindings/timer/actions,owl-timer.txt | 1 +
1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/timer/actions,owl-timer.txt b/Documentation/devicetree/bindings/timer/actions,owl-timer.txt
index e3c28da..977054f 100644
--- a/Documentation/devicetree/bindings/timer/actions,owl-timer.txt
+++ b/Documentation/devicetree/bindings/timer/actions,owl-timer.txt
@@ -2,6 +2,7 @@ Actions Semi Owl Timer

Required properties:
- compatible : "actions,s500-timer" for S500
+ "actions,s700-timer" for S700
"actions,s900-timer" for S900
- reg : Offset and length of the register set for the device.
- interrupts : Should contain the interrupts.
--
2.7.4

2018-01-08 13:29:30

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 03/20] clocksource/drivers/owl: Add the S700

From: Andreas Färber <[email protected]>

Actions S700 has two 2Hz timers like S500, and four TIMx timers like S900.

Signed-off-by: Andreas Färber <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
---
drivers/clocksource/owl-timer.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/clocksource/owl-timer.c b/drivers/clocksource/owl-timer.c
index 9fb4333..ea00a5e 100644
--- a/drivers/clocksource/owl-timer.c
+++ b/drivers/clocksource/owl-timer.c
@@ -169,4 +169,5 @@ static int __init owl_timer_init(struct device_node *node)
return 0;
}
TIMER_OF_DECLARE(owl_s500, "actions,s500-timer", owl_timer_init);
+TIMER_OF_DECLARE(owl_s700, "actions,s700-timer", owl_timer_init);
TIMER_OF_DECLARE(owl_s900, "actions,s900-timer", owl_timer_init);
--
2.7.4

2018-01-08 13:29:38

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 05/20] clocksource/drivers/timer-of: Fix function names

All the functions are not prefixed with 'timer_of_', fix the naming in order
to have the code consistent.

Signed-off-by: Daniel Lezcano <[email protected]>
---
drivers/clocksource/timer-of.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c
index a319904..ad55654 100644
--- a/drivers/clocksource/timer-of.c
+++ b/drivers/clocksource/timer-of.c
@@ -24,7 +24,7 @@

#include "timer-of.h"

-static __init void timer_irq_exit(struct of_timer_irq *of_irq)
+static __init void timer_of_irq_exit(struct of_timer_irq *of_irq)
{
struct timer_of *to = container_of(of_irq, struct timer_of, of_irq);

@@ -34,8 +34,8 @@ static __init void timer_irq_exit(struct of_timer_irq *of_irq)
free_irq(of_irq->irq, clkevt);
}

-static __init int timer_irq_init(struct device_node *np,
- struct of_timer_irq *of_irq)
+static __init int timer_of_irq_init(struct device_node *np,
+ struct of_timer_irq *of_irq)
{
int ret;
struct timer_of *to = container_of(of_irq, struct timer_of, of_irq);
@@ -72,15 +72,15 @@ static __init int timer_irq_init(struct device_node *np,
return 0;
}

-static __init void timer_clk_exit(struct of_timer_clk *of_clk)
+static __init void timer_of_clk_exit(struct of_timer_clk *of_clk)
{
of_clk->rate = 0;
clk_disable_unprepare(of_clk->clk);
clk_put(of_clk->clk);
}

-static __init int timer_clk_init(struct device_node *np,
- struct of_timer_clk *of_clk)
+static __init int timer_of_clk_init(struct device_node *np,
+ struct of_timer_clk *of_clk)
{
int ret;

@@ -116,13 +116,13 @@ static __init int timer_clk_init(struct device_node *np,
goto out;
}

-static __init void timer_base_exit(struct of_timer_base *of_base)
+static __init void timer_of_base_exit(struct of_timer_base *of_base)
{
iounmap(of_base->base);
}

-static __init int timer_base_init(struct device_node *np,
- 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;

@@ -141,21 +141,21 @@ int __init timer_of_init(struct device_node *np, struct timer_of *to)
int flags = 0;

if (to->flags & TIMER_OF_BASE) {
- ret = timer_base_init(np, &to->of_base);
+ ret = timer_of_base_init(np, &to->of_base);
if (ret)
goto out_fail;
flags |= TIMER_OF_BASE;
}

if (to->flags & TIMER_OF_CLOCK) {
- ret = timer_clk_init(np, &to->of_clk);
+ ret = timer_of_clk_init(np, &to->of_clk);
if (ret)
goto out_fail;
flags |= TIMER_OF_CLOCK;
}

if (to->flags & TIMER_OF_IRQ) {
- ret = timer_irq_init(np, &to->of_irq);
+ ret = timer_of_irq_init(np, &to->of_irq);
if (ret)
goto out_fail;
flags |= TIMER_OF_IRQ;
@@ -167,13 +167,13 @@ int __init timer_of_init(struct device_node *np, struct timer_of *to)

out_fail:
if (flags & TIMER_OF_IRQ)
- timer_irq_exit(&to->of_irq);
+ timer_of_irq_exit(&to->of_irq);

if (flags & TIMER_OF_CLOCK)
- timer_clk_exit(&to->of_clk);
+ timer_of_clk_exit(&to->of_clk);

if (flags & TIMER_OF_BASE)
- timer_base_exit(&to->of_base);
+ timer_of_base_exit(&to->of_base);
return ret;
}

@@ -187,11 +187,11 @@ int __init timer_of_init(struct device_node *np, struct timer_of *to)
void __init timer_of_cleanup(struct timer_of *to)
{
if (to->flags & TIMER_OF_IRQ)
- timer_irq_exit(&to->of_irq);
+ timer_of_irq_exit(&to->of_irq);

if (to->flags & TIMER_OF_CLOCK)
- timer_clk_exit(&to->of_clk);
+ timer_of_clk_exit(&to->of_clk);

if (to->flags & TIMER_OF_BASE)
- timer_base_exit(&to->of_base);
+ timer_of_base_exit(&to->of_base);
}
--
2.7.4

2018-01-08 13:29:48

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 10/20] clocksource/drivers/timer-of: Don't request the resource by name

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 <[email protected]>
Tested-by: Benjamin Gaignard <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
---
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

2018-01-08 13:29:51

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 14/20] clocksource/drivers/stm32: Encapsulate the timer width sorting out function

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 <[email protected]>
Tested-by: Benjamin Gaignard <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
---
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

2018-01-08 13:30:00

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 17/20] clocksource/drivers/stm32: Encapsulate more the clockevent code

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 <[email protected]>
Tested-by: Benjamin Gaignard <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
---
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

2018-01-08 13:30:02

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 20/20] clocksource/drivers/stm32: Start the timer's counter sooner

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 <[email protected]>
Tested-by: Benjamin Gaignard <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
---
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

2018-01-08 13:29:58

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 16/20] clocksource/drivers/stm32: Add the oneshot mode

From: Benjamin Gaignard <[email protected]>

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.

Signed-off-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Tested-by: Benjamin Gaignard <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
---
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

2018-01-08 13:30:26

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 19/20] clocksource/drivers/stm32: Add the timer delay

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

Signed-off-by: Daniel Lezcano <[email protected]>
Tested-by: Benjamin Gaignard <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
---
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

2018-01-08 13:31:11

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 18/20] clocksource/drivers/stm32: Add the clocksource

From: Benjamin Gaignard <[email protected]>

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

Signed-off-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Tested-by: Benjamin Gaignard <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
---
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

2018-01-08 13:31:33

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 15/20] clocksource/drivers/stm32: Compute a prescaler value with a targeted rate

From: Benjamin Gaignard <[email protected]>

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.

Signed-off-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Tested-by: Benjamin Gaignard <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
---
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

2018-01-08 13:32:09

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 13/20] clocksource/drivers/stm32: Use the node name as timer name

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 <[email protected]>
Tested-by: Benjamin Gaignard <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
---
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

2018-01-08 13:29:46

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 09/20] clocksource/drivers/timer-of: Store the device node pointer

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 <[email protected]>
Tested-by: Benjamin Gaignard <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
---
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 3f708f1..a5478f3 100644
--- a/drivers/clocksource/timer-of.h
+++ b/drivers/clocksource/timer-of.h
@@ -33,6 +33,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

2018-01-08 13:32:27

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 12/20] clocksource/drivers/stm32: Convert the driver to timer-of

From: Benjamin Gaignard <[email protected]>

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 <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Tested-by: Benjamin Gaignard <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
---
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

2018-01-08 13:32:50

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 11/20] clocksource/drivers/stm32: Fix kernel panic with multiple timers

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: [email protected]
Signed-off-by: Daniel Lezcano <[email protected]>
Tested-by: Benjamin Gaignard <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
---
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

2018-01-08 13:33:13

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 08/20] clocksource/drivers/spreadtrum: Add timer driver for Spreadtrum SC9860 platform

From: Baolin Wang <[email protected]>

The Spreadtrum SC9860 platform will use the architected timers as local
clock events, but we also need a broadcast timer device to wakeup the
cpus when the cpus are in sleep mode.

The Spreadtrum timer can support 32bit or 64bit counter, as well as
supporting period mode or one-shot mode.

Signed-off-by: Baolin Wang <[email protected]>
Acked-by: Philippe Ombredanne <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
---
drivers/clocksource/Kconfig | 7 ++
drivers/clocksource/Makefile | 1 +
drivers/clocksource/timer-sprd.c | 159 +++++++++++++++++++++++++++++++++++++++
3 files changed, 167 insertions(+)
create mode 100644 drivers/clocksource/timer-sprd.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index c729a88..9a6b087 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -441,6 +441,13 @@ config MTK_TIMER
help
Support for Mediatek timer driver.

+config SPRD_TIMER
+ bool "Spreadtrum timer driver" if COMPILE_TEST
+ depends on HAS_IOMEM
+ select TIMER_OF
+ help
+ Enables the support for the Spreadtrum timer driver.
+
config SYS_SUPPORTS_SH_MTU2
bool

diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 72711f1..d6dec44 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o
obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o
obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o
obj-$(CONFIG_OWL_TIMER) += owl-timer.o
+obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o

obj-$(CONFIG_ARC_TIMERS) += arc_timer.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
diff --git a/drivers/clocksource/timer-sprd.c b/drivers/clocksource/timer-sprd.c
new file mode 100644
index 0000000..ef9ebea
--- /dev/null
+++ b/drivers/clocksource/timer-sprd.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Spreadtrum Communications Inc.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include "timer-of.h"
+
+#define TIMER_NAME "sprd_timer"
+
+#define TIMER_LOAD_LO 0x0
+#define TIMER_LOAD_HI 0x4
+#define TIMER_VALUE_LO 0x8
+#define TIMER_VALUE_HI 0xc
+
+#define TIMER_CTL 0x10
+#define TIMER_CTL_PERIOD_MODE BIT(0)
+#define TIMER_CTL_ENABLE BIT(1)
+#define TIMER_CTL_64BIT_WIDTH BIT(16)
+
+#define TIMER_INT 0x14
+#define TIMER_INT_EN BIT(0)
+#define TIMER_INT_RAW_STS BIT(1)
+#define TIMER_INT_MASK_STS BIT(2)
+#define TIMER_INT_CLR BIT(3)
+
+#define TIMER_VALUE_SHDW_LO 0x18
+#define TIMER_VALUE_SHDW_HI 0x1c
+
+#define TIMER_VALUE_LO_MASK GENMASK(31, 0)
+
+static void sprd_timer_enable(void __iomem *base, u32 flag)
+{
+ u32 val = readl_relaxed(base + TIMER_CTL);
+
+ val |= TIMER_CTL_ENABLE;
+ if (flag & TIMER_CTL_64BIT_WIDTH)
+ val |= TIMER_CTL_64BIT_WIDTH;
+ else
+ val &= ~TIMER_CTL_64BIT_WIDTH;
+
+ if (flag & TIMER_CTL_PERIOD_MODE)
+ val |= TIMER_CTL_PERIOD_MODE;
+ else
+ val &= ~TIMER_CTL_PERIOD_MODE;
+
+ writel_relaxed(val, base + TIMER_CTL);
+}
+
+static void sprd_timer_disable(void __iomem *base)
+{
+ u32 val = readl_relaxed(base + TIMER_CTL);
+
+ val &= ~TIMER_CTL_ENABLE;
+ writel_relaxed(val, base + TIMER_CTL);
+}
+
+static void sprd_timer_update_counter(void __iomem *base, unsigned long cycles)
+{
+ writel_relaxed(cycles & TIMER_VALUE_LO_MASK, base + TIMER_LOAD_LO);
+ writel_relaxed(0, base + TIMER_LOAD_HI);
+}
+
+static void sprd_timer_enable_interrupt(void __iomem *base)
+{
+ writel_relaxed(TIMER_INT_EN, base + TIMER_INT);
+}
+
+static void sprd_timer_clear_interrupt(void __iomem *base)
+{
+ u32 val = readl_relaxed(base + TIMER_INT);
+
+ val |= TIMER_INT_CLR;
+ writel_relaxed(val, base + TIMER_INT);
+}
+
+static int sprd_timer_set_next_event(unsigned long cycles,
+ struct clock_event_device *ce)
+{
+ struct timer_of *to = to_timer_of(ce);
+
+ sprd_timer_disable(timer_of_base(to));
+ sprd_timer_update_counter(timer_of_base(to), cycles);
+ sprd_timer_enable(timer_of_base(to), 0);
+
+ return 0;
+}
+
+static int sprd_timer_set_periodic(struct clock_event_device *ce)
+{
+ struct timer_of *to = to_timer_of(ce);
+
+ sprd_timer_disable(timer_of_base(to));
+ sprd_timer_update_counter(timer_of_base(to), timer_of_period(to));
+ sprd_timer_enable(timer_of_base(to), TIMER_CTL_PERIOD_MODE);
+
+ return 0;
+}
+
+static int sprd_timer_shutdown(struct clock_event_device *ce)
+{
+ struct timer_of *to = to_timer_of(ce);
+
+ sprd_timer_disable(timer_of_base(to));
+ return 0;
+}
+
+static irqreturn_t sprd_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *ce = (struct clock_event_device *)dev_id;
+ struct timer_of *to = to_timer_of(ce);
+
+ sprd_timer_clear_interrupt(timer_of_base(to));
+
+ if (clockevent_state_oneshot(ce))
+ sprd_timer_disable(timer_of_base(to));
+
+ ce->event_handler(ce);
+ return IRQ_HANDLED;
+}
+
+static struct timer_of to = {
+ .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
+
+ .clkevt = {
+ .name = TIMER_NAME,
+ .rating = 300,
+ .features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_PERIODIC |
+ CLOCK_EVT_FEAT_ONESHOT,
+ .set_state_shutdown = sprd_timer_shutdown,
+ .set_state_periodic = sprd_timer_set_periodic,
+ .set_next_event = sprd_timer_set_next_event,
+ .cpumask = cpu_possible_mask,
+ },
+
+ .of_irq = {
+ .handler = sprd_timer_interrupt,
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ },
+};
+
+static int __init sprd_timer_init(struct device_node *np)
+{
+ int ret;
+
+ ret = timer_of_init(np, &to);
+ if (ret)
+ return ret;
+
+ sprd_timer_enable_interrupt(timer_of_base(&to));
+ clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
+ 1, UINT_MAX);
+
+ return 0;
+}
+
+TIMER_OF_DECLARE(sc9860_timer, "sprd,sc9860-timer", sprd_timer_init);
--
2.7.4

2018-01-08 13:29:36

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 06/20] clocksource/drivers/timer-of: Add kernel documentation

The current code has no comment, neither function description. Fix this by
adding a kernel doc format for the function description.

Signed-off-by: Daniel Lezcano <[email protected]>
---
drivers/clocksource/timer-of.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)

diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c
index ad55654..2af8b8a 100644
--- a/drivers/clocksource/timer-of.c
+++ b/drivers/clocksource/timer-of.c
@@ -24,6 +24,12 @@

#include "timer-of.h"

+/**
+ * timer_of_irq_exit - Release the interrupt
+ * @of_irq: an of_timer_irq structure pointer
+ *
+ * Free the irq resource
+ */
static __init void timer_of_irq_exit(struct of_timer_irq *of_irq)
{
struct timer_of *to = container_of(of_irq, struct timer_of, of_irq);
@@ -34,6 +40,22 @@ static __init void timer_of_irq_exit(struct of_timer_irq *of_irq)
free_irq(of_irq->irq, clkevt);
}

+/**
+ * timer_of_irq_init - Request the interrupt
+ * @np: a device tree node pointer
+ * @of_irq: an of_timer_irq structure pointer
+ *
+ * Get the interrupt number from the DT from its definition and
+ * request it. The interrupt is get by fallbacking as follow:
+ *
+ * - Get interrupt number by name
+ * - Get interrupt number by index
+ *
+ * When the interrupt is per cpu, 'request_percpu_irq' is called
+ * otherwise, 'request_irq' is used.
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
static __init int timer_of_irq_init(struct device_node *np,
struct of_timer_irq *of_irq)
{
@@ -72,6 +94,13 @@ static __init int timer_of_irq_init(struct device_node *np,
return 0;
}

+/**
+ * timer_of_clk_exit - Release the clock resources
+ * @of_clk: a of_timer_clk structure pointer
+ *
+ * Disables and release the refcount on the clk
+ *
+ */
static __init void timer_of_clk_exit(struct of_timer_clk *of_clk)
{
of_clk->rate = 0;
@@ -79,6 +108,15 @@ static __init void timer_of_clk_exit(struct of_timer_clk *of_clk)
clk_put(of_clk->clk);
}

+/**
+ * timer_of_clk_init - Initialize the clock resources
+ * @np: a device tree node pointer
+ * @of_clk: a of_timer_clk structure pointer
+ *
+ * Get the clock by name or by index, enables it and get the rate
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
static __init int timer_of_clk_init(struct device_node *np,
struct of_timer_clk *of_clk)
{
--
2.7.4

2018-01-08 13:33:51

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 07/20] dt-bindings: clocksource: Add Spreadtrum SC9860 timer

From: Baolin Wang <[email protected]>

This patch adds documentation of device tree bindings for the timers
found on Spreadtrum SC9860 platform.

Signed-off-by: Baolin Wang <[email protected]>
Acked-by: Rob Herring <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
---
.../bindings/timer/spreadtrum,sprd-timer.txt | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 Documentation/devicetree/bindings/timer/spreadtrum,sprd-timer.txt

diff --git a/Documentation/devicetree/bindings/timer/spreadtrum,sprd-timer.txt b/Documentation/devicetree/bindings/timer/spreadtrum,sprd-timer.txt
new file mode 100644
index 0000000..6d97e7d
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/spreadtrum,sprd-timer.txt
@@ -0,0 +1,20 @@
+Spreadtrum timers
+
+The Spreadtrum SC9860 platform provides 3 general-purpose timers.
+These timers can support 32bit or 64bit counter, as well as supporting
+period mode or one-shot mode, and they are can be wakeup source
+during deep sleep.
+
+Required properties:
+- compatible: should be "sprd,sc9860-timer" for SC9860 platform.
+- reg: The register address of the timer device.
+- interrupts: Should contain the interrupt for the timer device.
+- clocks: The phandle to the source clock (usually a 32.768 KHz fixed clock).
+
+Example:
+ timer@40050000 {
+ compatible = "sprd,sc9860-timer";
+ reg = <0 0x40050000 0 0x20>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ext_32k>;
+ };
--
2.7.4

2018-01-08 13:34:20

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 04/20] clocksource/drivers/tcb_clksrc: Fix clock speed message

From: Romain Izard <[email protected]>

The clock speed displayed at boot in an information message was 500 kHz
too high compared to its real value. As the value is not used anywhere,
there is no functional impact.

Fix the rounding formula to display the correct value.

Signed-off-by: Romain Izard <[email protected]>
Acked-by: Nicolas Ferre <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
---
drivers/clocksource/tcb_clksrc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c
index 9de47d4..43f4d5c 100644
--- a/drivers/clocksource/tcb_clksrc.c
+++ b/drivers/clocksource/tcb_clksrc.c
@@ -384,7 +384,7 @@ static int __init tcb_clksrc_init(void)

printk(bootinfo, clksrc.name, CONFIG_ATMEL_TCB_CLKSRC_BLOCK,
divided_rate / 1000000,
- ((divided_rate + 500000) % 1000000) / 1000);
+ ((divided_rate % 1000000) + 500) / 1000);

if (tc->tcb_config && tc->tcb_config->counter_width == 32) {
/* use apropriate function to read 32 bit counter */
--
2.7.4

2018-01-08 13:34:44

by Daniel Lezcano

[permalink] [raw]
Subject: [PATCH 02/20] clocksource/drivers/owl: Adopt TIMER_OF_DECLARE()

From: Andreas Färber <[email protected]>

Commit 1727339590fdb5a1ded881b540cd32121278d414 ("clocksource/drivers:
Rename CLOCKSOURCE_OF_DECLARE to TIMER_OF_DECLARE") deprecated
CLOCKSOURCE_OF_DECLARE(), so adopt the new macro TIMER_OF_DECLARE().

Reported-by: Daniel Lezcano <[email protected]>
Signed-off-by: Andreas Färber <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
---
drivers/clocksource/owl-timer.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clocksource/owl-timer.c b/drivers/clocksource/owl-timer.c
index c686305..9fb4333 100644
--- a/drivers/clocksource/owl-timer.c
+++ b/drivers/clocksource/owl-timer.c
@@ -168,5 +168,5 @@ static int __init owl_timer_init(struct device_node *node)

return 0;
}
-CLOCKSOURCE_OF_DECLARE(owl_s500, "actions,s500-timer", owl_timer_init);
-CLOCKSOURCE_OF_DECLARE(owl_s900, "actions,s900-timer", owl_timer_init);
+TIMER_OF_DECLARE(owl_s500, "actions,s500-timer", owl_timer_init);
+TIMER_OF_DECLARE(owl_s900, "actions,s900-timer", owl_timer_init);
--
2.7.4

2018-01-08 16:58:54

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PULL] clockevents for 4.16


* Daniel Lezcano <[email protected]> wrote:

>
> Hi Thomas,
>
> here are the changes for 4.16 synced with tip/timers/core:
>
> - Change the macro name to TIMER_OF_DECLARE for the owl driver (Andreas
> F?rber)
>
> - Add the S700 definition and the compatible string for the owl driver
> (Andreas F?rber)
>
> - Add the new spreadtrum timer driver for the SC9860 platform (Baolin Wang)
>
> - Use the timer-of API, compute the prescaler based on the target
> frequency, add the oneshot mode and the clocksource for the stm32
> (Benjamin Gaignard)
>
> - Fix the clock speed message for the tcb clocksource (Romain Izard)
>
> - Improve the timer-of code by adding documentation and unifying the
> function names (Daniel Lezcano)
>
> - Fix a kernel panic with multiple timers defined in the DT for the
> stm32 (Daniel Lezcano)
>
> - Consolidate and add the delay timer for the stm32 (Daniel Lezcano)
>
> Thanks!
>
> -- Daniel
>
> The following changes since commit 29f1b2b0fecfae69e31833836f1da3136696eee5:
>
> posix-timers: Prevent UB from shifting negative signed value
> (2018-01-04 14:57:10 +0100)
>
> are available in the git repository at:
>
> https://git.linaro.org/people/daniel.lezcano/linux.git clockevents/4.16
>
> for you to fetch changes up to 322fd24f5e67c396f04bef01ed33ac6bfca46bcd:
>
> clocksource/drivers/stm32: Start the timer's counter sooner
> (2018-01-08 12:10:02 +0100)
>
> ----------------------------------------------------------------
> Andreas F?rber (3):
> dt-bindings: timer: Add Actions Semi S700
> clocksource/drivers/owl: Adopt TIMER_OF_DECLARE()
> clocksource/drivers/owl: Add the S700
>
> Baolin Wang (2):
> dt-bindings: clocksource: Add Spreadtrum SC9860 timer
> clocksource/drivers/spreadtrum: Add timer driver for Spreadtrum
> SC9860 platform
>
> 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 (10):
> clocksource/drivers/timer-of: Fix function names
> clocksource/drivers/timer-of: Add kernel documentation
> 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
>
> Romain Izard (1):
> clocksource/drivers/tcb_clksrc: Fix clock speed message
>
> .../bindings/timer/actions,owl-timer.txt | 1 +
> .../bindings/timer/spreadtrum,sprd-timer.txt | 20 ++
> drivers/clocksource/Kconfig | 8 +
> drivers/clocksource/Makefile | 1 +
> drivers/clocksource/owl-timer.c | 5 +-
> drivers/clocksource/tcb_clksrc.c | 2 +-
> drivers/clocksource/timer-of.c | 85 +++--
> drivers/clocksource/timer-of.h | 1 +
> drivers/clocksource/timer-sprd.c | 159 +++++++++
> drivers/clocksource/timer-stm32.c | 358
> +++++++++++++++------
> 10 files changed, 508 insertions(+), 132 deletions(-)
> create mode 100644
> Documentation/devicetree/bindings/timer/spreadtrum,sprd-timer.txt
> create mode 100644 drivers/clocksource/timer-sprd.c

Hi, I've applied the patches tip:timers/core, with a number of minor typo/spelling
and readability edits to changelogs and code comments.

Thanks,

Ingo

2018-01-08 17:07:27

by Daniel Lezcano

[permalink] [raw]
Subject: Re: [PULL] clockevents for 4.16

On 08/01/2018 17:58, Ingo Molnar wrote:
>
> * Daniel Lezcano <[email protected]> wrote:
>
>>
>> Hi Thomas,
>>
>> here are the changes for 4.16 synced with tip/timers/core:

[ ... ]


> Hi, I've applied the patches tip:timers/core, with a number of minor typo/spelling
> and readability edits to changelogs and code comments.

Thanks Ingo!


--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

Subject: [tip:timers/core] clocksource/drivers/timer-of: Fix function names

Commit-ID: 5bbf4ad945a9bb353e77ef71c753ca9bb1e3d978
Gitweb: https://git.kernel.org/tip/5bbf4ad945a9bb353e77ef71c753ca9bb1e3d978
Author: Daniel Lezcano <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:44 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:23 +0100

clocksource/drivers/timer-of: Fix function names

All the functions are not prefixed with 'timer_of_', fix the naming in order
to have the code consistent.

Signed-off-by: Daniel Lezcano <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
drivers/clocksource/timer-of.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c
index a319904..ad55654 100644
--- a/drivers/clocksource/timer-of.c
+++ b/drivers/clocksource/timer-of.c
@@ -24,7 +24,7 @@

#include "timer-of.h"

-static __init void timer_irq_exit(struct of_timer_irq *of_irq)
+static __init void timer_of_irq_exit(struct of_timer_irq *of_irq)
{
struct timer_of *to = container_of(of_irq, struct timer_of, of_irq);

@@ -34,8 +34,8 @@ static __init void timer_irq_exit(struct of_timer_irq *of_irq)
free_irq(of_irq->irq, clkevt);
}

-static __init int timer_irq_init(struct device_node *np,
- struct of_timer_irq *of_irq)
+static __init int timer_of_irq_init(struct device_node *np,
+ struct of_timer_irq *of_irq)
{
int ret;
struct timer_of *to = container_of(of_irq, struct timer_of, of_irq);
@@ -72,15 +72,15 @@ static __init int timer_irq_init(struct device_node *np,
return 0;
}

-static __init void timer_clk_exit(struct of_timer_clk *of_clk)
+static __init void timer_of_clk_exit(struct of_timer_clk *of_clk)
{
of_clk->rate = 0;
clk_disable_unprepare(of_clk->clk);
clk_put(of_clk->clk);
}

-static __init int timer_clk_init(struct device_node *np,
- struct of_timer_clk *of_clk)
+static __init int timer_of_clk_init(struct device_node *np,
+ struct of_timer_clk *of_clk)
{
int ret;

@@ -116,13 +116,13 @@ out_clk_put:
goto out;
}

-static __init void timer_base_exit(struct of_timer_base *of_base)
+static __init void timer_of_base_exit(struct of_timer_base *of_base)
{
iounmap(of_base->base);
}

-static __init int timer_base_init(struct device_node *np,
- 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;

@@ -141,21 +141,21 @@ int __init timer_of_init(struct device_node *np, struct timer_of *to)
int flags = 0;

if (to->flags & TIMER_OF_BASE) {
- ret = timer_base_init(np, &to->of_base);
+ ret = timer_of_base_init(np, &to->of_base);
if (ret)
goto out_fail;
flags |= TIMER_OF_BASE;
}

if (to->flags & TIMER_OF_CLOCK) {
- ret = timer_clk_init(np, &to->of_clk);
+ ret = timer_of_clk_init(np, &to->of_clk);
if (ret)
goto out_fail;
flags |= TIMER_OF_CLOCK;
}

if (to->flags & TIMER_OF_IRQ) {
- ret = timer_irq_init(np, &to->of_irq);
+ ret = timer_of_irq_init(np, &to->of_irq);
if (ret)
goto out_fail;
flags |= TIMER_OF_IRQ;
@@ -167,13 +167,13 @@ int __init timer_of_init(struct device_node *np, struct timer_of *to)

out_fail:
if (flags & TIMER_OF_IRQ)
- timer_irq_exit(&to->of_irq);
+ timer_of_irq_exit(&to->of_irq);

if (flags & TIMER_OF_CLOCK)
- timer_clk_exit(&to->of_clk);
+ timer_of_clk_exit(&to->of_clk);

if (flags & TIMER_OF_BASE)
- timer_base_exit(&to->of_base);
+ timer_of_base_exit(&to->of_base);
return ret;
}

@@ -187,11 +187,11 @@ out_fail:
void __init timer_of_cleanup(struct timer_of *to)
{
if (to->flags & TIMER_OF_IRQ)
- timer_irq_exit(&to->of_irq);
+ timer_of_irq_exit(&to->of_irq);

if (to->flags & TIMER_OF_CLOCK)
- timer_clk_exit(&to->of_clk);
+ timer_of_clk_exit(&to->of_clk);

if (to->flags & TIMER_OF_BASE)
- timer_base_exit(&to->of_base);
+ timer_of_base_exit(&to->of_base);
}

Subject: [tip:timers/core] clocksource/drivers/timer-of: Add kernel documentation

Commit-ID: cf7f46b9b12269d204b6acd0925704543adb6e05
Gitweb: https://git.kernel.org/tip/cf7f46b9b12269d204b6acd0925704543adb6e05
Author: Daniel Lezcano <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:45 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:23 +0100

clocksource/drivers/timer-of: Add kernel documentation

The current code has no comments, neither any function descriptions. Fix this by
adding function descriptions in kernel doc format.

Signed-off-by: Daniel Lezcano <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[ Spelling and style fixes. ]
Signed-off-by: Ingo Molnar <[email protected]>
---
drivers/clocksource/timer-of.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)

diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c
index ad55654..c1045b9 100644
--- a/drivers/clocksource/timer-of.c
+++ b/drivers/clocksource/timer-of.c
@@ -24,6 +24,12 @@

#include "timer-of.h"

+/**
+ * timer_of_irq_exit - Release the interrupt
+ * @of_irq: an of_timer_irq structure pointer
+ *
+ * Free the irq resource
+ */
static __init void timer_of_irq_exit(struct of_timer_irq *of_irq)
{
struct timer_of *to = container_of(of_irq, struct timer_of, of_irq);
@@ -34,6 +40,22 @@ static __init void timer_of_irq_exit(struct of_timer_irq *of_irq)
free_irq(of_irq->irq, clkevt);
}

+/**
+ * timer_of_irq_init - Request the interrupt
+ * @np: a device tree node pointer
+ * @of_irq: an of_timer_irq structure pointer
+ *
+ * Get the interrupt number from the DT from its definition and
+ * request it. The interrupt is gotten by falling back the following way:
+ *
+ * - Get interrupt number by name
+ * - Get interrupt number by index
+ *
+ * When the interrupt is per CPU, 'request_percpu_irq()' is called,
+ * otherwise 'request_irq()' is used.
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
static __init int timer_of_irq_init(struct device_node *np,
struct of_timer_irq *of_irq)
{
@@ -72,6 +94,12 @@ static __init int timer_of_irq_init(struct device_node *np,
return 0;
}

+/**
+ * timer_of_clk_exit - Release the clock resources
+ * @of_clk: a of_timer_clk structure pointer
+ *
+ * Disables and releases the refcount on the clk
+ */
static __init void timer_of_clk_exit(struct of_timer_clk *of_clk)
{
of_clk->rate = 0;
@@ -79,6 +107,15 @@ static __init void timer_of_clk_exit(struct of_timer_clk *of_clk)
clk_put(of_clk->clk);
}

+/**
+ * timer_of_clk_init - Initialize the clock resources
+ * @np: a device tree node pointer
+ * @of_clk: a of_timer_clk structure pointer
+ *
+ * Get the clock by name or by index, enable it and get the rate
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
static __init int timer_of_clk_init(struct device_node *np,
struct of_timer_clk *of_clk)
{

Subject: [tip:timers/core] clocksource/drivers/tcb_clksrc: Fix clock speed message

Commit-ID: 542f824607a6968ea443208ccfef3b7daf503559
Gitweb: https://git.kernel.org/tip/542f824607a6968ea443208ccfef3b7daf503559
Author: Romain Izard <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:43 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:23 +0100

clocksource/drivers/tcb_clksrc: Fix clock speed message

The clock speed displayed at boot in an information message was 500 kHz
too high compared to its real value. As the value is not used anywhere,
there is no functional impact.

Fix the rounding formula to display the correct value.

Signed-off-by: Romain Izard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Nicolas Ferre <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
drivers/clocksource/tcb_clksrc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c
index 9de47d4..43f4d5c 100644
--- a/drivers/clocksource/tcb_clksrc.c
+++ b/drivers/clocksource/tcb_clksrc.c
@@ -384,7 +384,7 @@ static int __init tcb_clksrc_init(void)

printk(bootinfo, clksrc.name, CONFIG_ATMEL_TCB_CLKSRC_BLOCK,
divided_rate / 1000000,
- ((divided_rate + 500000) % 1000000) / 1000);
+ ((divided_rate % 1000000) + 500) / 1000);

if (tc->tcb_config && tc->tcb_config->counter_width == 32) {
/* use apropriate function to read 32 bit counter */

Subject: [tip:timers/core] dt-bindings/clocksource: Add Spreadtrum SC9860 timer documentation

Commit-ID: 286f30db8b713b17e048bb86df1e257fd8695498
Gitweb: https://git.kernel.org/tip/286f30db8b713b17e048bb86df1e257fd8695498
Author: Baolin Wang <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:46 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:24 +0100

dt-bindings/clocksource: Add Spreadtrum SC9860 timer documentation

This patch adds documentation of device tree bindings for the timers
found on the Spreadtrum SC9860 platform.

Signed-off-by: Baolin Wang <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Rob Herring <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
.../bindings/timer/spreadtrum,sprd-timer.txt | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/Documentation/devicetree/bindings/timer/spreadtrum,sprd-timer.txt b/Documentation/devicetree/bindings/timer/spreadtrum,sprd-timer.txt
new file mode 100644
index 0000000..6d97e7d
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/spreadtrum,sprd-timer.txt
@@ -0,0 +1,20 @@
+Spreadtrum timers
+
+The Spreadtrum SC9860 platform provides 3 general-purpose timers.
+These timers can support 32bit or 64bit counter, as well as supporting
+period mode or one-shot mode, and they are can be wakeup source
+during deep sleep.
+
+Required properties:
+- compatible: should be "sprd,sc9860-timer" for SC9860 platform.
+- reg: The register address of the timer device.
+- interrupts: Should contain the interrupt for the timer device.
+- clocks: The phandle to the source clock (usually a 32.768 KHz fixed clock).
+
+Example:
+ timer@40050000 {
+ compatible = "sprd,sc9860-timer";
+ reg = <0 0x40050000 0 0x20>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ext_32k>;
+ };

Subject: [tip:timers/core] clocksource/drivers/timer-of: Store the device node pointer in 'struct timer_of'

Commit-ID: 1c63c1c089a48e1b1821a73dc36a3997ced2f82d
Gitweb: https://git.kernel.org/tip/1c63c1c089a48e1b1821a73dc36a3997ced2f82d
Author: Daniel Lezcano <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:48 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:24 +0100

clocksource/drivers/timer-of: Store the device node pointer in 'struct timer_of'

Under certain circumstances, some specific operations must be done with the
device node pointer, which 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.

Tested-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
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 c1045b9..25008d2 100644
--- a/drivers/clocksource/timer-of.c
+++ b/drivers/clocksource/timer-of.c
@@ -200,6 +200,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 3f708f1..a5478f3 100644
--- a/drivers/clocksource/timer-of.h
+++ b/drivers/clocksource/timer-of.h
@@ -33,6 +33,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;

Subject: [tip:timers/core] clocksource/drivers/timer-of: Don't request the resource by name

Commit-ID: 9aea417afa6bf52f15a5b194944b6a646d61af04
Gitweb: https://git.kernel.org/tip/9aea417afa6bf52f15a5b194944b6a646d61af04
Author: Daniel Lezcano <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:49 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:24 +0100

clocksource/drivers/timer-of: Don't request the resource by name

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
conflicts on some platforms which have the same name as the node.

Tested-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
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 25008d2..06ed88a 100644
--- a/drivers/clocksource/timer-of.c
+++ b/drivers/clocksource/timer-of.c
@@ -161,11 +161,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);
}


Subject: [tip:timers/core] clocksource/drivers/spreadtrum: Add timer driver for the Spreadtrum SC9860 platform

Commit-ID: 067bc9144766495650e621b79bd2bc199cee0769
Gitweb: https://git.kernel.org/tip/067bc9144766495650e621b79bd2bc199cee0769
Author: Baolin Wang <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:47 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:24 +0100

clocksource/drivers/spreadtrum: Add timer driver for the Spreadtrum SC9860 platform

The Spreadtrum SC9860 platform will use the architected timers as local
clock events, but we also need a broadcast timer device to wake up the
CPUs when the CPUs are in sleep mode.

The Spreadtrum timer can support 32-bit or 64-bit counters, as well as
supporting period mode or one-shot mode.

Signed-off-by: Baolin Wang <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Philippe Ombredanne <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[ Minor readability edits. ]
Signed-off-by: Ingo Molnar <[email protected]>
---
drivers/clocksource/Kconfig | 7 ++
drivers/clocksource/Makefile | 1 +
drivers/clocksource/timer-sprd.c | 159 +++++++++++++++++++++++++++++++++++++++
3 files changed, 167 insertions(+)

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index c729a88..0359812 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -441,6 +441,13 @@ config MTK_TIMER
help
Support for Mediatek timer driver.

+config SPRD_TIMER
+ bool "Spreadtrum timer driver" if COMPILE_TEST
+ depends on HAS_IOMEM
+ select TIMER_OF
+ help
+ Enables support for the Spreadtrum timer driver.
+
config SYS_SUPPORTS_SH_MTU2
bool

diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 72711f1..d6dec44 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o
obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o
obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o
obj-$(CONFIG_OWL_TIMER) += owl-timer.o
+obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o

obj-$(CONFIG_ARC_TIMERS) += arc_timer.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
diff --git a/drivers/clocksource/timer-sprd.c b/drivers/clocksource/timer-sprd.c
new file mode 100644
index 0000000..ef9ebea
--- /dev/null
+++ b/drivers/clocksource/timer-sprd.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Spreadtrum Communications Inc.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include "timer-of.h"
+
+#define TIMER_NAME "sprd_timer"
+
+#define TIMER_LOAD_LO 0x0
+#define TIMER_LOAD_HI 0x4
+#define TIMER_VALUE_LO 0x8
+#define TIMER_VALUE_HI 0xc
+
+#define TIMER_CTL 0x10
+#define TIMER_CTL_PERIOD_MODE BIT(0)
+#define TIMER_CTL_ENABLE BIT(1)
+#define TIMER_CTL_64BIT_WIDTH BIT(16)
+
+#define TIMER_INT 0x14
+#define TIMER_INT_EN BIT(0)
+#define TIMER_INT_RAW_STS BIT(1)
+#define TIMER_INT_MASK_STS BIT(2)
+#define TIMER_INT_CLR BIT(3)
+
+#define TIMER_VALUE_SHDW_LO 0x18
+#define TIMER_VALUE_SHDW_HI 0x1c
+
+#define TIMER_VALUE_LO_MASK GENMASK(31, 0)
+
+static void sprd_timer_enable(void __iomem *base, u32 flag)
+{
+ u32 val = readl_relaxed(base + TIMER_CTL);
+
+ val |= TIMER_CTL_ENABLE;
+ if (flag & TIMER_CTL_64BIT_WIDTH)
+ val |= TIMER_CTL_64BIT_WIDTH;
+ else
+ val &= ~TIMER_CTL_64BIT_WIDTH;
+
+ if (flag & TIMER_CTL_PERIOD_MODE)
+ val |= TIMER_CTL_PERIOD_MODE;
+ else
+ val &= ~TIMER_CTL_PERIOD_MODE;
+
+ writel_relaxed(val, base + TIMER_CTL);
+}
+
+static void sprd_timer_disable(void __iomem *base)
+{
+ u32 val = readl_relaxed(base + TIMER_CTL);
+
+ val &= ~TIMER_CTL_ENABLE;
+ writel_relaxed(val, base + TIMER_CTL);
+}
+
+static void sprd_timer_update_counter(void __iomem *base, unsigned long cycles)
+{
+ writel_relaxed(cycles & TIMER_VALUE_LO_MASK, base + TIMER_LOAD_LO);
+ writel_relaxed(0, base + TIMER_LOAD_HI);
+}
+
+static void sprd_timer_enable_interrupt(void __iomem *base)
+{
+ writel_relaxed(TIMER_INT_EN, base + TIMER_INT);
+}
+
+static void sprd_timer_clear_interrupt(void __iomem *base)
+{
+ u32 val = readl_relaxed(base + TIMER_INT);
+
+ val |= TIMER_INT_CLR;
+ writel_relaxed(val, base + TIMER_INT);
+}
+
+static int sprd_timer_set_next_event(unsigned long cycles,
+ struct clock_event_device *ce)
+{
+ struct timer_of *to = to_timer_of(ce);
+
+ sprd_timer_disable(timer_of_base(to));
+ sprd_timer_update_counter(timer_of_base(to), cycles);
+ sprd_timer_enable(timer_of_base(to), 0);
+
+ return 0;
+}
+
+static int sprd_timer_set_periodic(struct clock_event_device *ce)
+{
+ struct timer_of *to = to_timer_of(ce);
+
+ sprd_timer_disable(timer_of_base(to));
+ sprd_timer_update_counter(timer_of_base(to), timer_of_period(to));
+ sprd_timer_enable(timer_of_base(to), TIMER_CTL_PERIOD_MODE);
+
+ return 0;
+}
+
+static int sprd_timer_shutdown(struct clock_event_device *ce)
+{
+ struct timer_of *to = to_timer_of(ce);
+
+ sprd_timer_disable(timer_of_base(to));
+ return 0;
+}
+
+static irqreturn_t sprd_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *ce = (struct clock_event_device *)dev_id;
+ struct timer_of *to = to_timer_of(ce);
+
+ sprd_timer_clear_interrupt(timer_of_base(to));
+
+ if (clockevent_state_oneshot(ce))
+ sprd_timer_disable(timer_of_base(to));
+
+ ce->event_handler(ce);
+ return IRQ_HANDLED;
+}
+
+static struct timer_of to = {
+ .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
+
+ .clkevt = {
+ .name = TIMER_NAME,
+ .rating = 300,
+ .features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_PERIODIC |
+ CLOCK_EVT_FEAT_ONESHOT,
+ .set_state_shutdown = sprd_timer_shutdown,
+ .set_state_periodic = sprd_timer_set_periodic,
+ .set_next_event = sprd_timer_set_next_event,
+ .cpumask = cpu_possible_mask,
+ },
+
+ .of_irq = {
+ .handler = sprd_timer_interrupt,
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ },
+};
+
+static int __init sprd_timer_init(struct device_node *np)
+{
+ int ret;
+
+ ret = timer_of_init(np, &to);
+ if (ret)
+ return ret;
+
+ sprd_timer_enable_interrupt(timer_of_base(&to));
+ clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
+ 1, UINT_MAX);
+
+ return 0;
+}
+
+TIMER_OF_DECLARE(sc9860_timer, "sprd,sc9860-timer", sprd_timer_init);

Subject: [tip:timers/core] clocksource/drivers/stm32: Fix kernel panic with multiple timers

Commit-ID: e0aeca3d8cbaea514eb98df1149faa918f9ec42d
Gitweb: https://git.kernel.org/tip/e0aeca3d8cbaea514eb98df1149faa918f9ec42d
Author: Daniel Lezcano <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:50 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:25 +0100

clocksource/drivers/stm32: Fix kernel panic with multiple timers

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.

Tested-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
Cc: Alexandre Torgue <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
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 @@ err_iomap:
err_clk_enable:
clk_put(clk);
err_clk_get:
+ kfree(data);
return ret;
}


Subject: [tip:timers/core] clocksource/drivers/stm32: Convert the driver to timer_of primitives

Commit-ID: d04af4908a7283bc6ae0dd9475ccf807d094f8ba
Gitweb: https://git.kernel.org/tip/d04af4908a7283bc6ae0dd9475ccf807d094f8ba
Author: Benjamin Gaignard <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:51 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:25 +0100

clocksource/drivers/stm32: Convert the driver to timer_of primitives

Convert the driver to use the timer_of() helpers. This allows the removal of
a custom private structure, factors out and simplifies the code.

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

Tested-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
Cc: Alexandre Torgue <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
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 0359812..b3b4ed9 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);

Subject: [tip:timers/core] clocksource/drivers/stm32: Use the node name as timer name

Commit-ID: f2ed8ef1cea41c7e7e5d52199db9c822951ab101
Gitweb: https://git.kernel.org/tip/f2ed8ef1cea41c7e7e5d52199db9c822951ab101
Author: Daniel Lezcano <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:52 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:25 +0100

clocksource/drivers/stm32: Use the node name as timer name

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.

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

Tested-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
Cc: Alexandre Torgue <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
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;

Subject: [tip:timers/core] clocksource/drivers/stm32: Factor out the timer width sorting code

Commit-ID: 70c62cf910aeba7cb79f4ebc7e6c8edbb37a77f6
Gitweb: https://git.kernel.org/tip/70c62cf910aeba7cb79f4ebc7e6c8edbb37a77f6
Author: Daniel Lezcano <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:53 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:25 +0100

clocksource/drivers/stm32: Factor out the timer width sorting code

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

Tested-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
Cc: Alexandre Torgue <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[ Spelling fixes. ]
Signed-off-by: Ingo Molnar <[email protected]>
---
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..33c7c90 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 32-bit max value and read/return the result. If the timer
+ * is 32 bits wide, the result will be UINT_MAX, otherwise it will
+ * be truncated by the 16-bit register to USHRT_MAX.
+ *
+ * Returns UINT_MAX if the timer is 32 bits wide, USHRT_MAX if it is a
+ * 16 bits wide.
+ */
+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)

Subject: [tip:timers/core] clocksource/drivers/stm32: Compute a prescaler value with a targeted rate

Commit-ID: 4744daa10dcd3a1470fbeba4945fbf44dcb1b0d1
Gitweb: https://git.kernel.org/tip/4744daa10dcd3a1470fbeba4945fbf44dcb1b0d1
Author: Benjamin Gaignard <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:54 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:25 +0100

clocksource/drivers/stm32: Compute a prescaler value with a targeted rate

The prescaler value is arbitrarily set to 1024 without any regard to the
timer frequency. For 32-bit 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 16-bit timers a prescaler
value is needed if we don't want to wrap too often per second which is
inefficient and adds more and more error margin. With a targeted clock
of 10MHz, the 16 bits are precise enough whatever the timer frequency is
as we will compute the prescaler.

Tested-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
Cc: Alexandre Torgue <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
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 33c7c90..928ac28 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);

Subject: [tip:timers/core] clocksource/drivers/stm32: Add oneshot mode

Commit-ID: 8e82df381b676ae5f6c93ab4a75f56d8f61babc4
Gitweb: https://git.kernel.org/tip/8e82df381b676ae5f6c93ab4a75f56d8f61babc4
Author: Benjamin Gaignard <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:55 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:26 +0100

clocksource/drivers/stm32: Add oneshot mode

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

Instead of using the auto-reload register for periodic events, we switch
to 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.

Tested-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
Cc: Alexandre Torgue <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
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 928ac28..882037f 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);

Subject: [tip:timers/core] clocksource/drivers/stm32: Factor out more of the clockevent code

Commit-ID: 3c84e75b1e5d8406e12b533d44f54ad84d6e3bd6
Gitweb: https://git.kernel.org/tip/3c84e75b1e5d8406e12b533d44f54ad84d6e3bd6
Author: Daniel Lezcano <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:56 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:26 +0100

clocksource/drivers/stm32: Factor out more of the clockevent code

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

Tested-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
Cc: Alexandre Torgue <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[ Small edits. ]
Signed-off-by: Ingo Molnar <[email protected]>
---
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 882037f..0d37f1a 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 32 bits wide, the result will be UINT_MAX, otherwise it will
* be truncated by the 16-bit register to USHRT_MAX.
*
- * Returns UINT_MAX if the timer is 32 bits wide, USHRT_MAX if it is a
- * 16 bits wide.
*/
-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 16 bits. 32-bit 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;

Subject: [tip:timers/core] clocksource/drivers/stm32: Add clocksource functionality

Commit-ID: f5ef02bd0e8cf53472cc358a542121366add0c9a
Gitweb: https://git.kernel.org/tip/f5ef02bd0e8cf53472cc358a542121366add0c9a
Author: Benjamin Gaignard <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:57 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:26 +0100

clocksource/drivers/stm32: Add clocksource functionality

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

Tested-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
Cc: Alexandre Torgue <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
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 0d37f1a..21b7492 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
+ * 16-bit timers but only for the 32-bit one, so if no 32-bit
+ * timer is registered yet, we select this 32-bit 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;


Subject: [tip:timers/core] clocksource/drivers/stm32: Add the timer delay callback

Commit-ID: 81abdbbffd69fecdac37fe1d2b44a21227ee23d4
Gitweb: https://git.kernel.org/tip/81abdbbffd69fecdac37fe1d2b44a21227ee23d4
Author: Daniel Lezcano <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:58 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:26 +0100

clocksource/drivers/stm32: Add the timer delay callback

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

Tested-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
Cc: Alexandre Torgue <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
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 21b7492..c7d1dae 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,

Subject: [tip:timers/core] clocksource/drivers/stm32: Start the timer's counter sooner

Commit-ID: 103bb56a2831bfc7f2d442da9e47f89f37d34952
Gitweb: https://git.kernel.org/tip/103bb56a2831bfc7f2d442da9e47f89f37d34952
Author: Daniel Lezcano <[email protected]>
AuthorDate: Mon, 8 Jan 2018 14:28:59 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 8 Jan 2018 17:57:26 +0100

clocksource/drivers/stm32: Start the timer's counter sooner

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.

Tested-by: Benjamin Gaignard <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Acked-by: Benjamin Gaignard <[email protected]>
Cc: Alexandre Torgue <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Maxime Coquelin <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
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 c7d1dae..e5cdc3a 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);