Patchwork [U-Boot,3/4,v2] arm: Support new Xilinx Zynq platform

login
register
mail settings
Submitter Michal Simek
Date Aug. 16, 2012, 6:30 a.m.
Message ID <1345098630-27902-3-git-send-email-monstr@monstr.eu>
Download mbox | patch
Permalink /patch/177910/
State Superseded
Delegated to: Albert ARIBAUD
Headers show

Comments

Michal Simek - Aug. 16, 2012, 6:30 a.m.
Add timer driver.

Signed-off-by: Michal Simek <monstr@monstr.eu>

---
v2: Move lowlevel_init.S from board to cpu folder
    Remove XPSS prefix
    Rename XSCUTIMER -> SCUTIMER

Keep timer in zynq folder till ARM custodian comments it.
---
 arch/arm/cpu/armv7/zynq/Makefile        |   52 +++++++++++
 arch/arm/cpu/armv7/zynq/lowlevel_init.S |   27 ++++++
 arch/arm/cpu/armv7/zynq/timer.c         |  151 +++++++++++++++++++++++++++++++
 3 files changed, 230 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/zynq/Makefile
 create mode 100644 arch/arm/cpu/armv7/zynq/lowlevel_init.S
 create mode 100644 arch/arm/cpu/armv7/zynq/timer.c
Michal Simek - Sept. 12, 2012, 10:23 a.m.
On 08/16/2012 08:30 AM, Michal Simek wrote:
> Add timer driver.
>
> Signed-off-by: Michal Simek <monstr@monstr.eu>
>
> ---
> v2: Move lowlevel_init.S from board to cpu folder
>      Remove XPSS prefix
>      Rename XSCUTIMER -> SCUTIMER
>
> Keep timer in zynq folder till ARM custodian comments it.
> ---
>   arch/arm/cpu/armv7/zynq/Makefile        |   52 +++++++++++
>   arch/arm/cpu/armv7/zynq/lowlevel_init.S |   27 ++++++
>   arch/arm/cpu/armv7/zynq/timer.c         |  151 +++++++++++++++++++++++++++++++
>   3 files changed, 230 insertions(+), 0 deletions(-)
>   create mode 100644 arch/arm/cpu/armv7/zynq/Makefile
>   create mode 100644 arch/arm/cpu/armv7/zynq/lowlevel_init.S
>   create mode 100644 arch/arm/cpu/armv7/zynq/timer.c

We haven't got any reaction for Albert.
Marek and Joe: Can you review this? And give me your ACK or NACK.

Thanks,
Michal
Marek Vasut - Sept. 13, 2012, 9:31 a.m.
Dear Michal Simek,

[...]

> +#include <config.h>
> +#include <linux/linkage.h>
> +
> +ENTRY(lowlevel_init)
> +        mov     pc, lr
> +ENDPROC(lowlevel_init)

inline void lowlevel_init(void) {} works as well and you don't need the assembly 
file.

