2015-08-07 13:56:52

by Hans Ulli Kroll

[permalink] [raw]
Subject: ARM:Gemini:clocksource update for 4.3

Hi all,

sorry for being late in this cycle ...
I asked Roman to send me his patchset with 2 patched, but he don't respond.

So here is my patchset.
But I used one more patch to cleanup the register definitions in the driver.
These where somewhat annoying, if a "autocomplete" editor is used.

The other patches changes to the timer1 and add timer3 as free running.
The initial driver missed also to enable the interrupt in the device, which
is also added.

Greeting froms Cologne
Hans Ulli Kroll


arch/arm/mach-gemini/include/mach/hardware.h | 3 -
arch/arm/mach-gemini/time.c | 176 +++++++++++++++++++++++++++++-------------
2 files changed, 123 insertions(+), 56 deletions(-)



2015-08-07 13:57:00

by Hans Ulli Kroll

[permalink] [raw]
Subject: [PATCH 1/3] ARM:Gemini:Add missing register definitions for gemini timer

Add missing register defintions for the gemini clocksource
Also do some #define' cleanup to make the code more readable.

Signed-off-by: Hans Ulli Kroll <[email protected]>
---
arch/arm/mach-gemini/include/mach/hardware.h | 3 -
arch/arm/mach-gemini/time.c | 85 ++++++++++++++++++----------
2 files changed, 55 insertions(+), 33 deletions(-)

diff --git a/arch/arm/mach-gemini/include/mach/hardware.h b/arch/arm/mach-gemini/include/mach/hardware.h
index 98e7b0f..f0390f1 100644
--- a/arch/arm/mach-gemini/include/mach/hardware.h
+++ b/arch/arm/mach-gemini/include/mach/hardware.h
@@ -57,9 +57,6 @@
#define GEMINI_USB1_BASE 0x69000000
#define GEMINI_BIG_ENDIAN_BASE 0x80000000

-#define GEMINI_TIMER1_BASE GEMINI_TIMER_BASE
-#define GEMINI_TIMER2_BASE (GEMINI_TIMER_BASE + 0x10)
-#define GEMINI_TIMER3_BASE (GEMINI_TIMER_BASE + 0x20)

/*
* UART Clock when System clk is 150MHz
diff --git a/arch/arm/mach-gemini/time.c b/arch/arm/mach-gemini/time.c
index b57d367..fd751b1 100644
--- a/arch/arm/mach-gemini/time.c
+++ b/arch/arm/mach-gemini/time.c
@@ -19,21 +19,46 @@
/*
* Register definitions for the timers
*/
-#define TIMER_COUNT(BASE_ADDR) (BASE_ADDR + 0x00)
-#define TIMER_LOAD(BASE_ADDR) (BASE_ADDR + 0x04)
-#define TIMER_MATCH1(BASE_ADDR) (BASE_ADDR + 0x08)
-#define TIMER_MATCH2(BASE_ADDR) (BASE_ADDR + 0x0C)
-#define TIMER_CR(BASE_ADDR) (BASE_ADDR + 0x30)
-
-#define TIMER_1_CR_ENABLE (1 << 0)
-#define TIMER_1_CR_CLOCK (1 << 1)
-#define TIMER_1_CR_INT (1 << 2)
-#define TIMER_2_CR_ENABLE (1 << 3)
-#define TIMER_2_CR_CLOCK (1 << 4)
-#define TIMER_2_CR_INT (1 << 5)
-#define TIMER_3_CR_ENABLE (1 << 6)
-#define TIMER_3_CR_CLOCK (1 << 7)
-#define TIMER_3_CR_INT (1 << 8)
+
+#define TIMER1_BASE GEMINI_TIMER_BASE
+#define TIMER2_BASE (GEMINI_TIMER_BASE + 0x10)
+#define TIMER3_BASE (GEMINI_TIMER_BASE + 0x20)
+
+#define TIMER_COUNT(BASE) (IO_ADDRESS(BASE) + 0x00)
+#define TIMER_LOAD(BASE) (IO_ADDRESS(BASE) + 0x04)
+#define TIMER_MATCH1(BASE) (IO_ADDRESS(BASE) + 0x08)
+#define TIMER_MATCH2(BASE) (IO_ADDRESS(BASE) + 0x0C)
+#define TIMER_CR (IO_ADDRESS(GEMINI_TIMER_BASE) + 0x30)
+#define TIMER_INTR_STATE (IO_ADDRESS(GEMINI_TIMER_BASE) + 0x34)
+#define TIMER_INTR_MASK (IO_ADDRESS(GEMINI_TIMER_BASE) + 0x38)
+
+#define TIMER_1_CR_ENABLE (1 << 0)
+#define TIMER_1_CR_CLOCK (1 << 1)
+#define TIMER_1_CR_INT (1 << 2)
+#define TIMER_2_CR_ENABLE (1 << 3)
+#define TIMER_2_CR_CLOCK (1 << 4)
+#define TIMER_2_CR_INT (1 << 5)
+#define TIMER_3_CR_ENABLE (1 << 6)
+#define TIMER_3_CR_CLOCK (1 << 7)
+#define TIMER_3_CR_INT (1 << 8)
+#define TIMER_1_CR_UPDOWN (1 << 9)
+#define TIMER_2_CR_UPDOWN (1 << 10)
+#define TIMER_3_CR_UPDOWN (1 << 11)
+#define TIMER_DEFAULT_FLAGS (TIMER_1_CR_UPDOWN | \
+ TIMER_3_CR_ENABLE | \
+ TIMER_3_CR_UPDOWN)
+
+#define TIMER_1_INT_MATCH1 (1 << 0)
+#define TIMER_1_INT_MATCH2 (1 << 1)
+#define TIMER_1_INT_OVERFLOW (1 << 2)
+#define TIMER_2_INT_MATCH1 (1 << 3)
+#define TIMER_2_INT_MATCH2 (1 << 4)
+#define TIMER_2_INT_OVERFLOW (1 << 5)
+#define TIMER_3_INT_MATCH1 (1 << 6)
+#define TIMER_3_INT_MATCH2 (1 << 7)
+#define TIMER_3_INT_OVERFLOW (1 << 8)
+#define TIMER_INT_ALL_MASK 0x1ff
+

