diff mbox

RFT: ARM: gemini: convert to GENERIC_CLOCKEVENTS

Message ID 1380625040-25912-1-git-send-email-linus.walleij@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Linus Walleij Oct. 1, 2013, 10:57 a.m. UTC
This converts the gemini machine to use generic clockevents
by rewriting the timer driver.

Cc: arm@kernel.org
Cc: Hans Ulli Kroll <ulli.kroll@googlemail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
This is flagged as Request for Testing (RFT) as I have no Gemini
platform. If I do not get help with testing this, the next step
will be a patch series to delete the platform.
---
 arch/arm/Kconfig            |  3 +-
 arch/arm/mach-gemini/time.c | 97 +++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 91 insertions(+), 9 deletions(-)

Comments

Arnd Bergmann Oct. 1, 2013, 11:28 a.m. UTC | #1
On Tuesday 01 October 2013, Linus Walleij wrote:
> This converts the gemini machine to use generic clockevents
> by rewriting the timer driver.

I've put a few more people on Cc that I think have access to hardware, according
to the openwrt changelog for gemini.

It would be great if someone could test the patch before we apply it.

	Arnd

> Cc: arm@kernel.org
> Cc: Hans Ulli Kroll <ulli.kroll@googlemail.com>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> This is flagged as Request for Testing (RFT) as I have no Gemini
> platform. If I do not get help with testing this, the next step
> will be a patch series to delete the platform.

I've suggested removing the platform before, but got the feedback that it's
actively maintained in openwrt. Unfortunately we didn't get much
activity to upstream the patches from
http://git.openwrt.org/?p=openwrt.git;a=tree;f=target/linux/gemini/patches
which are apparently required.

Rather than deleting the platform entirely, I'd be more inclined to accept
any cleanup patches like yours, testing or not, and let the downstream
users deal with fixing it up if it breaks. The ideal case of course would
be for someone to actively maintain the platform again and submit any patches
that are needed.

	Arnd