> diff --git a/arch/arm/cpu/armv7/zynq/timer.c
> b/arch/arm/cpu/armv7/zynq/timer.c new file mode 100644
> index 0000000..0252220
> --- /dev/null
> +++ b/arch/arm/cpu/armv7/zynq/timer.c
> @@ -0,0 +1,151 @@
> +/*
> + * Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
> + * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
> + *
> + * (C) Copyright 2008
> + * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
> + *
> + * (C) Copyright 2004
> + * Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
> + *
> + * (C) Copyright 2002-2004
> + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
> + *
> + * (C) Copyright 2003
> + * Texas Instruments <www.ti.com>
> + *
> + * (C) Copyright 2002
> + * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
> + * Marius Groeger <mgroeger@sysgo.de>
> + *
> + * (C) Copyright 2002
> + * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
> + * Alex Zuepke <azu@sysgo.de>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <div64.h>
> +#include <asm/io.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +struct scu_timer {
> +	u32 load; /* Timer Load Register */
> +	u32 counter; /* Timer Counter Register */
> +	u32 control; /* Timer Control Register */
> +};
> +
> +static struct scu_timer *timer_base = CONFIG_SCUTIMER_BASEADDR;
> +
> +#define SCUTIMER_CONTROL_PRESCALER_MASK	0x0000FF00 /* Prescaler */
> +#define SCUTIMER_CONTROL_PRESCALER_SHIFT	8
> +#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK	0x00000002 /* Auto-reload */
> +#define SCUTIMER_CONTROL_ENABLE_MASK		0x00000001 /* Timer enable */
> +
> +#define TIMER_LOAD_VAL 0xFFFFFFFF
> +#define TIMER_PRESCALE 255
> +#define TIMER_TICK_HZ  (CONFIG_CPU_FREQ_HZ / 2 / TIMER_PRESCALE)
> +
> +int timer_init(void)
> +{
> +	u32 val;
> +
> +	/* Load the timer counter register */
> +	writel(0xFFFFFFFF, &timer_base->counter);
> +
> +	/* Start the A9Timer device */
> +	val = readl(&timer_base->control);
> +	/* Enable Auto reload mode */
> +	val |= SCUTIMER_CONTROL_AUTO_RELOAD_MASK;
> +	/* Clear prescaler control bits */
> +	val &= ~SCUTIMER_CONTROL_PRESCALER_MASK;
> +	/* Set prescaler value */
> +	val |= (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT);
> +	/* Enable the decrementer */
> +	val |= SCUTIMER_CONTROL_ENABLE_MASK;
> +	writel(val, &timer_base->control);

clrsetbits_le32()

> +	/* Reset time */
> +	gd->lastinc = readl(&timer_base->counter) /
> +					(TIMER_TICK_HZ / CONFIG_SYS_HZ);
> +	gd->tbl = 0;
> +
> +	return 0;
> +}
> +
> +/*
> + * This function is derived from PowerPC code (read timebase as long
> long). + * On ARM it just returns the timer value.
> + */
> +ulong get_timer_masked(void)
> +{
> +	ulong now;
> +
> +	now = readl(&timer_base->counter) / (TIMER_TICK_HZ / CONFIG_SYS_HZ);
> +
> +	if (gd->lastinc >= now) {
> +		/* Normal mode */
> +		gd->tbl += gd->lastinc - now;
> +	} else {
> +		/* We have an overflow ... */
> +		gd->tbl += gd->lastinc + TIMER_LOAD_VAL - now;
> +	}
> +	gd->lastinc = now;
> +
> +	return gd->tbl;
> +}
> +
> +void __udelay(unsigned long usec)
> +{
> +	unsigned long long tmp;
> +	ulong tmo;
> +
> +	tmo = usec / (1000000 / CONFIG_SYS_HZ);
> +	tmp = get_ticks() + tmo; /* Get current timestamp */
> +
> +	while (get_ticks() < tmp) { /* Loop till event */
> +		 /* NOP */;
> +	}
> +}
> +
> +/* Timer without interrupts */
> +ulong get_timer(ulong base)
> +{
> +	return get_timer_masked() - base;
> +}
> +
> +/*
> + * This function is derived from PowerPC code (read timebase as long
> long). + * On ARM it just returns the timer value.
> + */
> +unsigned long long get_ticks(void)
> +{
> +	return get_timer(0);
> +}
> +
> +/*
> + * This function is derived from PowerPC code (timebase clock frequency).
> + * On ARM it returns the number of timer ticks per second.
> + */
> +ulong get_tbclk(void)
> +{
> +	return CONFIG_SYS_HZ;
> +}
Marek Vasut - Sept. 13, 2012, 9:32 a.m.
Dear Michal Simek,

> On 08/16/2012 08:30 AM, Michal Simek wrote:
> > Add timer driver.
> > 
> > Signed-off-by: Michal Simek <monstr@monstr.eu>
> > 
> > ---
> > v2: Move lowlevel_init.S from board to cpu folder
> > 
> >      Remove XPSS prefix
> >      Rename XSCUTIMER -> SCUTIMER
> > 
> > Keep timer in zynq folder till ARM custodian comments it.
> > ---
> > 
> >   arch/arm/cpu/armv7/zynq/Makefile        |   52 +++++++++++
> >   arch/arm/cpu/armv7/zynq/lowlevel_init.S |   27 ++++++
> >   arch/arm/cpu/armv7/zynq/timer.c         |  151
> >   +++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+), 0
> >   deletions(-)
> >   create mode 100644 arch/arm/cpu/armv7/zynq/Makefile
> >   create mode 100644 arch/arm/cpu/armv7/zynq/lowlevel_init.S
> >   create mode 100644 arch/arm/cpu/armv7/zynq/timer.c
> 
> We haven't got any reaction for Albert.
> Marek and Joe: Can you review this? And give me your ACK or NACK.

Oh I'll gladly torture you :-)