static unsigned int tick_rate;

@@ -42,19 +67,19 @@ static int gemini_timer_set_next_event(unsigned long cycles,
{
u32 cr;

- cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ cr = readl(TIMER_CR);

/* This may be overdoing it, feel free to test without this */
cr &= ~TIMER_2_CR_ENABLE;
cr &= ~TIMER_2_CR_INT;
- writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ writel(cr, TIMER_CR);

/* Set next event */
- writel(cycles, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE)));
- writel(cycles, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE)));
+ writel(cycles, TIMER_COUNT(TIMER2_BASE));
+ writel(cycles, TIMER_LOAD(TIMER2_BASE));
cr |= TIMER_2_CR_ENABLE;
cr |= TIMER_2_CR_INT;
- writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ writel(cr, TIMER_CR);

return 0;
}
@@ -67,10 +92,10 @@ static int gemini_timer_shutdown(struct clock_event_device *evt)
* Disable also for oneshot: the set_next() call will arm the timer
* instead.
*/
- cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ cr = readl(TIMER_CR);
cr &= ~TIMER_2_CR_ENABLE;
cr &= ~TIMER_2_CR_INT;
- writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ writel(cr, TIMER_CR);
return 0;
}

@@ -80,12 +105,12 @@ static int gemini_timer_set_periodic(struct clock_event_device *evt)
u32 cr;

/* Start the timer */
- writel(period, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE)));
- writel(period, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE)));
- cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ writel(period, TIMER_COUNT(TIMER2_BASE));
+ writel(period, TIMER_LOAD(TIMER2_BASE));
+ cr = readl(TIMER_CR);
cr |= TIMER_2_CR_ENABLE;
cr |= TIMER_2_CR_INT;
- writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ writel(cr, TIMER_CR);
return 0;
}

@@ -155,10 +180,10 @@ void __init gemini_timer_init(void)
setup_irq(IRQ_TIMER2, &gemini_timer_irq);