> ---
>  arch/arm/Kconfig            |  3 +-
>  arch/arm/mach-gemini/time.c | 97 +++++++++++++++++++++++++++++++++++++++++----
>  2 files changed, 91 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 1ad6fb6..1a903e6 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -386,8 +386,9 @@ config ARCH_CLPS711X
>  config ARCH_GEMINI
>  	bool "Cortina Systems Gemini"
>  	select ARCH_REQUIRE_GPIOLIB
> -	select ARCH_USES_GETTIMEOFFSET
> +	select CLKSRC_MMIO
>  	select CPU_FA526
> +	select GENERIC_CLOCKEVENTS
>  	select NEED_MACH_GPIO_H
>  	help
>  	  Support for the Cortina Systems Gemini family SoCs
> diff --git a/arch/arm/mach-gemini/time.c b/arch/arm/mach-gemini/time.c
> index 21dc5a8..0a63c4d 100644
> --- a/arch/arm/mach-gemini/time.c
> +++ b/arch/arm/mach-gemini/time.c
> @@ -13,6 +13,8 @@
>  #include <mach/hardware.h>
>  #include <mach/global_reg.h>
>  #include <asm/mach/time.h>
> +#include <linux/clockchips.h>
> +#include <linux/clocksource.h>
>  
>  /*
>   * Register definitions for the timers
> @@ -33,19 +35,89 @@
>  #define TIMER_3_CR_CLOCK		(1 << 7)
>  #define TIMER_3_CR_INT			(1 << 8)
>  
> +static unsigned int tick_rate;
> +
> +static int gemini_timer_set_next_event(unsigned long cycles,
> +				       struct clock_event_device *evt)
> +{
> +	u32 cr;
> +
> +	cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
> +
> +	/* 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)));
> +
> +	/* Set next event */
> +	writel(cycles, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE)));
> +	writel(cycles, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE)));
> +	cr |= TIMER_2_CR_ENABLE;
> +	cr |= TIMER_2_CR_INT;
> +	writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
> +
> +	return 0;
> +}
> +
> +static void gemini_timer_set_mode(enum clock_event_mode mode,
> +				  struct clock_event_device *evt)
> +{
> +	u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ);
> +	u32 cr;
> +
> +	switch (mode) {
> +        case CLOCK_EVT_MODE_PERIODIC:
> +		/* 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)));
> +		cr |= TIMER_2_CR_ENABLE;
> +		cr |= TIMER_2_CR_INT;
> +		writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
> +		break;
> +	case CLOCK_EVT_MODE_ONESHOT:
> +	case CLOCK_EVT_MODE_UNUSED:
> +        case CLOCK_EVT_MODE_SHUTDOWN:
> +	case CLOCK_EVT_MODE_RESUME:
> +		/*
> +		 * Disable also for oneshot: the set_next() call will
> +		 * arm the timer instead.
> +		 */
> +		cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
> +		cr &= ~TIMER_2_CR_ENABLE;
> +		cr &= ~TIMER_2_CR_INT;
> +		writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
> +		break;
> +	default:
> +                break;
> +	}
> +}
> +
> +/* Use TIMER2 as clock event */
> +static struct clock_event_device gemini_clockevent = {
> +	.name		= "TIMER2",
> +	.rating		= 300, /* Reasonably fast and accurate clock event */
> +	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> +	.set_next_event	= gemini_timer_set_next_event,
> +	.set_mode	= gemini_timer_set_mode,
> +};
> +
>  /*
>   * IRQ handler for the timer
>   */
>  static irqreturn_t gemini_timer_interrupt(int irq, void *dev_id)
>  {
> -	timer_tick();
> +	struct clock_event_device *evt = &gemini_clockevent;
>  
> +	evt->event_handler(evt);
>  	return IRQ_HANDLED;
>  }
>  
>  static struct irqaction gemini_timer_irq = {
>  	.name		= "Gemini Timer Tick",
> -	.flags		= IRQF_DISABLED | IRQF_TIMER,
> +	.flags		= IRQF_TIMER,
>  	.handler	= gemini_timer_interrupt,
>  };
>  
> @@ -54,9 +126,9 @@ static struct irqaction gemini_timer_irq = {
>   */
>  void __init gemini_timer_init(void)
>  {
> -	unsigned int tick_rate, reg_v;
> +	u32 reg_v;
>  
> -	reg_v = __raw_readl(IO_ADDRESS(GEMINI_GLOBAL_BASE + GLOBAL_STATUS));
> +	reg_v = readl(IO_ADDRESS(GEMINI_GLOBAL_BASE + GLOBAL_STATUS));
>  	tick_rate = REG_TO_AHB_SPEED(reg_v) * 1000000;
>  
>  	printk(KERN_INFO "Bus: %dMHz", tick_rate / 1000000);
> @@ -82,8 +154,17 @@ void __init gemini_timer_init(void)
>  	 * Make irqs happen for the system timer
>  	 */
>  	setup_irq(IRQ_TIMER2, &gemini_timer_irq);
> -	/* Start the timer */
> -	__raw_writel(tick_rate / HZ, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE)));
> -	__raw_writel(tick_rate / HZ, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE)));
> -	__raw_writel(TIMER_2_CR_ENABLE | TIMER_2_CR_INT, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
> +
> +	/* 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)),
> +				  "TIMER1", tick_rate, 300, 32,
> +				  clocksource_mmio_readl_up))
> +		pr_err("timer: failed to initialize gemini clock source\n");
> +
> +	/* Configure and register the clockevent */
> +	clockevents_config_and_register(&gemini_clockevent, tick_rate,
> +					1, 0xffffffff);
>  }
> -- 
> 1.8.3.1
> 
>
Linus Walleij Oct. 1, 2013, 11:56 a.m. UTC | #2
On Tue, Oct 1, 2013 at 1:28 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tuesday 01 October 2013, Linus Walleij wrote:
>> This converts the gemini machine to use generic clockevents
>> by rewriting the timer driver.
>
> I've put a few more people on Cc that I think have access to hardware, according
> to the openwrt changelog for gemini.

Thanks, if the fine OpenWRT folks can suggest a cheapo piece of equipment
that is fully supported by OpenWRT and that I can eBay to test my patches on
my own I'm all ears.

> I've suggested removing the platform before, but got the feedback that it's
> actively maintained in openwrt. Unfortunately we didn't get much
> activity to upstream the patches from
> http://git.openwrt.org/?p=openwrt.git;a=tree;f=target/linux/gemini/patches
> which are apparently required.

Both with OpenWRT and OpenEmbedded we are seeing this forking
instead of working with actively upstreaming and reducing the patch
stack. This is not so nice, we need to discuss what can be done to
reduce the patch stacks carried by other Open Source projects such
as these.

