diff mbox

[U-Boot] armv7m: Add SysTick timer driver

Message ID 1486133320-32334-1-git-send-email-phil.edworthy@renesas.com
State Superseded
Delegated to: Tom Rini
Headers show

Commit Message

Phil Edworthy Feb. 3, 2017, 2:48 p.m. UTC
The SysTick is a 24-bit down counter that is found on all ARM Cortex
M3, M4, M7 devices and is always located at a fixed address.

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
---
 arch/arm/cpu/armv7m/Makefile        |  2 +
 arch/arm/cpu/armv7m/systick-timer.c | 91 +++++++++++++++++++++++++++++++++++++
 2 files changed, 93 insertions(+)
 create mode 100644 arch/arm/cpu/armv7m/systick-timer.c

Comments

Tom Rini Feb. 5, 2017, 11:16 p.m. UTC | #1
On Fri, Feb 03, 2017 at 02:48:40PM +0000, Phil Edworthy wrote:

> The SysTick is a 24-bit down counter that is found on all ARM Cortex
> M3, M4, M7 devices and is always located at a fixed address.
> 
> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> ---
>  arch/arm/cpu/armv7m/Makefile        |  2 +
>  arch/arm/cpu/armv7m/systick-timer.c | 91 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 93 insertions(+)
>  create mode 100644 arch/arm/cpu/armv7m/systick-timer.c
> 
> diff --git a/arch/arm/cpu/armv7m/Makefile b/arch/arm/cpu/armv7m/Makefile
> index aff60e8..e1a6c40 100644
> --- a/arch/arm/cpu/armv7m/Makefile
> +++ b/arch/arm/cpu/armv7m/Makefile
> @@ -7,3 +7,5 @@
>  
>  extra-y := start.o
>  obj-y += cpu.o
> +
> +obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o
> diff --git a/arch/arm/cpu/armv7m/systick-timer.c b/arch/arm/cpu/armv7m/systick-timer.c
> new file mode 100644
> index 0000000..6ccc2fb
> --- /dev/null
> +++ b/arch/arm/cpu/armv7m/systick-timer.c
> @@ -0,0 +1,91 @@
> +/*
> + * ARM Cortex M3/M4/M7 SysTick timer driver
> + * (C) Copyright 2017 Renesas Electronics Europe Ltd
> + *
> + * Based on arch/arm/mach-stm32/stm32f1/timer.c
> + * (C) Copyright 2015
> + * Kamil Lulko, <kamil.lulko@gmail.com>
> + *
> + * Copyright 2015 ATS Advanced Telematics Systems GmbH
> + * Copyright 2015 Konsulko Group, Matt Porter <mporter@konsulko.com>
> + *
> + * SPDX-License-Identifier:     GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +/* SysTick Base Address - fixed for all Cortex M3, M4 and M7 devices */
> +#define SYSTICK_BASE		0xE000E010
> +
> +struct cm3_systick {
> +	uint32_t ctrl;
> +	uint32_t reload;
> +	uint32_t val;
> +	uint32_t calibration;
> +};
> +
> +#define TIMER_LOAD_VAL		0x00FFFFFF
> +#define SYSTICK_CTRL_EN		BIT(0)
> +/* Clock source: 0 = Ref clock, 1 = CPU clock */
> +#define SYSTICK_CTRL_CPU_CLK	BIT(2)
> +
> +/* read the 24-bit timer */
> +static ulong read_timer(void)
> +{
> +	struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> +
> +	/* The timer counts down, therefore convert to an incrementing timer */
> +	return TIMER_LOAD_VAL - readl(&systick->val);
> +}
> +
> +int timer_init(void)
> +{
> +	struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> +
> +	writel(TIMER_LOAD_VAL, &systick->reload);
> +	writel(TIMER_LOAD_VAL, &systick->val);
> +
> +#ifdef CONFIG_ARMCORTEXM3_SYSTICK_CPU
> +	/* Use CPU clock, no interrupts */
> +	writel(SYSTICK_CTRL_EN | SYSTICK_CTRL_CPU_CLK, &systick->ctrl);
> +#else
> +	/* Use external clock, no interrupts */
> +	writel(SYSTICK_CTRL_EN, &systick->ctrl);
> +#endif
> +
> +	gd->arch.tbl = 0;
> +	gd->arch.tbu = 0;
> +	gd->arch.lastinc = read_timer();
> +
> +	return 0;
> +}
> +
> +/* return milli-seconds timer value */
> +ulong get_timer(ulong base)
> +{
> +	unsigned long long t = get_ticks() * 1000;
> +
> +	return (ulong)((t / CONFIG_SYS_HZ_CLOCK)) - base;
> +}
> +
> +unsigned long long get_ticks(void)
> +{
> +	u32 now = read_timer();
> +
> +	if (now >= gd->arch.lastinc)
> +		gd->arch.tbl += (now - gd->arch.lastinc);
> +	else
> +		gd->arch.tbl += (TIMER_LOAD_VAL - gd->arch.lastinc) + now;
> +
> +	gd->arch.lastinc = now;
> +
> +	return gd->arch.tbl;
> +}
> +
> +ulong get_tbclk(void)
> +{
> +	return CONFIG_SYS_HZ_CLOCK;
> +}