/* Enable and use TIMER1 as clock source */
- writel(0xffffffff, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER1_BASE)));
- writel(0xffffffff, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER1_BASE)));
- writel(TIMER_1_CR_ENABLE, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
- if (clocksource_mmio_init(TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER1_BASE)),
+ writel(0xffffffff, TIMER_COUNT(TIMER1_BASE));
+ writel(0xffffffff, TIMER_LOAD(TIMER1_BASE));
+ writel(TIMER_1_CR_ENABLE, TIMER_CR);
+ if (clocksource_mmio_init(TIMER_COUNT(TIMER1_BASE),
"TIMER1", tick_rate, 300, 32,
clocksource_mmio_readl_up))
pr_err("timer: failed to initialize gemini clock source\n");
--
2.4.6

2015-08-07 13:56:54

by Hans Ulli Kroll

[permalink] [raw]
Subject: [PATCH 2/3] ARM:Gemini:use timer1 for clockevent

Use timer1 as clockevent timer.
The old driver uses timer2, which has some issues to setup
Also in the old driver it is forgotten to enable to interrupts.

Signed-off-by: Hans Ulli Kroll <[email protected]>
---
arch/arm/mach-gemini/time.c | 94 +++++++++++++++++++++++++++++----------------
1 file changed, 60 insertions(+), 34 deletions(-)

diff --git a/arch/arm/mach-gemini/time.c b/arch/arm/mach-gemini/time.c
index fd751b1..5e2b1ba 100644
--- a/arch/arm/mach-gemini/time.c
+++ b/arch/arm/mach-gemini/time.c
@@ -67,19 +67,11 @@ static int gemini_timer_set_next_event(unsigned long cycles,
{
u32 cr;

- cr = readl(TIMER_CR);
-
- /* This may be overdoing it, feel free to test without this */
- cr &= ~TIMER_2_CR_ENABLE;
- cr &= ~TIMER_2_CR_INT;
- writel(cr, TIMER_CR);
-
- /* Set next event */
- writel(cycles, TIMER_COUNT(TIMER2_BASE));
- writel(cycles, TIMER_LOAD(TIMER2_BASE));
- cr |= TIMER_2_CR_ENABLE;
- cr |= TIMER_2_CR_INT;
- writel(cr, TIMER_CR);
+ /* Setup the match register */
+ cr = readl(TIMER_COUNT(TIMER1_BASE));
+ writel(cr + cycles, TIMER_MATCH1(TIMER1_BASE));
+ if (readl(TIMER_COUNT(TIMER1_BASE)) - cr > cycles)
+ return -ETIME;

return 0;
}
@@ -92,10 +84,26 @@ static int gemini_timer_shutdown(struct clock_event_device *evt)
* Disable also for oneshot: the set_next() call will arm the timer
* instead.
*/
+ /* Stop timer and interrupt. */
cr = readl(TIMER_CR);
- cr &= ~TIMER_2_CR_ENABLE;
- cr &= ~TIMER_2_CR_INT;
+ cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
writel(cr, TIMER_CR);
+
+ /* Setup counter start from 0 */
+ writel(0, TIMER_COUNT(TIMER1_BASE));
+ writel(0, TIMER_LOAD(TIMER1_BASE));
+
+ /* enable interrupt */
+ cr = readl(TIMER_INTR_MASK);
+ cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2);
+ cr |= TIMER_1_INT_MATCH1;
+ writel(cr, TIMER_INTR_MASK);
+
+ /* start the timer */
+ cr = readl(TIMER_CR);
+ cr |= TIMER_1_CR_ENABLE;
+ writel(cr, TIMER_CR);
+
return 0;
}

@@ -104,21 +112,37 @@ static int gemini_timer_set_periodic(struct clock_event_device *evt)
u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ);
u32 cr;

+ /* Stop timer and interrupt */
+ cr = readl(TIMER_CR);
+ cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
+ writel(cr, TIMER_CR);
+
+ /* Setup timer to fire at 1/HT intervals. */
+ cr = 0xffffffff - (period - 1);
+ writel(cr, TIMER_COUNT(TIMER1_BASE));
+ writel(cr, TIMER_LOAD(TIMER1_BASE));
+
+ /* enable interrupt on overflow */
+ cr = readl(TIMER_INTR_MASK);
+ cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2);
+ cr |= TIMER_1_INT_OVERFLOW;
+ writel(cr, TIMER_INTR_MASK);
+
/* Start the timer */
- writel(period, TIMER_COUNT(TIMER2_BASE));
- writel(period, TIMER_LOAD(TIMER2_BASE));
cr = readl(TIMER_CR);
- cr |= TIMER_2_CR_ENABLE;
- cr |= TIMER_2_CR_INT;
+ cr |= TIMER_1_CR_ENABLE;
+ cr |= TIMER_1_CR_INT;
writel(cr, TIMER_CR);
+
return 0;
}

-/* Use TIMER2 as clock event */
+/* Use TIMER1 as clock event */
static struct clock_event_device gemini_clockevent = {
- .name = "TIMER2",
+ .name = "TIMER1",
/* Reasonably fast and accurate clock event */
.rating = 300,
+ .shift = 32,
.features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = gemini_timer_set_next_event,
@@ -175,20 +199,22 @@ void __init gemini_timer_init(void)
}

/*
- * Make irqs happen for the system timer
+ * Reset the interrupt mask and status
*/
- setup_irq(IRQ_TIMER2, &gemini_timer_irq);
-
- /* Enable and use TIMER1 as clock source */
- writel(0xffffffff, TIMER_COUNT(TIMER1_BASE));
- writel(0xffffffff, TIMER_LOAD(TIMER1_BASE));
- writel(TIMER_1_CR_ENABLE, TIMER_CR);
- if (clocksource_mmio_init(TIMER_COUNT(TIMER1_BASE),
- "TIMER1", tick_rate, 300, 32,
- clocksource_mmio_readl_up))
- pr_err("timer: failed to initialize gemini clock source\n");
-
- /* Configure and register the clockevent */
+ writel(TIMER_INT_ALL_MASK, TIMER_INTR_MASK);
+ writel(0, TIMER_INTR_STATE);
+ writel(TIMER_DEFAULT_FLAGS, TIMER_CR);
+
+ /*
+ * Setup clockevent timer (interrupt-driven.)
+ */
+ writel(0, TIMER_COUNT(TIMER1_BASE));
+ writel(0, TIMER_LOAD(TIMER1_BASE));
+ writel(0, TIMER_MATCH1(TIMER1_BASE));
+ writel(0, TIMER_MATCH2(TIMER1_BASE));
+ setup_irq(IRQ_TIMER1, &gemini_timer_irq);
+ gemini_clockevent.cpumask = cpumask_of(0);
clockevents_config_and_register(&gemini_clockevent, tick_rate,
1, 0xffffffff);
+
}
--
2.4.6