> Rather than deleting the platform entirely, I'd be more inclined to accept
> any cleanup patches like yours, testing or not, and let the downstream
> users deal with fixing it up if it breaks. The ideal case of course would
> be for someone to actively maintain the platform again and submit any patches
> that are needed.

Yeah :-/

As with any other platform with an active community interested in
long-term support it'd be best if someone stepped up to do
the necessary conversion to DT and maybe also multiplatform
(no idea if that works with the FA526 CPU though) so we can get
the maintenance burden down for everone involved.

I suggested project like this for the advanced kernel newbies
actually... let's see if it takes hold.

Yours,
Linus Walleij
Florian Fainelli Oct. 1, 2013, 1:18 p.m. UTC | #3
2013/10/1 Linus Walleij <linus.walleij@linaro.org>:
> On Tue, Oct 1, 2013 at 1:28 PM, Arnd Bergmann <arnd@arndb.de> wrote:
>> On Tuesday 01 October 2013, Linus Walleij wrote:
>>> This converts the gemini machine to use generic clockevents
>>> by rewriting the timer driver.
>>
>> I've put a few more people on Cc that I think have access to hardware, according
>> to the openwrt changelog for gemini.
>
> Thanks, if the fine OpenWRT folks can suggest a cheapo piece of equipment
> that is fully supported by OpenWRT and that I can eBay to test my patches on
> my own I'm all ears.

I can't remember off the top of my head what exact hardware Tomasz
Figa handed to me (could probably find it somewhere tomorrow).

>
>> I've suggested removing the platform before, but got the feedback that it's
>> actively maintained in openwrt. Unfortunately we didn't get much
>> activity to upstream the patches from
>> http://git.openwrt.org/?p=openwrt.git;a=tree;f=target/linux/gemini/patches
>> which are apparently required.
>
> Both with OpenWRT and OpenEmbedded we are seeing this forking
> instead of working with actively upstreaming and reducing the patch
> stack. This is not so nice, we need to discuss what can be done to
> reduce the patch stacks carried by other Open Source projects such
> as these.

I definitively agree, this has been a bad practice over the years, and
even though some of us have tried to resolve that, we are still not
quite there yet.

>
>> Rather than deleting the platform entirely, I'd be more inclined to accept
>> any cleanup patches like yours, testing or not, and let the downstream
>> users deal with fixing it up if it breaks. The ideal case of course would
>> be for someone to actively maintain the platform again and submit any patches
>> that are needed.
>
> Yeah :-/
>
> As with any other platform with an active community interested in
> long-term support it'd be best if someone stepped up to do
> the necessary conversion to DT and maybe also multiplatform
> (no idea if that works with the FA526 CPU though) so we can get
> the maintenance burden down for everone involved.
>
> I suggested project like this for the advanced kernel newbies
> actually... let's see if it takes hold.

One big prerequisite is having actual hardware support, we can
probably work out something to give these people access to hardware
(either remotely or physically).

Does not anybody actually have a farm of "old" ARM-based platforms
besides Olof? That way we could just ship the device to someone kind
enough to get some power supply + network + serial + JTAG/system
reset?
Arnd Bergmann Oct. 1, 2013, 5:42 p.m. UTC | #4
On Tuesday 01 October 2013, Linus Walleij wrote:
> As with any other platform with an active community interested in
> long-term support it'd be best if someone stepped up to do
> the necessary conversion to DT and maybe also multiplatform
> (no idea if that works with the FA526 CPU though) so we can get
> the maintenance burden down for everone involved.

Regarding multiplatform, IIRC Jonas Jensen had some issues with
ARM9 and FA526 being enabled at the same time (with mach-moxart),
which is probably easy enough to fix if necessary. You should
also be able to have a combined moxart+gemini kernel once someone
looks into multiplatform gemini. The only nonobvious part I can
see required for that is NEED_MACH_GPIO_H, and even that should
be simpler than the clockevents patch you just sent.

	Arnd
Linus Walleij Oct. 2, 2013, 7:52 a.m. UTC | #5
On Tue, Oct 1, 2013 at 7:42 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tuesday 01 October 2013, Linus Walleij wrote:
>> As with any other platform with an active community interested in
>> long-term support it'd be best if someone stepped up to do
>> the necessary conversion to DT and maybe also multiplatform
>> (no idea if that works with the FA526 CPU though) so we can get
>> the maintenance burden down for everone involved.
>
> Regarding multiplatform, IIRC Jonas Jensen had some issues with
> ARM9 and FA526 being enabled at the same time (with mach-moxart),
> which is probably easy enough to fix if necessary. You should
> also be able to have a combined moxart+gemini kernel once someone
> looks into multiplatform gemini. The only nonobvious part I can
> see required for that is NEED_MACH_GPIO_H, and even that should
> be simpler than the clockevents patch you just sent.