And (cc'ing maintainers) we could use this in place of
arch/arm/mach-stm32/*/timer.c I assume, yes?  Thanks!
Kamil Lulko Feb. 7, 2017, 2:12 p.m. UTC | #2
On Mon, Feb 6, 2017 at 12:16 AM, Tom Rini <trini@konsulko.com> wrote:
>
> On Fri, Feb 03, 2017 at 02:48:40PM +0000, Phil Edworthy wrote:
>
> > The SysTick is a 24-bit down counter that is found on all ARM Cortex
> > M3, M4, M7 devices and is always located at a fixed address.
> >
> > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> > ---
> >  arch/arm/cpu/armv7m/Makefile        |  2 +
> >  arch/arm/cpu/armv7m/systick-timer.c | 91 +++++++++++++++++++++++++++++++++++++
> >  2 files changed, 93 insertions(+)
> >  create mode 100644 arch/arm/cpu/armv7m/systick-timer.c
> >
> > diff --git a/arch/arm/cpu/armv7m/Makefile b/arch/arm/cpu/armv7m/Makefile
> > index aff60e8..e1a6c40 100644
> > --- a/arch/arm/cpu/armv7m/Makefile
> > +++ b/arch/arm/cpu/armv7m/Makefile
> > @@ -7,3 +7,5 @@
> >
> >  extra-y := start.o
> >  obj-y += cpu.o
> > +
> > +obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o
> > diff --git a/arch/arm/cpu/armv7m/systick-timer.c b/arch/arm/cpu/armv7m/systick-timer.c
> > new file mode 100644
> > index 0000000..6ccc2fb
> > --- /dev/null
> > +++ b/arch/arm/cpu/armv7m/systick-timer.c
> > @@ -0,0 +1,91 @@
> > +/*
> > + * ARM Cortex M3/M4/M7 SysTick timer driver
> > + * (C) Copyright 2017 Renesas Electronics Europe Ltd
> > + *
> > + * Based on arch/arm/mach-stm32/stm32f1/timer.c
> > + * (C) Copyright 2015
> > + * Kamil Lulko, <kamil.lulko@gmail.com>
> > + *
> > + * Copyright 2015 ATS Advanced Telematics Systems GmbH
> > + * Copyright 2015 Konsulko Group, Matt Porter <mporter@konsulko.com>
> > + *
> > + * SPDX-License-Identifier:     GPL-2.0+
> > + */
> > +
> > +#include <common.h>
> > +#include <asm/io.h>
> > +
> > +DECLARE_GLOBAL_DATA_PTR;
> > +
> > +/* SysTick Base Address - fixed for all Cortex M3, M4 and M7 devices */
> > +#define SYSTICK_BASE         0xE000E010
> > +
> > +struct cm3_systick {
> > +     uint32_t ctrl;
> > +     uint32_t reload;
> > +     uint32_t val;
> > +     uint32_t calibration;
> > +};
> > +
> > +#define TIMER_LOAD_VAL               0x00FFFFFF
> > +#define SYSTICK_CTRL_EN              BIT(0)
> > +/* Clock source: 0 = Ref clock, 1 = CPU clock */
> > +#define SYSTICK_CTRL_CPU_CLK BIT(2)
> > +
> > +/* read the 24-bit timer */
> > +static ulong read_timer(void)
> > +{
> > +     struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> > +
> > +     /* The timer counts down, therefore convert to an incrementing timer */
> > +     return TIMER_LOAD_VAL - readl(&systick->val);
> > +}
> > +
> > +int timer_init(void)
> > +{
> > +     struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> > +
> > +     writel(TIMER_LOAD_VAL, &systick->reload);
> > +     writel(TIMER_LOAD_VAL, &systick->val);
> > +
> > +#ifdef CONFIG_ARMCORTEXM3_SYSTICK_CPU
> > +     /* Use CPU clock, no interrupts */
> > +     writel(SYSTICK_CTRL_EN | SYSTICK_CTRL_CPU_CLK, &systick->ctrl);
> > +#else
> > +     /* Use external clock, no interrupts */
> > +     writel(SYSTICK_CTRL_EN, &systick->ctrl);
> > +#endif
> > +
> > +     gd->arch.tbl = 0;
> > +     gd->arch.tbu = 0;
> > +     gd->arch.lastinc = read_timer();
> > +
> > +     return 0;
> > +}
> > +
> > +/* return milli-seconds timer value */
> > +ulong get_timer(ulong base)
> > +{
> > +     unsigned long long t = get_ticks() * 1000;
> > +
> > +     return (ulong)((t / CONFIG_SYS_HZ_CLOCK)) - base;
> > +}
> > +
> > +unsigned long long get_ticks(void)
> > +{
> > +     u32 now = read_timer();
> > +
> > +     if (now >= gd->arch.lastinc)
> > +             gd->arch.tbl += (now - gd->arch.lastinc);
> > +     else
> > +             gd->arch.tbl += (TIMER_LOAD_VAL - gd->arch.lastinc) + now;
> > +
> > +     gd->arch.lastinc = now;
> > +
> > +     return gd->arch.tbl;
> > +}
> > +
> > +ulong get_tbclk(void)
> > +{
> > +     return CONFIG_SYS_HZ_CLOCK;
> > +}
>
> And (cc'ing maintainers) we could use this in place of
> arch/arm/mach-stm32/*/timer.c I assume, yes?  Thanks!
>
> --
> Tom

Yes, however as far as I remember the systick is only 24-bit and
usually runs on CPU clock so it will roll over too fast to be useful
without using interrupts. Maybe I have missed something?

/Kamil
Phil Edworthy Feb. 7, 2017, 2:19 p.m. UTC | #3
Hi Kamil,

On 07 February 2017 14:12, Kamil Lulko wrote:
> On Mon, Feb 6, 2017 at 12:16 AM, Tom Rini <trini@konsulko.com> wrote:
> > On Fri, Feb 03, 2017 at 02:48:40PM +0000, Phil Edworthy wrote:
> >
> > > The SysTick is a 24-bit down counter that is found on all ARM Cortex
> > > M3, M4, M7 devices and is always located at a fixed address.
> > >
> > > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> > > ---
> > >  arch/arm/cpu/armv7m/Makefile        |  2 +
> > >  arch/arm/cpu/armv7m/systick-timer.c | 91
> +++++++++++++++++++++++++++++++++++++
> > >  2 files changed, 93 insertions(+)
> > >  create mode 100644 arch/arm/cpu/armv7m/systick-timer.c
> > >
> > > diff --git a/arch/arm/cpu/armv7m/Makefile
> b/arch/arm/cpu/armv7m/Makefile
> > > index aff60e8..e1a6c40 100644
> > > --- a/arch/arm/cpu/armv7m/Makefile
> > > +++ b/arch/arm/cpu/armv7m/Makefile
> > > @@ -7,3 +7,5 @@
> > >
> > >  extra-y := start.o
> > >  obj-y += cpu.o
> > > +
> > > +obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o
> > > diff --git a/arch/arm/cpu/armv7m/systick-timer.c
> b/arch/arm/cpu/armv7m/systick-timer.c
> > > new file mode 100644
> > > index 0000000..6ccc2fb
> > > --- /dev/null
> > > +++ b/arch/arm/cpu/armv7m/systick-timer.c
> > > @@ -0,0 +1,91 @@
> > > +/*
> > > + * ARM Cortex M3/M4/M7 SysTick timer driver
> > > + * (C) Copyright 2017 Renesas Electronics Europe Ltd
> > > + *
> > > + * Based on arch/arm/mach-stm32/stm32f1/timer.c
> > > + * (C) Copyright 2015
> > > + * Kamil Lulko, <kamil.lulko@gmail.com>
> > > + *
> > > + * Copyright 2015 ATS Advanced Telematics Systems GmbH
> > > + * Copyright 2015 Konsulko Group, Matt Porter <mporter@konsulko.com>
> > > + *
> > > + * SPDX-License-Identifier:     GPL-2.0+
> > > + */
> > > +
> > > +#include <common.h>
> > > +#include <asm/io.h>
> > > +
> > > +DECLARE_GLOBAL_DATA_PTR;
> > > +
> > > +/* SysTick Base Address - fixed for all Cortex M3, M4 and M7 devices */
> > > +#define SYSTICK_BASE         0xE000E010
> > > +
> > > +struct cm3_systick {
> > > +     uint32_t ctrl;
> > > +     uint32_t reload;
> > > +     uint32_t val;
> > > +     uint32_t calibration;
> > > +};
> > > +
> > > +#define TIMER_LOAD_VAL               0x00FFFFFF
> > > +#define SYSTICK_CTRL_EN              BIT(0)
> > > +/* Clock source: 0 = Ref clock, 1 = CPU clock */
> > > +#define SYSTICK_CTRL_CPU_CLK BIT(2)
> > > +
> > > +/* read the 24-bit timer */
> > > +static ulong read_timer(void)
> > > +{
> > > +     struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> > > +
> > > +     /* The timer counts down, therefore convert to an incrementing timer */
> > > +     return TIMER_LOAD_VAL - readl(&systick->val);
> > > +}
> > > +
> > > +int timer_init(void)
> > > +{
> > > +     struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> > > +
> > > +     writel(TIMER_LOAD_VAL, &systick->reload);
> > > +     writel(TIMER_LOAD_VAL, &systick->val);
> > > +
> > > +#ifdef CONFIG_ARMCORTEXM3_SYSTICK_CPU
> > > +     /* Use CPU clock, no interrupts */
> > > +     writel(SYSTICK_CTRL_EN | SYSTICK_CTRL_CPU_CLK, &systick->ctrl);
> > > +#else
> > > +     /* Use external clock, no interrupts */
> > > +     writel(SYSTICK_CTRL_EN, &systick->ctrl);
> > > +#endif
> > > +
> > > +     gd->arch.tbl = 0;
> > > +     gd->arch.tbu = 0;
> > > +     gd->arch.lastinc = read_timer();
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +/* return milli-seconds timer value */
> > > +ulong get_timer(ulong base)
> > > +{
> > > +     unsigned long long t = get_ticks() * 1000;
> > > +
> > > +     return (ulong)((t / CONFIG_SYS_HZ_CLOCK)) - base;
> > > +}
> > > +
> > > +unsigned long long get_ticks(void)
> > > +{
> > > +     u32 now = read_timer();
> > > +
> > > +     if (now >= gd->arch.lastinc)
> > > +             gd->arch.tbl += (now - gd->arch.lastinc);
> > > +     else
> > > +             gd->arch.tbl += (TIMER_LOAD_VAL - gd->arch.lastinc) + now;
> > > +
> > > +     gd->arch.lastinc = now;
> > > +
> > > +     return gd->arch.tbl;
> > > +}
> > > +
> > > +ulong get_tbclk(void)
> > > +{
> > > +     return CONFIG_SYS_HZ_CLOCK;
> > > +}
> >
> > And (cc'ing maintainers) we could use this in place of
> > arch/arm/mach-stm32/*/timer.c I assume, yes?  Thanks!
> >
> > --
> > Tom
> 
> Yes, however as far as I remember the systick is only 24-bit and
> usually runs on CPU clock so it will roll over too fast to be useful
> without using interrupts. Maybe I have missed something?

Yes, it is only a 24-bit counter. On the device I am using, the clock
is not the cpu clock, but a low speed clock at 6.25MHz. Even at that
low clock it will still wrap every ~2.6 seconds.

> /Kamil

Thanks
Phil
Tom Rini Feb. 7, 2017, 2:23 p.m. UTC | #4
On Tue, Feb 07, 2017 at 02:19:39PM +0000, Phil Edworthy wrote:
> Hi Kamil,
> 
> On 07 February 2017 14:12, Kamil Lulko wrote:
> > On Mon, Feb 6, 2017 at 12:16 AM, Tom Rini <trini@konsulko.com> wrote:
> > > On Fri, Feb 03, 2017 at 02:48:40PM +0000, Phil Edworthy wrote:
> > >
> > > > The SysTick is a 24-bit down counter that is found on all ARM Cortex
> > > > M3, M4, M7 devices and is always located at a fixed address.
> > > >
> > > > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> > > > ---
> > > >  arch/arm/cpu/armv7m/Makefile        |  2 +
> > > >  arch/arm/cpu/armv7m/systick-timer.c | 91
> > +++++++++++++++++++++++++++++++++++++
> > > >  2 files changed, 93 insertions(+)
> > > >  create mode 100644 arch/arm/cpu/armv7m/systick-timer.c
> > > >
> > > > diff --git a/arch/arm/cpu/armv7m/Makefile
> > b/arch/arm/cpu/armv7m/Makefile
> > > > index aff60e8..e1a6c40 100644
> > > > --- a/arch/arm/cpu/armv7m/Makefile
> > > > +++ b/arch/arm/cpu/armv7m/Makefile
> > > > @@ -7,3 +7,5 @@
> > > >
> > > >  extra-y := start.o
> > > >  obj-y += cpu.o
> > > > +
> > > > +obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o
> > > > diff --git a/arch/arm/cpu/armv7m/systick-timer.c
> > b/arch/arm/cpu/armv7m/systick-timer.c
> > > > new file mode 100644
> > > > index 0000000..6ccc2fb
> > > > --- /dev/null
> > > > +++ b/arch/arm/cpu/armv7m/systick-timer.c
> > > > @@ -0,0 +1,91 @@
> > > > +/*
> > > > + * ARM Cortex M3/M4/M7 SysTick timer driver
> > > > + * (C) Copyright 2017 Renesas Electronics Europe Ltd
> > > > + *
> > > > + * Based on arch/arm/mach-stm32/stm32f1/timer.c
> > > > + * (C) Copyright 2015
> > > > + * Kamil Lulko, <kamil.lulko@gmail.com>
> > > > + *
> > > > + * Copyright 2015 ATS Advanced Telematics Systems GmbH
> > > > + * Copyright 2015 Konsulko Group, Matt Porter <mporter@konsulko.com>
> > > > + *
> > > > + * SPDX-License-Identifier:     GPL-2.0+
> > > > + */
> > > > +
> > > > +#include <common.h>
> > > > +#include <asm/io.h>
> > > > +
> > > > +DECLARE_GLOBAL_DATA_PTR;
> > > > +
> > > > +/* SysTick Base Address - fixed for all Cortex M3, M4 and M7 devices */
> > > > +#define SYSTICK_BASE         0xE000E010
> > > > +
> > > > +struct cm3_systick {
> > > > +     uint32_t ctrl;
> > > > +     uint32_t reload;
> > > > +     uint32_t val;
> > > > +     uint32_t calibration;
> > > > +};
> > > > +
> > > > +#define TIMER_LOAD_VAL               0x00FFFFFF
> > > > +#define SYSTICK_CTRL_EN              BIT(0)
> > > > +/* Clock source: 0 = Ref clock, 1 = CPU clock */
> > > > +#define SYSTICK_CTRL_CPU_CLK BIT(2)
> > > > +
> > > > +/* read the 24-bit timer */
> > > > +static ulong read_timer(void)
> > > > +{
> > > > +     struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> > > > +
> > > > +     /* The timer counts down, therefore convert to an incrementing timer */
> > > > +     return TIMER_LOAD_VAL - readl(&systick->val);
> > > > +}
> > > > +
> > > > +int timer_init(void)
> > > > +{
> > > > +     struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> > > > +
> > > > +     writel(TIMER_LOAD_VAL, &systick->reload);
> > > > +     writel(TIMER_LOAD_VAL, &systick->val);
> > > > +
> > > > +#ifdef CONFIG_ARMCORTEXM3_SYSTICK_CPU
> > > > +     /* Use CPU clock, no interrupts */
> > > > +     writel(SYSTICK_CTRL_EN | SYSTICK_CTRL_CPU_CLK, &systick->ctrl);
> > > > +#else
> > > > +     /* Use external clock, no interrupts */
> > > > +     writel(SYSTICK_CTRL_EN, &systick->ctrl);
> > > > +#endif
> > > > +
> > > > +     gd->arch.tbl = 0;
> > > > +     gd->arch.tbu = 0;
> > > > +     gd->arch.lastinc = read_timer();
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +/* return milli-seconds timer value */
> > > > +ulong get_timer(ulong base)
> > > > +{
> > > > +     unsigned long long t = get_ticks() * 1000;
> > > > +
> > > > +     return (ulong)((t / CONFIG_SYS_HZ_CLOCK)) - base;
> > > > +}
> > > > +
> > > > +unsigned long long get_ticks(void)
> > > > +{
> > > > +     u32 now = read_timer();
> > > > +
> > > > +     if (now >= gd->arch.lastinc)
> > > > +             gd->arch.tbl += (now - gd->arch.lastinc);
> > > > +     else
> > > > +             gd->arch.tbl += (TIMER_LOAD_VAL - gd->arch.lastinc) + now;
> > > > +
> > > > +     gd->arch.lastinc = now;
> > > > +
> > > > +     return gd->arch.tbl;
> > > > +}
> > > > +
> > > > +ulong get_tbclk(void)
> > > > +{
> > > > +     return CONFIG_SYS_HZ_CLOCK;
> > > > +}
> > >
> > > And (cc'ing maintainers) we could use this in place of
> > > arch/arm/mach-stm32/*/timer.c I assume, yes?  Thanks!
> > >
> > > --
> > > Tom
> > 
> > Yes, however as far as I remember the systick is only 24-bit and
> > usually runs on CPU clock so it will roll over too fast to be useful
> > without using interrupts. Maybe I have missed something?
> 
> Yes, it is only a 24-bit counter. On the device I am using, the clock
> is not the cpu clock, but a low speed clock at 6.25MHz. Even at that
> low clock it will still wrap every ~2.6 seconds.

So are you able to use the timer then, given the quick overflow?
Phil Edworthy Feb. 7, 2017, 2:34 p.m. UTC | #5
Hi Tom,

On 07 February 2017 14:23, Tom Rini wrote:
> On Tue, Feb 07, 2017 at 02:19:39PM +0000, Phil Edworthy wrote:
> > Hi Kamil,
> >
> > On 07 February 2017 14:12, Kamil Lulko wrote:
> > > On Mon, Feb 6, 2017 at 12:16 AM, Tom Rini <trini@konsulko.com> wrote:
> > > > On Fri, Feb 03, 2017 at 02:48:40PM +0000, Phil Edworthy wrote:
> > > >
> > > > > The SysTick is a 24-bit down counter that is found on all ARM Cortex
> > > > > M3, M4, M7 devices and is always located at a fixed address.
> > > > >
> > > > > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> > > > > ---
> > > > >  arch/arm/cpu/armv7m/Makefile        |  2 +
> > > > >  arch/arm/cpu/armv7m/systick-timer.c | 91
> > > +++++++++++++++++++++++++++++++++++++
> > > > >  2 files changed, 93 insertions(+)
> > > > >  create mode 100644 arch/arm/cpu/armv7m/systick-timer.c
> > > > >
> > > > > diff --git a/arch/arm/cpu/armv7m/Makefile
> > > b/arch/arm/cpu/armv7m/Makefile
> > > > > index aff60e8..e1a6c40 100644
> > > > > --- a/arch/arm/cpu/armv7m/Makefile
> > > > > +++ b/arch/arm/cpu/armv7m/Makefile
> > > > > @@ -7,3 +7,5 @@
> > > > >
> > > > >  extra-y := start.o
> > > > >  obj-y += cpu.o
> > > > > +
> > > > > +obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o
> > > > > diff --git a/arch/arm/cpu/armv7m/systick-timer.c
> > > b/arch/arm/cpu/armv7m/systick-timer.c
> > > > > new file mode 100644
> > > > > index 0000000..6ccc2fb
> > > > > --- /dev/null
> > > > > +++ b/arch/arm/cpu/armv7m/systick-timer.c
> > > > > @@ -0,0 +1,91 @@
> > > > > +/*
> > > > > + * ARM Cortex M3/M4/M7 SysTick timer driver
> > > > > + * (C) Copyright 2017 Renesas Electronics Europe Ltd
> > > > > + *
> > > > > + * Based on arch/arm/mach-stm32/stm32f1/timer.c
> > > > > + * (C) Copyright 2015
> > > > > + * Kamil Lulko, <kamil.lulko@gmail.com>
> > > > > + *
> > > > > + * Copyright 2015 ATS Advanced Telematics Systems GmbH
> > > > > + * Copyright 2015 Konsulko Group, Matt Porter
> <mporter@konsulko.com>
> > > > > + *
> > > > > + * SPDX-License-Identifier:     GPL-2.0+
> > > > > + */
> > > > > +
> > > > > +#include <common.h>
> > > > > +#include <asm/io.h>
> > > > > +
> > > > > +DECLARE_GLOBAL_DATA_PTR;
> > > > > +
> > > > > +/* SysTick Base Address - fixed for all Cortex M3, M4 and M7 devices */
> > > > > +#define SYSTICK_BASE         0xE000E010
> > > > > +
> > > > > +struct cm3_systick {
> > > > > +     uint32_t ctrl;
> > > > > +     uint32_t reload;
> > > > > +     uint32_t val;
> > > > > +     uint32_t calibration;
> > > > > +};
> > > > > +
> > > > > +#define TIMER_LOAD_VAL               0x00FFFFFF
> > > > > +#define SYSTICK_CTRL_EN              BIT(0)
> > > > > +/* Clock source: 0 = Ref clock, 1 = CPU clock */
> > > > > +#define SYSTICK_CTRL_CPU_CLK BIT(2)
> > > > > +
> > > > > +/* read the 24-bit timer */
> > > > > +static ulong read_timer(void)
> > > > > +{
> > > > > +     struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> > > > > +
> > > > > +     /* The timer counts down, therefore convert to an incrementing timer
> */
> > > > > +     return TIMER_LOAD_VAL - readl(&systick->val);
> > > > > +}
> > > > > +
> > > > > +int timer_init(void)
> > > > > +{
> > > > > +     struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> > > > > +
> > > > > +     writel(TIMER_LOAD_VAL, &systick->reload);
> > > > > +     writel(TIMER_LOAD_VAL, &systick->val);
> > > > > +
> > > > > +#ifdef CONFIG_ARMCORTEXM3_SYSTICK_CPU
> > > > > +     /* Use CPU clock, no interrupts */
> > > > > +     writel(SYSTICK_CTRL_EN | SYSTICK_CTRL_CPU_CLK, &systick->ctrl);
> > > > > +#else
> > > > > +     /* Use external clock, no interrupts */
> > > > > +     writel(SYSTICK_CTRL_EN, &systick->ctrl);
> > > > > +#endif
> > > > > +
> > > > > +     gd->arch.tbl = 0;
> > > > > +     gd->arch.tbu = 0;
> > > > > +     gd->arch.lastinc = read_timer();
> > > > > +
> > > > > +     return 0;
> > > > > +}
> > > > > +
> > > > > +/* return milli-seconds timer value */
> > > > > +ulong get_timer(ulong base)
> > > > > +{
> > > > > +     unsigned long long t = get_ticks() * 1000;
> > > > > +
> > > > > +     return (ulong)((t / CONFIG_SYS_HZ_CLOCK)) - base;
> > > > > +}
> > > > > +
> > > > > +unsigned long long get_ticks(void)
> > > > > +{
> > > > > +     u32 now = read_timer();
> > > > > +
> > > > > +     if (now >= gd->arch.lastinc)
> > > > > +             gd->arch.tbl += (now - gd->arch.lastinc);
> > > > > +     else
> > > > > +             gd->arch.tbl += (TIMER_LOAD_VAL - gd->arch.lastinc) + now;
> > > > > +
> > > > > +     gd->arch.lastinc = now;
> > > > > +
> > > > > +     return gd->arch.tbl;
> > > > > +}
> > > > > +
> > > > > +ulong get_tbclk(void)
> > > > > +{
> > > > > +     return CONFIG_SYS_HZ_CLOCK;
> > > > > +}
> > > >
> > > > And (cc'ing maintainers) we could use this in place of
> > > > arch/arm/mach-stm32/*/timer.c I assume, yes?  Thanks!
> > > >
> > > > --
> > > > Tom
> > >
> > > Yes, however as far as I remember the systick is only 24-bit and
> > > usually runs on CPU clock so it will roll over too fast to be useful
> > > without using interrupts. Maybe I have missed something?
> >
> > Yes, it is only a 24-bit counter. On the device I am using, the clock
> > is not the cpu clock, but a low speed clock at 6.25MHz. Even at that
> > low clock it will still wrap every ~2.6 seconds.
> 
> So are you able to use the timer then, given the quick overflow?
Yes, I didn't see any problems. All of the udelay/mdelay calls should
work because they resolve to constantly calling get_ticks.

I guess it will not work if you attempt to time something that is
longer than 2.6 seconds though.

Thanks
Phil
Vikas MANOCHA Feb. 12, 2017, 8:52 p.m. UTC | #6
Hi Phil,

> -----Original Message-----
> From: Tom Rini [mailto:trini@konsulko.com]
> Sent: Sunday, February 05, 2017 3:17 PM
> To: Phil Edworthy <phil.edworthy@renesas.com>; Vikas MANOCHA <vikas.manocha@st.com>; Michael Kurz
> <michi.kurz@gmail.com>
> Cc: Albert Aribaud <albert.u.boot@aribaud.net>; u-boot@lists.denx.de; Kamil Lulko <kamil.lulko@gmail.com>
> Subject: Re: [U-Boot] [PATCH] armv7m: Add SysTick timer driver
> 
> On Fri, Feb 03, 2017 at 02:48:40PM +0000, Phil Edworthy wrote:
> 
> > The SysTick is a 24-bit down counter that is found on all ARM Cortex
> > M3, M4, M7 devices and is always located at a fixed address.
> >
> > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> > ---
> >  arch/arm/cpu/armv7m/Makefile        |  2 +
> >  arch/arm/cpu/armv7m/systick-timer.c | 91
> > +++++++++++++++++++++++++++++++++++++
> >  2 files changed, 93 insertions(+)
> >  create mode 100644 arch/arm/cpu/armv7m/systick-timer.c
> >
> > diff --git a/arch/arm/cpu/armv7m/Makefile
> > b/arch/arm/cpu/armv7m/Makefile index aff60e8..e1a6c40 100644
> > --- a/arch/arm/cpu/armv7m/Makefile
> > +++ b/arch/arm/cpu/armv7m/Makefile
> > @@ -7,3 +7,5 @@
> >
> >  extra-y := start.o
> >  obj-y += cpu.o
> > +
> > +obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o
> > diff --git a/arch/arm/cpu/armv7m/systick-timer.c
> > b/arch/arm/cpu/armv7m/systick-timer.c
> > new file mode 100644
> > index 0000000..6ccc2fb
> > --- /dev/null
> > +++ b/arch/arm/cpu/armv7m/systick-timer.c
> > @@ -0,0 +1,91 @@
> > +/*
> > + * ARM Cortex M3/M4/M7 SysTick timer driver
> > + * (C) Copyright 2017 Renesas Electronics Europe Ltd
> > + *
> > + * Based on arch/arm/mach-stm32/stm32f1/timer.c
> > + * (C) Copyright 2015
> > + * Kamil Lulko, <kamil.lulko@gmail.com>
> > + *
> > + * Copyright 2015 ATS Advanced Telematics Systems GmbH
> > + * Copyright 2015 Konsulko Group, Matt Porter <mporter@konsulko.com>
> > + *
> > + * SPDX-License-Identifier:     GPL-2.0+
> > + */
> > +
> > +#include <common.h>
> > +#include <asm/io.h>
> > +
> > +DECLARE_GLOBAL_DATA_PTR;
> > +
> > +/* SysTick Base Address - fixed for all Cortex M3, M4 and M7 devices */
> > +#define SYSTICK_BASE		0xE000E010
> > +
> > +struct cm3_systick {
> > +	uint32_t ctrl;
> > +	uint32_t reload;
> > +	uint32_t val;

This register is current timer value, write of any value clears it.
Rename to cur_val would avoid any confusion.

> > +	uint32_t calibration;
> > +};
> > +
> > +#define TIMER_LOAD_VAL		0x00FFFFFF
> > +#define SYSTICK_CTRL_EN		BIT(0)
> > +/* Clock source: 0 = Ref clock, 1 = CPU clock */
> > +#define SYSTICK_CTRL_CPU_CLK	BIT(2)
> > +
> > +/* read the 24-bit timer */
> > +static ulong read_timer(void)
> > +{
> > +	struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> > +
> > +	/* The timer counts down, therefore convert to an incrementing timer */
> > +	return TIMER_LOAD_VAL - readl(&systick->val); }

use mask to be sure of 24bit timer counter value.

> > +
> > +int timer_init(void)
> > +{
> > +	struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> > +
> > +	writel(TIMER_LOAD_VAL, &systick->reload);
> > +	writel(TIMER_LOAD_VAL, &systick->val);

Writing load value gives the impression that it is load register, in fact it is only clearing countflag.

> > +
> > +#ifdef CONFIG_ARMCORTEXM3_SYSTICK_CPU

Cortex M3 systick has only cpu clock source ?

Cheers,
Vikas

> > +	/* Use CPU clock, no interrupts */
> > +	writel(SYSTICK_CTRL_EN | SYSTICK_CTRL_CPU_CLK, &systick->ctrl);
> > +#else
> > +	/* Use external clock, no interrupts */
> > +	writel(SYSTICK_CTRL_EN, &systick->ctrl); #endif
> > +
> > +	gd->arch.tbl = 0;
> > +	gd->arch.tbu = 0;
> > +	gd->arch.lastinc = read_timer();
> > +
> > +	return 0;
> > +}
> > +
> > +/* return milli-seconds timer value */ ulong get_timer(ulong base) {
> > +	unsigned long long t = get_ticks() * 1000;
> > +
> > +	return (ulong)((t / CONFIG_SYS_HZ_CLOCK)) - base; }
> > +
> > +unsigned long long get_ticks(void)
> > +{
> > +	u32 now = read_timer();
> > +
> > +	if (now >= gd->arch.lastinc)
> > +		gd->arch.tbl += (now - gd->arch.lastinc);
> > +	else
> > +		gd->arch.tbl += (TIMER_LOAD_VAL - gd->arch.lastinc) + now;
> > +
> > +	gd->arch.lastinc = now;
> > +
> > +	return gd->arch.tbl;
> > +}
> > +
> > +ulong get_tbclk(void)
> > +{
> > +	return CONFIG_SYS_HZ_CLOCK;
> > +}
> 
> And (cc'ing maintainers) we could use this in place of arch/arm/mach-stm32/*/timer.c I assume, yes?  Thanks!
> 
> --
> Tom
Vikas MANOCHA Feb. 12, 2017, 9:09 p.m. UTC | #7
Hi Phil,

> -----Original Message-----
> From: Phil Edworthy [mailto:phil.edworthy@renesas.com]
> Sent: Tuesday, February 07, 2017 6:34 AM
> To: Tom Rini <trini@konsulko.com>
> Cc: Kamil Lulko <kamil.lulko@gmail.com>; Vikas MANOCHA <vikas.manocha@st.com>; Michael Kurz <michi.kurz@gmail.com>;
> Albert Aribaud <albert.u.boot@aribaud.net>; U-Boot Mailing List <u-boot@lists.denx.de>
> Subject: RE: [U-Boot] [PATCH] armv7m: Add SysTick timer driver
> 
> Hi Tom,
> 
> On 07 February 2017 14:23, Tom Rini wrote:
> > On Tue, Feb 07, 2017 at 02:19:39PM +0000, Phil Edworthy wrote:
> > > Hi Kamil,
> > >
> > > On 07 February 2017 14:12, Kamil Lulko wrote:
> > > > On Mon, Feb 6, 2017 at 12:16 AM, Tom Rini <trini@konsulko.com> wrote:
> > > > > On Fri, Feb 03, 2017 at 02:48:40PM +0000, Phil Edworthy wrote:
> > > > >
> > > > > > The SysTick is a 24-bit down counter that is found on all ARM
> > > > > > Cortex M3, M4, M7 devices and is always located at a fixed address.
> > > > > >
> > > > > > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> > > > > > ---
> > > > > >  arch/arm/cpu/armv7m/Makefile        |  2 +
> > > > > >  arch/arm/cpu/armv7m/systick-timer.c | 91
> > > > +++++++++++++++++++++++++++++++++++++
> > > > > >  2 files changed, 93 insertions(+)  create mode 100644
> > > > > > arch/arm/cpu/armv7m/systick-timer.c
> > > > > >
> > > > > > diff --git a/arch/arm/cpu/armv7m/Makefile
> > > > b/arch/arm/cpu/armv7m/Makefile
> > > > > > index aff60e8..e1a6c40 100644
> > > > > > --- a/arch/arm/cpu/armv7m/Makefile
> > > > > > +++ b/arch/arm/cpu/armv7m/Makefile
> > > > > > @@ -7,3 +7,5 @@
> > > > > >
> > > > > >  extra-y := start.o
> > > > > >  obj-y += cpu.o
> > > > > > +
> > > > > > +obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o
> > > > > > diff --git a/arch/arm/cpu/armv7m/systick-timer.c
> > > > b/arch/arm/cpu/armv7m/systick-timer.c
> > > > > > new file mode 100644
> > > > > > index 0000000..6ccc2fb
> > > > > > --- /dev/null
> > > > > > +++ b/arch/arm/cpu/armv7m/systick-timer.c
> > > > > > @@ -0,0 +1,91 @@
> > > > > > +/*
> > > > > > + * ARM Cortex M3/M4/M7 SysTick timer driver
> > > > > > + * (C) Copyright 2017 Renesas Electronics Europe Ltd
> > > > > > + *
> > > > > > + * Based on arch/arm/mach-stm32/stm32f1/timer.c
> > > > > > + * (C) Copyright 2015
> > > > > > + * Kamil Lulko, <kamil.lulko@gmail.com>
> > > > > > + *
> > > > > > + * Copyright 2015 ATS Advanced Telematics Systems GmbH
> > > > > > + * Copyright 2015 Konsulko Group, Matt Porter
> > <mporter@konsulko.com>
> > > > > > + *
> > > > > > + * SPDX-License-Identifier:     GPL-2.0+
> > > > > > + */
> > > > > > +
> > > > > > +#include <common.h>
> > > > > > +#include <asm/io.h>
> > > > > > +
> > > > > > +DECLARE_GLOBAL_DATA_PTR;
> > > > > > +
> > > > > > +/* SysTick Base Address - fixed for all Cortex M3, M4 and M7 devices */
> > > > > > +#define SYSTICK_BASE         0xE000E010
> > > > > > +
> > > > > > +struct cm3_systick {
> > > > > > +     uint32_t ctrl;
> > > > > > +     uint32_t reload;
> > > > > > +     uint32_t val;
> > > > > > +     uint32_t calibration;
> > > > > > +};
> > > > > > +
> > > > > > +#define TIMER_LOAD_VAL               0x00FFFFFF
> > > > > > +#define SYSTICK_CTRL_EN              BIT(0)
> > > > > > +/* Clock source: 0 = Ref clock, 1 = CPU clock */ #define
> > > > > > +SYSTICK_CTRL_CPU_CLK BIT(2)
> > > > > > +
> > > > > > +/* read the 24-bit timer */
> > > > > > +static ulong read_timer(void) {
> > > > > > +     struct cm3_systick *systick = (struct cm3_systick
> > > > > > +*)SYSTICK_BASE;
> > > > > > +
> > > > > > +     /* The timer counts down, therefore convert to an
> > > > > > + incrementing timer
> > */
> > > > > > +     return TIMER_LOAD_VAL - readl(&systick->val); }
> > > > > > +
> > > > > > +int timer_init(void)
> > > > > > +{
> > > > > > +     struct cm3_systick *systick = (struct cm3_systick
> > > > > > +*)SYSTICK_BASE;
> > > > > > +
> > > > > > +     writel(TIMER_LOAD_VAL, &systick->reload);
> > > > > > +     writel(TIMER_LOAD_VAL, &systick->val);
> > > > > > +
> > > > > > +#ifdef CONFIG_ARMCORTEXM3_SYSTICK_CPU
> > > > > > +     /* Use CPU clock, no interrupts */
> > > > > > +     writel(SYSTICK_CTRL_EN | SYSTICK_CTRL_CPU_CLK,
> > > > > > +&systick->ctrl); #else
> > > > > > +     /* Use external clock, no interrupts */
> > > > > > +     writel(SYSTICK_CTRL_EN, &systick->ctrl); #endif
> > > > > > +
> > > > > > +     gd->arch.tbl = 0;
> > > > > > +     gd->arch.tbu = 0;
> > > > > > +     gd->arch.lastinc = read_timer();
> > > > > > +
> > > > > > +     return 0;
> > > > > > +}
> > > > > > +
> > > > > > +/* return milli-seconds timer value */ ulong get_timer(ulong
> > > > > > +base) {
> > > > > > +     unsigned long long t = get_ticks() * 1000;
> > > > > > +
> > > > > > +     return (ulong)((t / CONFIG_SYS_HZ_CLOCK)) - base; }
> > > > > > +
> > > > > > +unsigned long long get_ticks(void) {
> > > > > > +     u32 now = read_timer();
> > > > > > +
> > > > > > +     if (now >= gd->arch.lastinc)
> > > > > > +             gd->arch.tbl += (now - gd->arch.lastinc);
> > > > > > +     else
> > > > > > +             gd->arch.tbl += (TIMER_LOAD_VAL -
> > > > > > + gd->arch.lastinc) + now;
> > > > > > +
> > > > > > +     gd->arch.lastinc = now;
> > > > > > +
> > > > > > +     return gd->arch.tbl;
> > > > > > +}
> > > > > > +
> > > > > > +ulong get_tbclk(void)
> > > > > > +{
> > > > > > +     return CONFIG_SYS_HZ_CLOCK; }
> > > > >
> > > > > And (cc'ing maintainers) we could use this in place of
> > > > > arch/arm/mach-stm32/*/timer.c I assume, yes?  Thanks!
> > > > >
> > > > > --
> > > > > Tom
> > > >
> > > > Yes, however as far as I remember the systick is only 24-bit and
> > > > usually runs on CPU clock so it will roll over too fast to be
> > > > useful without using interrupts. Maybe I have missed something?
> > >
> > > Yes, it is only a 24-bit counter. On the device I am using, the
> > > clock is not the cpu clock, but a low speed clock at 6.25MHz. Even
> > > at that low clock it will still wrap every ~2.6 seconds.
> >
> > So are you able to use the timer then, given the quick overflow?
> Yes, I didn't see any problems. All of the udelay/mdelay calls should work because they resolve to constantly calling get_ticks.
> 
> I guess it will not work if you attempt to time something that is longer than 2.6 seconds though.

Hmm, I wish it had some way to increase overflow time...it doesn't have the pre-scalar to divide the clock..

As this timer is same for all cortex-Mx, It makes sense to use this timer for stm32 and other cortexMx. 
I didn't check calibration register : could it be useful here ?

Cheers,
Vikas

> 
> Thanks
> Phil
Phil Edworthy Feb. 13, 2017, 9:39 a.m. UTC | #8
Hi Vikas,

On 12 February 2017 20:53, Vikas MANOCHA wrote:
> > On Fri, Feb 03, 2017 at 02:48:40PM +0000, Phil Edworthy wrote:
> >
> > > The SysTick is a 24-bit down counter that is found on all ARM Cortex
> > > M3, M4, M7 devices and is always located at a fixed address.
> > >
> > > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> > > ---
> > >  arch/arm/cpu/armv7m/Makefile        |  2 +
> > >  arch/arm/cpu/armv7m/systick-timer.c | 91
> > > +++++++++++++++++++++++++++++++++++++
> > >  2 files changed, 93 insertions(+)
> > >  create mode 100644 arch/arm/cpu/armv7m/systick-timer.c
> > >
> > > diff --git a/arch/arm/cpu/armv7m/Makefile
> > > b/arch/arm/cpu/armv7m/Makefile index aff60e8..e1a6c40 100644
> > > --- a/arch/arm/cpu/armv7m/Makefile
> > > +++ b/arch/arm/cpu/armv7m/Makefile
> > > @@ -7,3 +7,5 @@
> > >
> > >  extra-y := start.o
> > >  obj-y += cpu.o
> > > +
> > > +obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o
> > > diff --git a/arch/arm/cpu/armv7m/systick-timer.c
> > > b/arch/arm/cpu/armv7m/systick-timer.c
> > > new file mode 100644
> > > index 0000000..6ccc2fb
> > > --- /dev/null
> > > +++ b/arch/arm/cpu/armv7m/systick-timer.c
> > > @@ -0,0 +1,91 @@
> > > +/*
> > > + * ARM Cortex M3/M4/M7 SysTick timer driver
> > > + * (C) Copyright 2017 Renesas Electronics Europe Ltd
> > > + *
> > > + * Based on arch/arm/mach-stm32/stm32f1/timer.c
> > > + * (C) Copyright 2015
> > > + * Kamil Lulko, <kamil.lulko@gmail.com>
> > > + *
> > > + * Copyright 2015 ATS Advanced Telematics Systems GmbH
> > > + * Copyright 2015 Konsulko Group, Matt Porter <mporter@konsulko.com>
> > > + *
> > > + * SPDX-License-Identifier:     GPL-2.0+
> > > + */
> > > +
> > > +#include <common.h>
> > > +#include <asm/io.h>
> > > +
> > > +DECLARE_GLOBAL_DATA_PTR;
> > > +
> > > +/* SysTick Base Address - fixed for all Cortex M3, M4 and M7 devices */
> > > +#define SYSTICK_BASE		0xE000E010
> > > +
> > > +struct cm3_systick {
> > > +	uint32_t ctrl;
> > > +	uint32_t reload;
> > > +	uint32_t val;
> 
> This register is current timer value, write of any value clears it.
> Rename to cur_val would avoid any confusion.
Ok, though I'm not sure that cur_val is any clearer :)

> > > +	uint32_t calibration;
> > > +};
> > > +
> > > +#define TIMER_LOAD_VAL		0x00FFFFFF
> > > +#define SYSTICK_CTRL_EN		BIT(0)
> > > +/* Clock source: 0 = Ref clock, 1 = CPU clock */
> > > +#define SYSTICK_CTRL_CPU_CLK	BIT(2)
> > > +
> > > +/* read the 24-bit timer */
> > > +static ulong read_timer(void)
> > > +{
> > > +	struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> > > +
> > > +	/* The timer counts down, therefore convert to an incrementing timer */
> > > +	return TIMER_LOAD_VAL - readl(&systick->val); }
> 
> use mask to be sure of 24bit timer counter value.
Why? It's a 24-bit timer, the other bits are always zero.
 
> > > +
> > > +int timer_init(void)
> > > +{
> > > +	struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
> > > +
> > > +	writel(TIMER_LOAD_VAL, &systick->reload);
> > > +	writel(TIMER_LOAD_VAL, &systick->val);
> 
> Writing load value gives the impression that it is load register, in fact it is only
> clearing countflag.
Ok

> > > +
> > > +#ifdef CONFIG_ARMCORTEXM3_SYSTICK_CPU
> 
> Cortex M3 systick has only cpu clock source ?
No, it can have cpu clock or another clock external to the M3 core.
In our case we use the external clock because it is much slower than the
cpu clock, making the timer usable without interrupts. I can't imagine
anyone using the cpu clock unless they add code to handle the interrupt.
I'll add a comment to that effect.

Thanks
Phil

> Cheers,
> Vikas
> 
> > > +	/* Use CPU clock, no interrupts */
> > > +	writel(SYSTICK_CTRL_EN | SYSTICK_CTRL_CPU_CLK, &systick->ctrl);
> > > +#else
> > > +	/* Use external clock, no interrupts */
> > > +	writel(SYSTICK_CTRL_EN, &systick->ctrl); #endif
> > > +
> > > +	gd->arch.tbl = 0;
> > > +	gd->arch.tbu = 0;
> > > +	gd->arch.lastinc = read_timer();
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +/* return milli-seconds timer value */ ulong get_timer(ulong base) {
> > > +	unsigned long long t = get_ticks() * 1000;
> > > +
> > > +	return (ulong)((t / CONFIG_SYS_HZ_CLOCK)) - base; }
> > > +
> > > +unsigned long long get_ticks(void)
> > > +{
> > > +	u32 now = read_timer();
> > > +
> > > +	if (now >= gd->arch.lastinc)
> > > +		gd->arch.tbl += (now - gd->arch.lastinc);
> > > +	else
> > > +		gd->arch.tbl += (TIMER_LOAD_VAL - gd->arch.lastinc) + now;
> > > +
> > > +	gd->arch.lastinc = now;
> > > +
> > > +	return gd->arch.tbl;
> > > +}
> > > +
> > > +ulong get_tbclk(void)
> > > +{
> > > +	return CONFIG_SYS_HZ_CLOCK;
> > > +}
> >
> > And (cc'ing maintainers) we could use this in place of arch/arm/mach-
> stm32/*/timer.c I assume, yes?  Thanks!
> >
> > --
> > Tom
Phil Edworthy Feb. 13, 2017, 9:48 a.m. UTC | #9
Hi Vikas,

On 12 February 2017 21:10, Vikas MANOCHA wrote:
> Hi Phil,
> 
> > -----Original Message-----
> > From: Phil Edworthy [mailto:phil.edworthy@renesas.com]
> > Sent: Tuesday, February 07, 2017 6:34 AM
> > To: Tom Rini <trini@konsulko.com>
> > Cc: Kamil Lulko <kamil.lulko@gmail.com>; Vikas MANOCHA
> <vikas.manocha@st.com>; Michael Kurz <michi.kurz@gmail.com>;
> > Albert Aribaud <albert.u.boot@aribaud.net>; U-Boot Mailing List <u-
> boot@lists.denx.de>
> > Subject: RE: [U-Boot] [PATCH] armv7m: Add SysTick timer driver
> >
> > Hi Tom,
> >
> > On 07 February 2017 14:23, Tom Rini wrote:
> > > On Tue, Feb 07, 2017 at 02:19:39PM +0000, Phil Edworthy wrote:
> > > > Hi Kamil,
> > > >
> > > > On 07 February 2017 14:12, Kamil Lulko wrote:
> > > > > On Mon, Feb 6, 2017 at 12:16 AM, Tom Rini <trini@konsulko.com> wrote:
> > > > > > On Fri, Feb 03, 2017 at 02:48:40PM +0000, Phil Edworthy wrote:
> > > > > >
> > > > > > > The SysTick is a 24-bit down counter that is found on all ARM
> > > > > > > Cortex M3, M4, M7 devices and is always located at a fixed address.
> > > > > > >
> > > > > > > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> > > > > > > ---
> > > > > > >  arch/arm/cpu/armv7m/Makefile        |  2 +
> > > > > > >  arch/arm/cpu/armv7m/systick-timer.c | 91
> > > > > +++++++++++++++++++++++++++++++++++++
> > > > > > >  2 files changed, 93 insertions(+)  create mode 100644
> > > > > > > arch/arm/cpu/armv7m/systick-timer.c
> > > > > > >
> > > > > > > diff --git a/arch/arm/cpu/armv7m/Makefile
> > > > > b/arch/arm/cpu/armv7m/Makefile
> > > > > > > index aff60e8..e1a6c40 100644
> > > > > > > --- a/arch/arm/cpu/armv7m/Makefile
> > > > > > > +++ b/arch/arm/cpu/armv7m/Makefile
> > > > > > > @@ -7,3 +7,5 @@
> > > > > > >
> > > > > > >  extra-y := start.o
> > > > > > >  obj-y += cpu.o
> > > > > > > +
> > > > > > > +obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o
> > > > > > > diff --git a/arch/arm/cpu/armv7m/systick-timer.c
> > > > > b/arch/arm/cpu/armv7m/systick-timer.c
> > > > > > > new file mode 100644
> > > > > > > index 0000000..6ccc2fb
> > > > > > > --- /dev/null
> > > > > > > +++ b/arch/arm/cpu/armv7m/systick-timer.c
> > > > > > > @@ -0,0 +1,91 @@
> > > > > > > +/*
> > > > > > > + * ARM Cortex M3/M4/M7 SysTick timer driver
> > > > > > > + * (C) Copyright 2017 Renesas Electronics Europe Ltd
> > > > > > > + *
> > > > > > > + * Based on arch/arm/mach-stm32/stm32f1/timer.c
> > > > > > > + * (C) Copyright 2015
> > > > > > > + * Kamil Lulko, <kamil.lulko@gmail.com>
> > > > > > > + *
> > > > > > > + * Copyright 2015 ATS Advanced Telematics Systems GmbH
> > > > > > > + * Copyright 2015 Konsulko Group, Matt Porter
> > > <mporter@konsulko.com>
> > > > > > > + *
> > > > > > > + * SPDX-License-Identifier:     GPL-2.0+
> > > > > > > + */
> > > > > > > +
> > > > > > > +#include <common.h>
> > > > > > > +#include <asm/io.h>
> > > > > > > +
> > > > > > > +DECLARE_GLOBAL_DATA_PTR;
> > > > > > > +
> > > > > > > +/* SysTick Base Address - fixed for all Cortex M3, M4 and M7 devices
> */
> > > > > > > +#define SYSTICK_BASE         0xE000E010
> > > > > > > +
> > > > > > > +struct cm3_systick {
> > > > > > > +     uint32_t ctrl;
> > > > > > > +     uint32_t reload;
> > > > > > > +     uint32_t val;
> > > > > > > +     uint32_t calibration;
> > > > > > > +};
> > > > > > > +
> > > > > > > +#define TIMER_LOAD_VAL               0x00FFFFFF
> > > > > > > +#define SYSTICK_CTRL_EN              BIT(0)
> > > > > > > +/* Clock source: 0 = Ref clock, 1 = CPU clock */ #define
> > > > > > > +SYSTICK_CTRL_CPU_CLK BIT(2)
> > > > > > > +
> > > > > > > +/* read the 24-bit timer */
> > > > > > > +static ulong read_timer(void) {
> > > > > > > +     struct cm3_systick *systick = (struct cm3_systick
> > > > > > > +*)SYSTICK_BASE;
> > > > > > > +
> > > > > > > +     /* The timer counts down, therefore convert to an
> > > > > > > + incrementing timer
> > > */
> > > > > > > +     return TIMER_LOAD_VAL - readl(&systick->val); }
> > > > > > > +
> > > > > > > +int timer_init(void)
> > > > > > > +{
> > > > > > > +     struct cm3_systick *systick = (struct cm3_systick
> > > > > > > +*)SYSTICK_BASE;
> > > > > > > +
> > > > > > > +     writel(TIMER_LOAD_VAL, &systick->reload);
> > > > > > > +     writel(TIMER_LOAD_VAL, &systick->val);
> > > > > > > +
> > > > > > > +#ifdef CONFIG_ARMCORTEXM3_SYSTICK_CPU
> > > > > > > +     /* Use CPU clock, no interrupts */
> > > > > > > +     writel(SYSTICK_CTRL_EN | SYSTICK_CTRL_CPU_CLK,
> > > > > > > +&systick->ctrl); #else
> > > > > > > +     /* Use external clock, no interrupts */
> > > > > > > +     writel(SYSTICK_CTRL_EN, &systick->ctrl); #endif
> > > > > > > +
> > > > > > > +     gd->arch.tbl = 0;
> > > > > > > +     gd->arch.tbu = 0;
> > > > > > > +     gd->arch.lastinc = read_timer();
> > > > > > > +
> > > > > > > +     return 0;
> > > > > > > +}
> > > > > > > +
> > > > > > > +/* return milli-seconds timer value */ ulong get_timer(ulong
> > > > > > > +base) {
> > > > > > > +     unsigned long long t = get_ticks() * 1000;
> > > > > > > +
> > > > > > > +     return (ulong)((t / CONFIG_SYS_HZ_CLOCK)) - base; }
> > > > > > > +
> > > > > > > +unsigned long long get_ticks(void) {
> > > > > > > +     u32 now = read_timer();
> > > > > > > +
> > > > > > > +     if (now >= gd->arch.lastinc)
> > > > > > > +             gd->arch.tbl += (now - gd->arch.lastinc);
> > > > > > > +     else
> > > > > > > +             gd->arch.tbl += (TIMER_LOAD_VAL -
> > > > > > > + gd->arch.lastinc) + now;
> > > > > > > +
> > > > > > > +     gd->arch.lastinc = now;
> > > > > > > +
> > > > > > > +     return gd->arch.tbl;
> > > > > > > +}
> > > > > > > +
> > > > > > > +ulong get_tbclk(void)
> > > > > > > +{
> > > > > > > +     return CONFIG_SYS_HZ_CLOCK; }
> > > > > >
> > > > > > And (cc'ing maintainers) we could use this in place of
> > > > > > arch/arm/mach-stm32/*/timer.c I assume, yes?  Thanks!
> > > > > >
> > > > > > --
> > > > > > Tom
> > > > >
> > > > > Yes, however as far as I remember the systick is only 24-bit and
> > > > > usually runs on CPU clock so it will roll over too fast to be
> > > > > useful without using interrupts. Maybe I have missed something?
> > > >
> > > > Yes, it is only a 24-bit counter. On the device I am using, the
> > > > clock is not the cpu clock, but a low speed clock at 6.25MHz. Even
> > > > at that low clock it will still wrap every ~2.6 seconds.
> > >
> > > So are you able to use the timer then, given the quick overflow?
> > Yes, I didn't see any problems. All of the udelay/mdelay calls should work
> because they resolve to constantly calling get_ticks.
> >
> > I guess it will not work if you attempt to time something that is longer than 2.6
> seconds though.
> 
> Hmm, I wish it had some way to increase overflow time...it doesn't have the pre-
> scalar to divide the clock..
None that I could find.

> As this timer is same for all cortex-Mx, It makes sense to use this timer for stm32
> and other cortexMx.
> I didn't check calibration register : could it be useful here ?
It could be used to get the clock rate, though you would need a fall back in
case the calibration reg is wrong or indicates an inexact 10ms value.

Thanks
Phil

> Cheers,
> Vikas
> 
> >
> > Thanks
> > Phil
diff mbox

Patch

diff --git a/arch/arm/cpu/armv7m/Makefile b/arch/arm/cpu/armv7m/Makefile
index aff60e8..e1a6c40 100644
--- a/arch/arm/cpu/armv7m/Makefile
+++ b/arch/arm/cpu/armv7m/Makefile
@@ -7,3 +7,5 @@ 
 
 extra-y := start.o
 obj-y += cpu.o
+
+obj-$(CONFIG_SYS_ARCH_TIMER) += systick-timer.o
diff --git a/arch/arm/cpu/armv7m/systick-timer.c b/arch/arm/cpu/armv7m/systick-timer.c
new file mode 100644
index 0000000..6ccc2fb
--- /dev/null
+++ b/arch/arm/cpu/armv7m/systick-timer.c
@@ -0,0 +1,91 @@ 
+/*
+ * ARM Cortex M3/M4/M7 SysTick timer driver
+ * (C) Copyright 2017 Renesas Electronics Europe Ltd
+ *
+ * Based on arch/arm/mach-stm32/stm32f1/timer.c
+ * (C) Copyright 2015
+ * Kamil Lulko, <kamil.lulko@gmail.com>
+ *
+ * Copyright 2015 ATS Advanced Telematics Systems GmbH
+ * Copyright 2015 Konsulko Group, Matt Porter <mporter@konsulko.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* SysTick Base Address - fixed for all Cortex M3, M4 and M7 devices */
+#define SYSTICK_BASE		0xE000E010
+
+struct cm3_systick {
+	uint32_t ctrl;
+	uint32_t reload;
+	uint32_t val;
+	uint32_t calibration;
+};
+
+#define TIMER_LOAD_VAL		0x00FFFFFF
+#define SYSTICK_CTRL_EN		BIT(0)
+/* Clock source: 0 = Ref clock, 1 = CPU clock */
+#define SYSTICK_CTRL_CPU_CLK	BIT(2)
+
+/* read the 24-bit timer */
+static ulong read_timer(void)
+{
+	struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
+
+	/* The timer counts down, therefore convert to an incrementing timer */
+	return TIMER_LOAD_VAL - readl(&systick->val);
+}
+
+int timer_init(void)
+{
+	struct cm3_systick *systick = (struct cm3_systick *)SYSTICK_BASE;
+
+	writel(TIMER_LOAD_VAL, &systick->reload);
+	writel(TIMER_LOAD_VAL, &systick->val);
+
+#ifdef CONFIG_ARMCORTEXM3_SYSTICK_CPU
+	/* Use CPU clock, no interrupts */
+	writel(SYSTICK_CTRL_EN | SYSTICK_CTRL_CPU_CLK, &systick->ctrl);
+#else
+	/* Use external clock, no interrupts */
+	writel(SYSTICK_CTRL_EN, &systick->ctrl);
+#endif
+
+	gd->arch.tbl = 0;
+	gd->arch.tbu = 0;
+	gd->arch.lastinc = read_timer();
+
+	return 0;
+}
+
+/* return milli-seconds timer value */
+ulong get_timer(ulong base)
+{
+	unsigned long long t = get_ticks() * 1000;
+
+	return (ulong)((t / CONFIG_SYS_HZ_CLOCK)) - base;
+}
+
+unsigned long long get_ticks(void)
+{
+	u32 now = read_timer();
+
+	if (now >= gd->arch.lastinc)
+		gd->arch.tbl += (now - gd->arch.lastinc);
+	else
+		gd->arch.tbl += (TIMER_LOAD_VAL - gd->arch.lastinc) + now;
+
+	gd->arch.lastinc = now;
+
+	return gd->arch.tbl;
+}
+
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ_CLOCK;
+}