btw I might need a bit of a review for a ublaze stuff eventually and maybe some 
xilinx uart too, there's a large stdio patchset I have queued. Would you review 
please?

> Thanks,
> Michal

Best regards,
Marek Vasut
Michal Simek - Sept. 13, 2012, 9:36 a.m.
On 09/13/2012 11:32 AM, Marek Vasut wrote:
> Dear Michal Simek,
>
>> On 08/16/2012 08:30 AM, Michal Simek wrote:
>>> Add timer driver.
>>>
>>> Signed-off-by: Michal Simek <monstr@monstr.eu>
>>>
>>> ---
>>> v2: Move lowlevel_init.S from board to cpu folder
>>>
>>>       Remove XPSS prefix
>>>       Rename XSCUTIMER -> SCUTIMER
>>>
>>> Keep timer in zynq folder till ARM custodian comments it.
>>> ---
>>>
>>>    arch/arm/cpu/armv7/zynq/Makefile        |   52 +++++++++++
>>>    arch/arm/cpu/armv7/zynq/lowlevel_init.S |   27 ++++++
>>>    arch/arm/cpu/armv7/zynq/timer.c         |  151
>>>    +++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+), 0
>>>    deletions(-)
>>>    create mode 100644 arch/arm/cpu/armv7/zynq/Makefile
>>>    create mode 100644 arch/arm/cpu/armv7/zynq/lowlevel_init.S
>>>    create mode 100644 arch/arm/cpu/armv7/zynq/timer.c
>>
>> We haven't got any reaction for Albert.
>> Marek and Joe: Can you review this? And give me your ACK or NACK.
>
> Oh I'll gladly torture you :-)

Go ahead. :-)

>
> btw I might need a bit of a review for a ublaze stuff eventually and maybe some
> xilinx uart too, there's a large stdio patchset I have queued. Would you review
> please?

Feel free to contact me if you need any help with any xilinx stuff. Microblaze/xilinx ppc
or current arm code.
I am keen to change current code to u-boot new standard and also with dts support.

Thanks,
Michal
Michal Simek - Sept. 13, 2012, 9:52 a.m.
On 09/13/2012 11:31 AM, Marek Vasut wrote:
> Dear Michal Simek,
>
> [...]
>
>> +#include <config.h>
>> +#include <linux/linkage.h>
>> +
>> +ENTRY(lowlevel_init)
>> +        mov     pc, lr
>> +ENDPROC(lowlevel_init)
>
> inline void lowlevel_init(void) {} works as well and you don't need the assembly
> file.

:-) yes. The reason why I have done it in this way that we have some asm code
which will go to this area. That's why I have kept it in asm instead of C.

Michal
Marek Vasut - Sept. 13, 2012, 10:31 a.m.
Dear Michal Simek,

> On 09/13/2012 11:31 AM, Marek Vasut wrote:
> > Dear Michal Simek,
> > 
> > [...]
> > 
> >> +#include <config.h>
> >> +#include <linux/linkage.h>
> >> +
> >> +ENTRY(lowlevel_init)
> >> +        mov     pc, lr
> >> +ENDPROC(lowlevel_init)
> > 
> > inline void lowlevel_init(void) {} works as well and you don't need the
> > assembly file.
> :
> :-) yes. The reason why I have done it in this way that we have some asm
> :code
> 
> which will go to this area. That's why I have kept it in asm instead of C.

What code? Will the code go into lowlevel_init() ?

Best regards,
Marek Vasut
Michal Simek - Sept. 13, 2012, 11:24 a.m.
On 09/13/2012 12:31 PM, Marek Vasut wrote:
> Dear Michal Simek,
>
>> On 09/13/2012 11:31 AM, Marek Vasut wrote:
>>> Dear Michal Simek,
>>>
>>> [...]
>>>
>>>> +#include <config.h>
>>>> +#include <linux/linkage.h>
>>>> +
>>>> +ENTRY(lowlevel_init)
>>>> +        mov     pc, lr
>>>> +ENDPROC(lowlevel_init)
>>>
>>> inline void lowlevel_init(void) {} works as well and you don't need the
>>> assembly file.
>> :
>> :-) yes. The reason why I have done it in this way that we have some asm
>> :code
>>
>> which will go to this area. That's why I have kept it in asm instead of C.
>
> What code? Will the code go into lowlevel_init() ?

For example SLCR locking if is not locked from the first stage bootloader.
Also if necessary OCM and DDR remap, FPGA reset can be also there
based on configuration.