I sent a patch to delete NEED_MACH_GPIO_H as well and already
applied it to the GPIO tree, it was a piece of cake (unless I have
now unwittingly broken something).

Yours,
Linus Walleij
Arnd Bergmann Oct. 2, 2013, 11:58 p.m. UTC | #6
On Wednesday 02 October 2013, Linus Walleij wrote:
> On Tue, Oct 1, 2013 at 7:42 PM, Arnd Bergmann <arnd@arndb.de> wrote:
>
> > Regarding multiplatform, IIRC Jonas Jensen had some issues with
> > ARM9 and FA526 being enabled at the same time (with mach-moxart),
> > which is probably easy enough to fix if necessary. You should
> > also be able to have a combined moxart+gemini kernel once someone
> > looks into multiplatform gemini. The only nonobvious part I can
> > see required for that is NEED_MACH_GPIO_H, and even that should
> > be simpler than the clockevents patch you just sent.
> 
> I sent a patch to delete NEED_MACH_GPIO_H as well and already
> applied it to the GPIO tree, it was a piece of cake (unless I have
> now unwittingly broken something).

Ah, cool. Upon  brief look I could not find any users for the other
header files, so I guess we can try to just go ahead and move them
all out of include/mach/ to mach-gemini/*.h or to include/debug.

On second look, we need to convert it to MULTI_IRQ_HANDLER first.

	Arnd
Linus Walleij Oct. 24, 2013, 10:06 a.m. UTC | #7
On Tue, Oct 1, 2013 at 12:57 PM, Linus Walleij <linus.walleij@linaro.org> wrote:

> This converts the gemini machine to use generic clockevents
> by rewriting the timer driver.
>
> Cc: arm@kernel.org
> Cc: Hans Ulli Kroll <ulli.kroll@googlemail.com>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> This is flagged as Request for Testing (RFT) as I have no Gemini
> platform. If I do not get help with testing this, the next step
> will be a patch series to delete the platform.

OK nobody is able to test this it seems, but it is a vital refactoring.

Should we just apply this and see what happens?

Or should I just send a deletion patch right away?

I would lean toward just applying it and see if the OpenWRT
people will notice and/or complain.

What does the ARM SoC people say?

Yours,
Linus Walleij
Olof Johansson Oct. 24, 2013, 2 p.m. UTC | #8
On Thu, Oct 24, 2013 at 3:06 AM, Linus Walleij <linus.walleij@linaro.org> wrote:
> On Tue, Oct 1, 2013 at 12:57 PM, Linus Walleij <linus.walleij@linaro.org> wrote:
>
>> This converts the gemini machine to use generic clockevents
>> by rewriting the timer driver.
>>
>> Cc: arm@kernel.org
>> Cc: Hans Ulli Kroll <ulli.kroll@googlemail.com>
>> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
>> ---
>> This is flagged as Request for Testing (RFT) as I have no Gemini
>> platform. If I do not get help with testing this, the next step
>> will be a patch series to delete the platform.
>
> OK nobody is able to test this it seems, but it is a vital refactoring.
>
> Should we just apply this and see what happens?
>
> Or should I just send a deletion patch right away?
>
> I would lean toward just applying it and see if the OpenWRT
> people will notice and/or complain.
>
> What does the ARM SoC people say?

I suspect the feedback latency will be very long, since they don't
track upstream closely (or at least don't on all platforms). So either
way, really. We can definitely pick it up and fix up later if needed
-- given that you haven't found testers I'm suspecting very few people
would likewise be impacted by any kind of breakage introduced.


-Olof
Linus Walleij Oct. 24, 2013, 2:30 p.m. UTC | #9
Adding openwrt-devel to this thread to get some traction...

On Thu, Oct 24, 2013 at 12:06 PM, Linus Walleij
<linus.walleij@linaro.org> wrote:
> On Tue, Oct 1, 2013 at 12:57 PM, Linus Walleij <linus.walleij@linaro.org> wrote:
>
>> This converts the gemini machine to use generic clockevents
>> by rewriting the timer driver.
>>
>> Cc: arm@kernel.org
>> Cc: Hans Ulli Kroll <ulli.kroll@googlemail.com>
>> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
>> ---
>> This is flagged as Request for Testing (RFT) as I have no Gemini
>> platform. If I do not get help with testing this, the next step
>> will be a patch series to delete the platform.
>
> OK nobody is able to test this it seems, but it is a vital refactoring.
>
> Should we just apply this and see what happens?
>
> Or should I just send a deletion patch right away?
>
> I would lean toward just applying it and see if the OpenWRT
> people will notice and/or complain.
>
> What does the ARM SoC people say?
>
> Yours,
> Linus Walleij
Florian Fainelli Oct. 24, 2013, 4:47 p.m. UTC | #10
Hello Linus,

2013/10/24 Linus Walleij <linus.walleij@linaro.org>:
> Adding openwrt-devel to this thread to get some traction...

I won't have my gemini device available for the next 6-8 weeks, so
just go ahead and merge this, if it breaks, there is still time to
figure out how to unbreak later. It cannot possibly be worse since few
people have it and actually seem to use it. Does that work for you?

>
> On Thu, Oct 24, 2013 at 12:06 PM, Linus Walleij
> <linus.walleij@linaro.org> wrote:
>> On Tue, Oct 1, 2013 at 12:57 PM, Linus Walleij <linus.walleij@linaro.org> wrote:
>>
>>> This converts the gemini machine to use generic clockevents
>>> by rewriting the timer driver.
>>>
>>> Cc: arm@kernel.org
>>> Cc: Hans Ulli Kroll <ulli.kroll@googlemail.com>
>>> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
>>> ---
>>> This is flagged as Request for Testing (RFT) as I have no Gemini
>>> platform. If I do not get help with testing this, the next step
>>> will be a patch series to delete the platform.
>>
>> OK nobody is able to test this it seems, but it is a vital refactoring.
>>
>> Should we just apply this and see what happens?
>>
>> Or should I just send a deletion patch right away?
>>
>> I would lean toward just applying it and see if the OpenWRT
>> people will notice and/or complain.
>>
>> What does the ARM SoC people say?
>>
>> Yours,
>> Linus Walleij
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel@lists.openwrt.org
> https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
Arnd Bergmann Oct. 24, 2013, 10:06 p.m. UTC | #11
On Thursday 24 October 2013, Linus Walleij wrote:

> > This is flagged as Request for Testing (RFT) as I have no Gemini
> > platform. If I do not get help with testing this, the next step
> > will be a patch series to delete the platform.
> 
> OK nobody is able to test this it seems, but it is a vital refactoring.
> 
> Should we just apply this and see what happens?
> 
> Or should I just send a deletion patch right away?
> 
> I would lean toward just applying it and see if the OpenWRT
> people will notice and/or complain.
> 
> What does the ARM SoC people say?

I'd prefer applying it as-is.

	Arnd
Linus Walleij Oct. 25, 2013, 1:53 p.m. UTC | #12
On Fri, Oct 25, 2013 at 12:06 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Thursday 24 October 2013, Linus Walleij wrote:
>
>> I would lean toward just applying it and see if the OpenWRT
>> people will notice and/or complain.
>>
>> What does the ARM SoC people say?
>
> I'd prefer applying it as-is.

OK Olof/Kevin: can either of you strip "RFT" from $SUBJECT
and apply this patch to the ARM SoC tree?

Yours,
Linus Walleij
Olof Johansson Oct. 28, 2013, 10:07 p.m. UTC | #13
On Fri, Oct 25, 2013 at 03:53:17PM +0200, Linus Walleij wrote:
> On Fri, Oct 25, 2013 at 12:06 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Thursday 24 October 2013, Linus Walleij wrote:
> >
> >> I would lean toward just applying it and see if the OpenWRT
> >> people will notice and/or complain.
> >>
> >> What does the ARM SoC people say?
> >
> > I'd prefer applying it as-is.
> 
> OK Olof/Kevin: can either of you strip "RFT" from $SUBJECT
> and apply this patch to the ARM SoC tree?

Done, applied to next/cleanup.


-Olof
diff mbox

Patch

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1ad6fb6..1a903e6 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -386,8 +386,9 @@  config ARCH_CLPS711X
 config ARCH_GEMINI
 	bool "Cortina Systems Gemini"
 	select ARCH_REQUIRE_GPIOLIB
-	select ARCH_USES_GETTIMEOFFSET
+	select CLKSRC_MMIO
 	select CPU_FA526
+	select GENERIC_CLOCKEVENTS
 	select NEED_MACH_GPIO_H
 	help
 	  Support for the Cortina Systems Gemini family SoCs
diff --git a/arch/arm/mach-gemini/time.c b/arch/arm/mach-gemini/time.c
index 21dc5a8..0a63c4d 100644
--- a/arch/arm/mach-gemini/time.c
+++ b/arch/arm/mach-gemini/time.c
@@ -13,6 +13,8 @@ 
 #include <mach/hardware.h>
 #include <mach/global_reg.h>
 #include <asm/mach/time.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
 
 /*
  * Register definitions for the timers
@@ -33,19 +35,89 @@ 
 #define TIMER_3_CR_CLOCK		(1 << 7)
 #define TIMER_3_CR_INT			(1 << 8)
 
+static unsigned int tick_rate;
+
+static int gemini_timer_set_next_event(unsigned long cycles,
+				       struct clock_event_device *evt)
+{
+	u32 cr;
+
+	cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+
+	/* 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)));
+
+	/* Set next event */
+	writel(cycles, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE)));
+	writel(cycles, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE)));
+	cr |= TIMER_2_CR_ENABLE;
+	cr |= TIMER_2_CR_INT;
+	writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+
+	return 0;
+}
+
+static void gemini_timer_set_mode(enum clock_event_mode mode,
+				  struct clock_event_device *evt)
+{
+	u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ);
+	u32 cr;
+
+	switch (mode) {
+        case CLOCK_EVT_MODE_PERIODIC:
+		/* 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)));
+		cr |= TIMER_2_CR_ENABLE;
+		cr |= TIMER_2_CR_INT;
+		writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_UNUSED:
+        case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_RESUME:
+		/*
+		 * Disable also for oneshot: the set_next() call will
+		 * arm the timer instead.
+		 */
+		cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+		cr &= ~TIMER_2_CR_ENABLE;
+		cr &= ~TIMER_2_CR_INT;
+		writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+		break;
+	default:
+                break;
+	}
+}
+
+/* Use TIMER2 as clock event */
+static struct clock_event_device gemini_clockevent = {
+	.name		= "TIMER2",
+	.rating		= 300, /* Reasonably fast and accurate clock event */
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.set_next_event	= gemini_timer_set_next_event,
+	.set_mode	= gemini_timer_set_mode,
+};
+
 /*
  * IRQ handler for the timer
  */
 static irqreturn_t gemini_timer_interrupt(int irq, void *dev_id)
 {
-	timer_tick();
+	struct clock_event_device *evt = &gemini_clockevent;
 
+	evt->event_handler(evt);
 	return IRQ_HANDLED;
 }
 
 static struct irqaction gemini_timer_irq = {
 	.name		= "Gemini Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_TIMER,
 	.handler	= gemini_timer_interrupt,
 };
 