2015-08-07 13:56:59

by Hans Ulli Kroll

[permalink] [raw]
Subject: [PATCH 3/3] ARM:Gemini:setup timer3 as free running timer

In the original driver it is missed to setup a free running driver.
This timer is needed for the scheduler.
So setup it.

Signed-off-by: Hans Ulli Kroll <[email protected]>
---
arch/arm/mach-gemini/time.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-gemini/time.c b/arch/arm/mach-gemini/time.c
index 5e2b1ba..f5f18df 100644
--- a/arch/arm/mach-gemini/time.c
+++ b/arch/arm/mach-gemini/time.c
@@ -15,6 +15,7 @@
#include <asm/mach/time.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
+#include <linux/sched_clock.h>

/*
* Register definitions for the timers
@@ -62,6 +63,11 @@

static unsigned int tick_rate;

+static u64 notrace gemini_read_sched_clock(void)
+{
+ return readl(TIMER_COUNT(TIMER3_BASE));
+}
+
static int gemini_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
@@ -206,8 +212,21 @@ void __init gemini_timer_init(void)
writel(TIMER_DEFAULT_FLAGS, TIMER_CR);

/*
- * Setup clockevent timer (interrupt-driven.)
+ * Setup free-running clocksource timer (interrupts
+ * disabled.)
*/
+ writel(0, TIMER_COUNT(TIMER3_BASE));
+ writel(0, TIMER_LOAD(TIMER3_BASE));
+ writel(0, TIMER_MATCH1(TIMER3_BASE));
+ writel(0, TIMER_MATCH2(TIMER3_BASE));
+ clocksource_mmio_init(TIMER_COUNT(TIMER3_BASE),
+ "gemini_clocksource", tick_rate,
+ 300, 32, clocksource_mmio_readl_up);
+ sched_clock_register(gemini_read_sched_clock, 32, tick_rate);
+
+ /*
+ * Setup clockevent timer (interrupt-driven.)
+ */
writel(0, TIMER_COUNT(TIMER1_BASE));
writel(0, TIMER_LOAD(TIMER1_BASE));
writel(0, TIMER_MATCH1(TIMER1_BASE));
--
2.4.6

2015-08-11 14:01:40

by Olof Johansson

[permalink] [raw]
Subject: Re: ARM:Gemini:clocksource update for 4.3

Hi,

On Fri, Aug 07, 2015 at 03:56:00PM +0200, Hans Ulli Kroll wrote:
> Hi all,
>
> sorry for being late in this cycle ...
> I asked Roman to send me his patchset with 2 patched, but he don't respond.
>
> So here is my patchset.
> But I used one more patch to cleanup the register definitions in the driver.
> These where somewhat annoying, if a "autocomplete" editor is used.
>
> The other patches changes to the timer1 and add timer3 as free running.
> The initial driver missed also to enable the interrupt in the device, which
> is also added.

First of all, what are these patches based against? At least the first
one doesn't apply to our tree, possibly due to conflicts with Linus
Walleij's patch "ARM: gemini: convert to GENERIC_CLOCKEVENTS" from 2013.

A couple of general comments about the patch series:

1) Please feel free to include a git shortlog with the cover letter

2) We try to standardize on "ARM: <platform>: <patch description"
as subject, i.e. here it would be "ARM: gemini: ...". (Space and
capitalization is the difference). I'll fix this up when applying, just
mentioning it for future patches.

3) While it's nice to see some updates and cleanups to the clock driver in the
mach directory, what would be even more awesome would be an effort to move
it into the drivers/clocksource directory where other platforms now have
their drivers. If you want to continue working on these, please consider
doing that work!


-Olof

2015-08-11 20:10:57

by Hans Ulli Kroll

[permalink] [raw]
Subject: ARM: gemini: clocksource update for 4.3 v2

Hi,

these is version 2 of the clocksource updates for 4.3

These patches are rebased on your arm-soc/for-next tree.
latest commit e4c4ce53a925146167a58cfd2e862952cdc316e1

arm-soc: document merges

They is also a patch from Viresh Kumar in mach-gemini
ARM/gemini/time: Migrate to new 'set-state' interface

The other patches affecting clocksource are going through the
clocksource tree.

For the clocksource in general :
I'm planning to move to DT. mach-moxart locks promising.
Same CPU FA526 as mach-gemini.
But they are two devices they can't moved easily to DT.
- MISC global reg for differnt device settings
- ethernet, up to 2 irq's, shared address space (bitfield)

Don't ask me why the engineers have done this ...

So I need DT in conjunction with (one) board file(s).
Is this possible ??

Greeting from Cologne
Ulli

-v2
added shortlog and changed subject in patches.