Thanks,
Michal
Marek Vasut - Sept. 13, 2012, 12:32 p.m.
Dear Michal Simek,

> On 09/13/2012 12:31 PM, Marek Vasut wrote:
> > Dear Michal Simek,
> > 
> >> On 09/13/2012 11:31 AM, Marek Vasut wrote:
> >>> Dear Michal Simek,
> >>> 
> >>> [...]
> >>> 
> >>>> +#include <config.h>
> >>>> +#include <linux/linkage.h>
> >>>> +
> >>>> +ENTRY(lowlevel_init)
> >>>> +        mov     pc, lr
> >>>> +ENDPROC(lowlevel_init)
> >>> 
> >>> inline void lowlevel_init(void) {} works as well and you don't need the
> >>> assembly file.
> >>> 
> >> :-) yes. The reason why I have done it in this way that we have some asm
> >> :code
> >> 
> >> which will go to this area. That's why I have kept it in asm instead of
> >> C.
> > 
> > What code? Will the code go into lowlevel_init() ?
> 
> For example SLCR locking if is not locked from the first stage bootloader.
> Also if necessary OCM and DDR remap, FPGA reset can be also there
> based on configuration.

Can it not be in C code ?

> Thanks,
> Michal

Best regards,
Marek Vasut
Michal Simek - Sept. 13, 2012, 12:52 p.m.
On 09/13/2012 02:32 PM, Marek Vasut wrote:
> Dear Michal Simek,
>
>> On 09/13/2012 12:31 PM, Marek Vasut wrote:
>>> Dear Michal Simek,
>>>
>>>> On 09/13/2012 11:31 AM, Marek Vasut wrote:
>>>>> Dear Michal Simek,
>>>>>
>>>>> [...]
>>>>>
>>>>>> +#include <config.h>
>>>>>> +#include <linux/linkage.h>
>>>>>> +
>>>>>> +ENTRY(lowlevel_init)
>>>>>> +        mov     pc, lr
>>>>>> +ENDPROC(lowlevel_init)
>>>>>
>>>>> inline void lowlevel_init(void) {} works as well and you don't need the
>>>>> assembly file.
>>>>>
>>>> :-) yes. The reason why I have done it in this way that we have some asm
>>>> :code
>>>>
>>>> which will go to this area. That's why I have kept it in asm instead of
>>>> C.
>>>
>>> What code? Will the code go into lowlevel_init() ?
>>
>> For example SLCR locking if is not locked from the first stage bootloader.
>> Also if necessary OCM and DDR remap, FPGA reset can be also there
>> based on configuration.
>
> Can it not be in C code ?

Probably can be in C code. I have no problem to move it to C.

Cheers,
Michal
Marek Vasut - Sept. 13, 2012, 1:01 p.m.
Dear Michal Simek,

> On 09/13/2012 02:32 PM, Marek Vasut wrote:
> > Dear Michal Simek,
> > 
> >> On 09/13/2012 12:31 PM, Marek Vasut wrote:
> >>> Dear Michal Simek,
> >>> 
> >>>> On 09/13/2012 11:31 AM, Marek Vasut wrote:
> >>>>> Dear Michal Simek,
> >>>>> 
> >>>>> [...]
> >>>>> 
> >>>>>> +#include <config.h>
> >>>>>> +#include <linux/linkage.h>
> >>>>>> +
> >>>>>> +ENTRY(lowlevel_init)
> >>>>>> +        mov     pc, lr
> >>>>>> +ENDPROC(lowlevel_init)
> >>>>> 
> >>>>> inline void lowlevel_init(void) {} works as well and you don't need
> >>>>> the assembly file.
> >>>>> 
> >>>> :-) yes. The reason why I have done it in this way that we have some
> >>>> :asm code
> >>>> 
> >>>> which will go to this area. That's why I have kept it in asm instead
> >>>> of C.
> >>> 
> >>> What code? Will the code go into lowlevel_init() ?
> >> 
> >> For example SLCR locking if is not locked from the first stage
> >> bootloader. Also if necessary OCM and DDR remap, FPGA reset can be also
> >> there based on configuration.
> > 
> > Can it not be in C code ?
> 
> Probably can be in C code. I have no problem to move it to C.

Please do, cut the assembly to minimum.

> Cheers,
> Michal

Best regards,
Marek Vasut

Patch

