diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 77cc373..5de417c 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk
 LIB	= $(obj)lib$(CPU).o

 src-y  := cpu.o interrupts.o
+src-$(CONFIG_FTTMR010)    += fttmr010.o

 START	= start.o
 COBJS	= $(src-y)
diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c
new file mode 100644
index 0000000..39e170a
--- /dev/null
+++ b/arch/arm/cpu/faraday/fttmr010.c
@@ -0,0 +1,160 @@
+/*
+ * arch/arm/cpu/faraday/fttmr010.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/fttmr010.h>
+
+static ulong ticks;				/* U-Boot ticks since startup */
+static ulong sclk  = 66000000;	/* source clock (66MHz by default) */
+static struct fttmr010 __iomem *regs = (void __iomem *)CONFIG_TIMER_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	/* Disable Timer2 */
+	clrbits_le32(&regs->cr, FTTMR010_TM2_CRMASK);
+	/* Disable Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_state);
+
+	/* Configure Timer2 */
+	writel((sclk / 1000000) * usec, &regs->timer2_counter);
+	writel(0, &regs->timer2_load);
+	writel(0, &regs->timer2_match1);
+	writel(0, &regs->timer2_match2);
+
+	/* Enable Timer2 */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE);
+
+	/* Wait until timeout */
+	while (!(readl(&regs->interrupt_state) & FTTMR010_TM2_ISRMASK))
+		;
+}
+
+#ifdef CONFIG_USE_IRQ
+
+void timer_interrupt(struct pt_regs *ctx)
+{
+	++ticks;
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+}
+
+#endif    /* #ifdef CONFIG_USE_IRQ */
+
+void reset_timer_masked(void)
+{
+	/* Disable Timer1 */
+	clrbits_le32(&regs->cr, FTTMR010_TM1_CRMASK);
+	/* Disable Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt init */
+	irq_set_trigger(CONFIG_TIMER_IRQ, 1, 0);
+	irq_install_handler(CONFIG_TIMER_IRQ, (void *)timer_interrupt, NULL);
+	irq_enable(CONFIG_TIMER_IRQ);
+#endif
+
+	/* timer1 setup */
+#ifdef CONFIG_USE_IRQ
+	/* setup a 1 sec periodic timer */
+	writel(sclk / CONFIG_SYS_HZ, &regs->timer1_counter);
+	writel(sclk / CONFIG_SYS_HZ, &regs->timer1_load);
+#else
+	/* setup a 30 sec one-shot timer */
+	writel(30 * sclk, &regs->timer1_counter);
+	writel(0, &regs->timer1_load);
+#endif
+	writel(0, &regs->timer1_match1);
+	writel(0, &regs->timer1_match2);
+
+	/* start timer1 with overflow interrupt enabled */
+	writel(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2,
+		&regs->interrupt_mask);
+	setbits_le32(&regs->cr,
+		FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE);
+}
+
+ulong get_timer_masked(void)
+{
+#ifdef CONFIG_USE_IRQ
+	return ticks;
+#else
+	ulong s = sclk / CONFIG_SYS_HZ;
+	ulong t = ((30 * sclk) - readl(&regs->timer1_counter)) / s;
+
+	return ticks + t;
+#endif
+}
+
+int timer_init(void)
+{
+	ticks = 0;
+#ifdef CONFIG_TIMER_FREQ
+	sclk  = CONFIG_TIMER_FREQ;
+#else
+	sclk  = clk_get_rate("APB");
+#endif
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt is not yet initialized here */
+#else
+	reset_timer_masked();
+#endif
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+#ifndef CONFIG_USE_IRQ
+	if (!readl(&regs->timer1_counter)) {
+		ticks += 30 * CONFIG_SYS_HZ;
+		reset_timer_masked();
+	}
+#endif
+	return get_timer_masked() - base;
+}
+
+void set_timer(ulong t)
+{
+	ticks = t;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * 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;
+}
diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h
index 72abcb3..ef10f31 100644
--- a/include/faraday/fttmr010.h
+++ b/include/faraday/fttmr010.h
@@ -57,6 +57,16 @@ struct fttmr010 {
 #define FTTMR010_TM1_CLOCK	(1 << 1)
 #define FTTMR010_TM1_ENABLE	(1 << 0)

+#define FTTMR010_TM1_CRMASK \
+	(FTTMR010_TM1_UPDOWN | FTTMR010_TM1_OFENABLE \
+	| FTTMR010_TM1_CLOCK | FTTMR010_TM1_ENABLE)
+#define FTTMR010_TM2_CRMASK \
+	(FTTMR010_TM2_UPDOWN | FTTMR010_TM2_OFENABLE \
+	| FTTMR010_TM2_CLOCK | FTTMR010_TM2_ENABLE)
+#define FTTMR010_TM3_CRMASK \
+	(FTTMR010_TM3_UPDOWN | FTTMR010_TM3_OFENABLE \
+	| FTTMR010_TM3_CLOCK | FTTMR010_TM3_ENABLE)
+
 /*
  * Timer Interrupt State & Mask Registers
  */
@@ -70,4 +80,11 @@ struct fttmr010 {
 #define FTTMR010_TM1_MATCH2	(1 << 1)
 #define FTTMR010_TM1_MATCH1	(1 << 0)

+#define FTTMR010_TM1_ISRMASK \
+	(FTTMR010_TM1_OVERFLOW | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_MATCH1)
+#define FTTMR010_TM2_ISRMASK \
+	(FTTMR010_TM2_OVERFLOW | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_MATCH1)
+#define FTTMR010_TM3_ISRMASK \
+	(FTTMR010_TM3_OVERFLOW | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_MATCH1)
+
 #endif	/* __FTTMR010_H */