Hans Ulli Kroll (3):
ARM: gemini: Add missing register definitions for gemini timer
ARM: gemini: use timer1 for clockevent
ARM: gemini: setup timer3 as free running timer

arch/arm/mach-gemini/include/mach/hardware.h | 3 -
arch/arm/mach-gemini/time.c | 176 +++++++++++++++++++--------
2 files changed, 123 insertions(+), 56 deletions(-)

2015-08-11 20:10:42

by Hans Ulli Kroll

[permalink] [raw]
Subject: [PATCH 1/3] ARM:Gemini:Add missing register definitions for gemini timer

Add missing register defintions for the gemini clocksource
Also do some #define' cleanup to make the code more readable.

Signed-off-by: Hans Ulli Kroll <[email protected]>
---
arch/arm/mach-gemini/include/mach/hardware.h | 3 -
arch/arm/mach-gemini/time.c | 85 ++++++++++++++++++----------
2 files changed, 55 insertions(+), 33 deletions(-)

diff --git a/arch/arm/mach-gemini/include/mach/hardware.h b/arch/arm/mach-gemini/include/mach/hardware.h
index 98e7b0f..f0390f1 100644
--- a/arch/arm/mach-gemini/include/mach/hardware.h
+++ b/arch/arm/mach-gemini/include/mach/hardware.h
@@ -57,9 +57,6 @@
#define GEMINI_USB1_BASE 0x69000000
#define GEMINI_BIG_ENDIAN_BASE 0x80000000

-#define GEMINI_TIMER1_BASE GEMINI_TIMER_BASE
-#define GEMINI_TIMER2_BASE (GEMINI_TIMER_BASE + 0x10)
-#define GEMINI_TIMER3_BASE (GEMINI_TIMER_BASE + 0x20)

/*
* UART Clock when System clk is 150MHz
diff --git a/arch/arm/mach-gemini/time.c b/arch/arm/mach-gemini/time.c
index b57d367..fd751b1 100644
--- a/arch/arm/mach-gemini/time.c
+++ b/arch/arm/mach-gemini/time.c
@@ -19,21 +19,46 @@
/*
* Register definitions for the timers
*/
-#define TIMER_COUNT(BASE_ADDR) (BASE_ADDR + 0x00)
-#define TIMER_LOAD(BASE_ADDR) (BASE_ADDR + 0x04)
-#define TIMER_MATCH1(BASE_ADDR) (BASE_ADDR + 0x08)
-#define TIMER_MATCH2(BASE_ADDR) (BASE_ADDR + 0x0C)
-#define TIMER_CR(BASE_ADDR) (BASE_ADDR + 0x30)
-
-#define TIMER_1_CR_ENABLE (1 << 0)
-#define TIMER_1_CR_CLOCK (1 << 1)
-#define TIMER_1_CR_INT (1 << 2)
-#define TIMER_2_CR_ENABLE (1 << 3)
-#define TIMER_2_CR_CLOCK (1 << 4)
-#define TIMER_2_CR_INT (1 << 5)
-#define TIMER_3_CR_ENABLE (1 << 6)
-#define TIMER_3_CR_CLOCK (1 << 7)
-#define TIMER_3_CR_INT (1 << 8)
+
+#define TIMER1_BASE GEMINI_TIMER_BASE
+#define TIMER2_BASE (GEMINI_TIMER_BASE + 0x10)
+#define TIMER3_BASE (GEMINI_TIMER_BASE + 0x20)
+
+#define TIMER_COUNT(BASE) (IO_ADDRESS(BASE) + 0x00)
+#define TIMER_LOAD(BASE) (IO_ADDRESS(BASE) + 0x04)
+#define TIMER_MATCH1(BASE) (IO_ADDRESS(BASE) + 0x08)
+#define TIMER_MATCH2(BASE) (IO_ADDRESS(BASE) + 0x0C)
+#define TIMER_CR (IO_ADDRESS(GEMINI_TIMER_BASE) + 0x30)
+#define TIMER_INTR_STATE (IO_ADDRESS(GEMINI_TIMER_BASE) + 0x34)
+#define TIMER_INTR_MASK (IO_ADDRESS(GEMINI_TIMER_BASE) + 0x38)
+
+#define TIMER_1_CR_ENABLE (1 << 0)
+#define TIMER_1_CR_CLOCK (1 << 1)
+#define TIMER_1_CR_INT (1 << 2)
+#define TIMER_2_CR_ENABLE (1 << 3)
+#define TIMER_2_CR_CLOCK (1 << 4)
+#define TIMER_2_CR_INT (1 << 5)
+#define TIMER_3_CR_ENABLE (1 << 6)
+#define TIMER_3_CR_CLOCK (1 << 7)
+#define TIMER_3_CR_INT (1 << 8)
+#define TIMER_1_CR_UPDOWN (1 << 9)
+#define TIMER_2_CR_UPDOWN (1 << 10)
+#define TIMER_3_CR_UPDOWN (1 << 11)
+#define TIMER_DEFAULT_FLAGS (TIMER_1_CR_UPDOWN | \
+ TIMER_3_CR_ENABLE | \
+ TIMER_3_CR_UPDOWN)
+
+#define TIMER_1_INT_MATCH1 (1 << 0)
+#define TIMER_1_INT_MATCH2 (1 << 1)
+#define TIMER_1_INT_OVERFLOW (1 << 2)
+#define TIMER_2_INT_MATCH1 (1 << 3)
+#define TIMER_2_INT_MATCH2 (1 << 4)
+#define TIMER_2_INT_OVERFLOW (1 << 5)
+#define TIMER_3_INT_MATCH1 (1 << 6)
+#define TIMER_3_INT_MATCH2 (1 << 7)
+#define TIMER_3_INT_OVERFLOW (1 << 8)
+#define TIMER_INT_ALL_MASK 0x1ff
+