@@ -54,9 +126,9 @@  static struct irqaction gemini_timer_irq = {
  */
 void __init gemini_timer_init(void)
 {
-	unsigned int tick_rate, reg_v;
+	u32 reg_v;
 
-	reg_v = __raw_readl(IO_ADDRESS(GEMINI_GLOBAL_BASE + GLOBAL_STATUS));
+	reg_v = readl(IO_ADDRESS(GEMINI_GLOBAL_BASE + GLOBAL_STATUS));
 	tick_rate = REG_TO_AHB_SPEED(reg_v) * 1000000;
 
 	printk(KERN_INFO "Bus: %dMHz", tick_rate / 1000000);
@@ -82,8 +154,17 @@  void __init gemini_timer_init(void)
 	 * Make irqs happen for the system timer
 	 */
 	setup_irq(IRQ_TIMER2, &gemini_timer_irq);
-	/* Start the timer */
-	__raw_writel(tick_rate / HZ, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE)));
-	__raw_writel(tick_rate / HZ, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE)));
-	__raw_writel(TIMER_2_CR_ENABLE | TIMER_2_CR_INT, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+
+	/* 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)),
+				  "TIMER1", tick_rate, 300, 32,
+				  clocksource_mmio_readl_up))
+		pr_err("timer: failed to initialize gemini clock source\n");
+
+	/* Configure and register the clockevent */
+	clockevents_config_and_register(&gemini_clockevent, tick_rate,
+					1, 0xffffffff);
 }