diff --git a/arch/arm/cpu/armv7/zynq/Makefile b/arch/arm/cpu/armv7/zynq/Makefile
new file mode 100644
index 0000000..1d2d7e1
--- /dev/null
+++ b/arch/arm/cpu/armv7/zynq/Makefile
@@ -0,0 +1,52 @@ 
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2008
+# Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+SOBJS-y	:= lowlevel_init.o
+COBJS-y	:= timer.o
+
+SOBJS	:= $(SOBJS-y)
+COBJS	:= $(COBJS-y)
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB): $(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/armv7/zynq/lowlevel_init.S b/arch/arm/cpu/armv7/zynq/lowlevel_init.S
new file mode 100644
index 0000000..642eb18
--- /dev/null
+++ b/arch/arm/cpu/armv7/zynq/lowlevel_init.S
@@ -0,0 +1,27 @@ 
+/*
+ * (C) Copyright 2012 Michal Simek <monstr@monstr.eu>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#include <linux/linkage.h>
+
+ENTRY(lowlevel_init)
+        mov     pc, lr
+ENDPROC(lowlevel_init)
diff --git a/arch/arm/cpu/armv7/zynq/timer.c b/arch/arm/cpu/armv7/zynq/timer.c
new file mode 100644
index 0000000..0252220
--- /dev/null
+++ b/arch/arm/cpu/armv7/zynq/timer.c
@@ -0,0 +1,151 @@ 
+/*
+ * Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
+ *
+ * (C) Copyright 2008
+ * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
+ *
+ * (C) Copyright 2004
+ * Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
+ *
+ * (C) Copyright 2002-2004
+ * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
+ *
+ * (C) Copyright 2003
+ * Texas Instruments <www.ti.com>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <div64.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct scu_timer {
+	u32 load; /* Timer Load Register */
+	u32 counter; /* Timer Counter Register */
+	u32 control; /* Timer Control Register */
+};
+
+static struct scu_timer *timer_base = CONFIG_SCUTIMER_BASEADDR;
+
+#define SCUTIMER_CONTROL_PRESCALER_MASK	0x0000FF00 /* Prescaler */
+#define SCUTIMER_CONTROL_PRESCALER_SHIFT	8
+#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK	0x00000002 /* Auto-reload */
+#define SCUTIMER_CONTROL_ENABLE_MASK		0x00000001 /* Timer enable */
+
+#define TIMER_LOAD_VAL 0xFFFFFFFF
+#define TIMER_PRESCALE 255
+#define TIMER_TICK_HZ  (CONFIG_CPU_FREQ_HZ / 2 / TIMER_PRESCALE)
+
+int timer_init(void)
+{
+	u32 val;
+
+	/* Load the timer counter register */
+	writel(0xFFFFFFFF, &timer_base->counter);
+
+	/* Start the A9Timer device */
+	val = readl(&timer_base->control);
+	/* Enable Auto reload mode */
+	val |= SCUTIMER_CONTROL_AUTO_RELOAD_MASK;
+	/* Clear prescaler control bits */
+	val &= ~SCUTIMER_CONTROL_PRESCALER_MASK;
+	/* Set prescaler value */
+	val |= (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT);
+	/* Enable the decrementer */
+	val |= SCUTIMER_CONTROL_ENABLE_MASK;
+	writel(val, &timer_base->control);
+
+	/* Reset time */
+	gd->lastinc = readl(&timer_base->counter) /
+					(TIMER_TICK_HZ / CONFIG_SYS_HZ);
+	gd->tbl = 0;
+
+	return 0;
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+ulong get_timer_masked(void)
+{
+	ulong now;
+
+	now = readl(&timer_base->counter) / (TIMER_TICK_HZ / CONFIG_SYS_HZ);
+
+	if (gd->lastinc >= now) {
+		/* Normal mode */
+		gd->tbl += gd->lastinc - now;
+	} else {
+		/* We have an overflow ... */
+		gd->tbl += gd->lastinc + TIMER_LOAD_VAL - now;
+	}
+	gd->lastinc = now;
+
+	return gd->tbl;
+}
+
+void __udelay(unsigned long usec)
+{
+	unsigned long long tmp;
+	ulong tmo;
+
+	tmo = usec / (1000000 / CONFIG_SYS_HZ);
+	tmp = get_ticks() + tmo; /* Get current timestamp */
+
+	while (get_ticks() < tmp) { /* Loop till event */
+		 /* NOP */;
+	}
+}
+
+/* Timer without interrupts */
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}