static unsigned int tick_rate;

@@ -42,19 +67,19 @@ static int gemini_timer_set_next_event(unsigned long cycles,
{
u32 cr;

- cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ cr = readl(TIMER_CR);

/* This may be overdoing it, feel free to test without this */
cr &= ~TIMER_2_CR_ENABLE;
cr &= ~TIMER_2_CR_INT;
- writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ writel(cr, TIMER_CR);

/* Set next event */
- writel(cycles, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE)));
- writel(cycles, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE)));
+ writel(cycles, TIMER_COUNT(TIMER2_BASE));
+ writel(cycles, TIMER_LOAD(TIMER2_BASE));
cr |= TIMER_2_CR_ENABLE;
cr |= TIMER_2_CR_INT;
- writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ writel(cr, TIMER_CR);

return 0;
}
@@ -67,10 +92,10 @@ static int gemini_timer_shutdown(struct clock_event_device *evt)
* Disable also for oneshot: the set_next() call will arm the timer
* instead.
*/
- cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ cr = readl(TIMER_CR);
cr &= ~TIMER_2_CR_ENABLE;
cr &= ~TIMER_2_CR_INT;
- writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ writel(cr, TIMER_CR);
return 0;
}

@@ -80,12 +105,12 @@ static int gemini_timer_set_periodic(struct clock_event_device *evt)
u32 cr;

/* Start the timer */
- writel(period, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE)));
- writel(period, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE)));
- cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ writel(period, TIMER_COUNT(TIMER2_BASE));
+ writel(period, TIMER_LOAD(TIMER2_BASE));
+ cr = readl(TIMER_CR);
cr |= TIMER_2_CR_ENABLE;
cr |= TIMER_2_CR_INT;
- writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+ writel(cr, TIMER_CR);
return 0;
}

@@ -155,10 +180,10 @@ void __init gemini_timer_init(void)
setup_irq(IRQ_TIMER2, &gemini_timer_irq);

/* Enable and use TIMER1 as clock source */
- writel(0xffffffff, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER1_BASE)));
- writel(0xffffffff, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER1_BASE)));
- writel(TIMER_1_CR_ENABLE, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
- if (clocksource_mmio_init(TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER1_BASE)),
+ writel(0xffffffff, TIMER_COUNT(TIMER1_BASE));
+ writel(0xffffffff, TIMER_LOAD(TIMER1_BASE));
+ writel(TIMER_1_CR_ENABLE, TIMER_CR);
+ if (clocksource_mmio_init(TIMER_COUNT(TIMER1_BASE),
"TIMER1", tick_rate, 300, 32,
clocksource_mmio_readl_up))
pr_err("timer: failed to initialize gemini clock source\n");
--
2.4.6

2015-08-11 20:11:26

by Hans Ulli Kroll

[permalink] [raw]
Subject: [PATCH 2/3] ARM:Gemini:use timer1 for clockevent

Use timer1 as clockevent timer.
The old driver uses timer2, which has some issues to setup

Signed-off-by: Hans Ulli Kroll <[email protected]>
---
arch/arm/mach-gemini/time.c | 94 +++++++++++++++++++++++++++++----------------
1 file changed, 60 insertions(+), 34 deletions(-)

diff --git a/arch/arm/mach-gemini/time.c b/arch/arm/mach-gemini/time.c
index fd751b1..5e2b1ba 100644
--- a/arch/arm/mach-gemini/time.c
+++ b/arch/arm/mach-gemini/time.c
@@ -67,19 +67,11 @@ static int gemini_timer_set_next_event(unsigned long cycles,
{
u32 cr;

- cr = readl(TIMER_CR);
-
- /* This may be overdoing it, feel free to test without this */
- cr &= ~TIMER_2_CR_ENABLE;
- cr &= ~TIMER_2_CR_INT;
- writel(cr, TIMER_CR);
-
- /* Set next event */
- writel(cycles, TIMER_COUNT(TIMER2_BASE));
- writel(cycles, TIMER_LOAD(TIMER2_BASE));
- cr |= TIMER_2_CR_ENABLE;
- cr |= TIMER_2_CR_INT;
- writel(cr, TIMER_CR);
+ /* Setup the match register */
+ cr = readl(TIMER_COUNT(TIMER1_BASE));
+ writel(cr + cycles, TIMER_MATCH1(TIMER1_BASE));
+ if (readl(TIMER_COUNT(TIMER1_BASE)) - cr > cycles)
+ return -ETIME;

return 0;
}
@@ -92,10 +84,26 @@ static int gemini_timer_shutdown(struct clock_event_device *evt)
* Disable also for oneshot: the set_next() call will arm the timer
* instead.
*/
+ /* Stop timer and interrupt. */
cr = readl(TIMER_CR);
- cr &= ~TIMER_2_CR_ENABLE;
- cr &= ~TIMER_2_CR_INT;
+ cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
writel(cr, TIMER_CR);
+
+ /* Setup counter start from 0 */
+ writel(0, TIMER_COUNT(TIMER1_BASE));
+ writel(0, TIMER_LOAD(TIMER1_BASE));
+
+ /* enable interrupt */
+ cr = readl(TIMER_INTR_MASK);
+ cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2);
+ cr |= TIMER_1_INT_MATCH1;
+ writel(cr, TIMER_INTR_MASK);
+
+ /* start the timer */
+ cr = readl(TIMER_CR);
+ cr |= TIMER_1_CR_ENABLE;
+ writel(cr, TIMER_CR);
+
return 0;
}

@@ -104,21 +112,37 @@ static int gemini_timer_set_periodic(struct clock_event_device *evt)
u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ);
u32 cr;

+ /* Stop timer and interrupt */
+ cr = readl(TIMER_CR);
+ cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
+ writel(cr, TIMER_CR);
+
+ /* Setup timer to fire at 1/HT intervals. */
+ cr = 0xffffffff - (period - 1);
+ writel(cr, TIMER_COUNT(TIMER1_BASE));
+ writel(cr, TIMER_LOAD(TIMER1_BASE));
+
+ /* enable interrupt on overflow */
+ cr = readl(TIMER_INTR_MASK);
+ cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2);
+ cr |= TIMER_1_INT_OVERFLOW;
+ writel(cr, TIMER_INTR_MASK);
+
/* Start the timer */
- writel(period, TIMER_COUNT(TIMER2_BASE));
- writel(period, TIMER_LOAD(TIMER2_BASE));
cr = readl(TIMER_CR);
- cr |= TIMER_2_CR_ENABLE;
- cr |= TIMER_2_CR_INT;
+ cr |= TIMER_1_CR_ENABLE;
+ cr |= TIMER_1_CR_INT;
writel(cr, TIMER_CR);
+
return 0;
}

-/* Use TIMER2 as clock event */
+/* Use TIMER1 as clock event */
static struct clock_event_device gemini_clockevent = {
- .name = "TIMER2",
+ .name = "TIMER1",
/* Reasonably fast and accurate clock event */
.rating = 300,
+ .shift = 32,
.features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = gemini_timer_set_next_event,
@@ -175,20 +199,22 @@ void __init gemini_timer_init(void)
}

/*
- * Make irqs happen for the system timer
+ * Reset the interrupt mask and status
*/
- setup_irq(IRQ_TIMER2, &gemini_timer_irq);
-
- /* Enable and use TIMER1 as clock source */
- writel(0xffffffff, TIMER_COUNT(TIMER1_BASE));
- writel(0xffffffff, TIMER_LOAD(TIMER1_BASE));
- writel(TIMER_1_CR_ENABLE, TIMER_CR);
- if (clocksource_mmio_init(TIMER_COUNT(TIMER1_BASE),
- "TIMER1", tick_rate, 300, 32,
- clocksource_mmio_readl_up))
- pr_err("timer: failed to initialize gemini clock source\n");
-
- /* Configure and register the clockevent */
+ writel(TIMER_INT_ALL_MASK, TIMER_INTR_MASK);
+ writel(0, TIMER_INTR_STATE);
+ writel(TIMER_DEFAULT_FLAGS, TIMER_CR);
+
+ /*
+ * Setup clockevent timer (interrupt-driven.)
+ */
+ writel(0, TIMER_COUNT(TIMER1_BASE));
+ writel(0, TIMER_LOAD(TIMER1_BASE));
+ writel(0, TIMER_MATCH1(TIMER1_BASE));
+ writel(0, TIMER_MATCH2(TIMER1_BASE));
+ setup_irq(IRQ_TIMER1, &gemini_timer_irq);
+ gemini_clockevent.cpumask = cpumask_of(0);
clockevents_config_and_register(&gemini_clockevent, tick_rate,
1, 0xffffffff);
+
}
--
2.4.6

2015-08-11 20:10:46

by Hans Ulli Kroll

[permalink] [raw]
Subject: [PATCH 3/3] ARM:Gemini:setup timer3 as free running timer

In the original driver it is missed to setup a free running driver.
This timer is needed for the scheduler.
So setup it.

Signed-off-by: Hans Ulli Kroll <[email protected]>
---
arch/arm/mach-gemini/time.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-gemini/time.c b/arch/arm/mach-gemini/time.c
index 5e2b1ba..f5f18df 100644
--- a/arch/arm/mach-gemini/time.c
+++ b/arch/arm/mach-gemini/time.c
@@ -15,6 +15,7 @@
#include <asm/mach/time.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
+#include <linux/sched_clock.h>

/*
* Register definitions for the timers
@@ -62,6 +63,11 @@

static unsigned int tick_rate;

+static u64 notrace gemini_read_sched_clock(void)
+{
+ return readl(TIMER_COUNT(TIMER3_BASE));
+}
+
static int gemini_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
@@ -206,8 +212,21 @@ void __init gemini_timer_init(void)
writel(TIMER_DEFAULT_FLAGS, TIMER_CR);

/*
- * Setup clockevent timer (interrupt-driven.)
+ * Setup free-running clocksource timer (interrupts
+ * disabled.)
*/
+ writel(0, TIMER_COUNT(TIMER3_BASE));
+ writel(0, TIMER_LOAD(TIMER3_BASE));
+ writel(0, TIMER_MATCH1(TIMER3_BASE));
+ writel(0, TIMER_MATCH2(TIMER3_BASE));
+ clocksource_mmio_init(TIMER_COUNT(TIMER3_BASE),
+ "gemini_clocksource", tick_rate,
+ 300, 32, clocksource_mmio_readl_up);
+ sched_clock_register(gemini_read_sched_clock, 32, tick_rate);
+
+ /*
+ * Setup clockevent timer (interrupt-driven.)
+ */
writel(0, TIMER_COUNT(TIMER1_BASE));
writel(0, TIMER_LOAD(TIMER1_BASE));
writel(0, TIMER_MATCH1(TIMER1_BASE));
--
2.4.6

2015-08-12 12:41:53

by Linus Walleij

[permalink] [raw]
Subject: Re: ARM: gemini: clocksource update for 4.3 v2

On Tue, Aug 11, 2015 at 10:09 PM, Hans Ulli Kroll
<[email protected]> wrote:

> these is version 2 of the clocksource updates for 4.3

Reviewed-by: Linus Walleij <[email protected]>

For all three patches.

Yours,
Linus Walleij

2015-08-12 20:36:42

by Roman Yeryomin

[permalink] [raw]
Subject: Re: ARM:Gemini:clocksource update for 4.3

On 2015-08-07 16:56, Hans Ulli Kroll wrote:
> Hi all,
>
> sorry for being late in this cycle ...
> I asked Roman to send me his patchset with 2 patched, but he don't
> respond.

Sorry, was in business trip, just returned.

> So here is my patchset.

Thanks for taking care!


Regards,
Roman

2015-08-13 09:43:15

by Olof Johansson

[permalink] [raw]
Subject: Re: ARM: gemini: clocksource update for 4.3 v2

On Wed, Aug 12, 2015 at 02:41:50PM +0200, Linus Walleij wrote:
> On Tue, Aug 11, 2015 at 10:09 PM, Hans Ulli Kroll
> <[email protected]> wrote:
>
> > these is version 2 of the clocksource updates for 4.3
>
> Reviewed-by: Linus Walleij <[email protected]>
>
> For all three patches.

Thanks for the review, Linus!


-Olof

2015-08-13 09:43:22

by Olof Johansson

[permalink] [raw]
Subject: Re: ARM: gemini: clocksource update for 4.3 v2

On Tue, Aug 11, 2015 at 10:09:02PM +0200, Hans Ulli Kroll wrote:
> Hi,
>
> these is version 2 of the clocksource updates for 4.3
>
> These patches are rebased on your arm-soc/for-next tree.
> latest commit e4c4ce53a925146167a58cfd2e862952cdc316e1
>
> arm-soc: document merges
>
> They is also a patch from Viresh Kumar in mach-gemini
> ARM/gemini/time: Migrate to new 'set-state' interface
>
> The other patches affecting clocksource are going through the
> clocksource tree.

Thanks, applied now!

> For the clocksource in general :
> I'm planning to move to DT. mach-moxart locks promising.
> Same CPU FA526 as mach-gemini.
> But they are two devices they can't moved easily to DT.
> - MISC global reg for differnt device settings
> - ethernet, up to 2 irq's, shared address space (bitfield)
>
> Don't ask me why the engineers have done this ...
>
> So I need DT in conjunction with (one) board file(s).
> Is this possible ??

It might be a bit messy to deal with a few things when you split between board
files and DT. In general you might be interested in looking at the syscon
bindings which tend to be used when there are "misc" registers on a SoC that
multiple drivers need to share.


See Documentation/devicetree/bindings/mfd/syscon.txt and other drivers and
platforms for examples of that.

-Olof