i.MXC family: Adding timer support
authorJuergen Beisert <j.beisert@pengutronix.de>
Sat, 5 Jul 2008 08:02:50 +0000 (10:02 +0200)
committerRobert Schwebel <r.schwebel@pengutronix.de>
Sat, 5 Jul 2008 08:02:50 +0000 (10:02 +0200)
This patch adds timer support for the i.MX machine family. This code can
be used on the following machs:

 - i.MX1 (tested)
 - i.MX2 (i.MX21 (to be tested), i.MX27 (tested))
 - i.MX3 (i.MX31 (tested))

TODO: It seems impossible to build a kernel for more than one CPU because the
timer do not follow the platform device rules. So it does only work if
timer 1 can be accessed on all CPUs at the same address.

Signed-off-by: Juergen Beisert <j.beisert@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
arch/arm/Kconfig
arch/arm/mach-mx3/Makefile
arch/arm/mach-mx3/mx31ads.c
arch/arm/mach-mx3/time.c [deleted file]
arch/arm/plat-mxc/Makefile
arch/arm/plat-mxc/time.c [new file with mode: 0644]
include/asm-arm/arch-mxc/common.h
include/asm-arm/arch-mxc/mxc.h
include/asm-arm/arch-mxc/mxc_timer.h [new file with mode: 0644]

index 5c8c1a8..8a9a84c 100644 (file)
@@ -367,6 +367,8 @@ config ARCH_NS9XXX
 
 config ARCH_MXC
        bool "Freescale MXC/iMX-based"
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
        select ARCH_MTD_XIP
        select GENERIC_GPIO
        select HAVE_GPIO_LIB
index 68f062b..562c75d 100644 (file)
@@ -4,5 +4,5 @@
 
 # Object file lists.
 
-obj-y                  := mm.o time.o clock.o devices.o iomux.o
+obj-y                  := mm.o clock.o devices.o iomux.o
 obj-$(CONFIG_MACH_MX31ADS)     += mx31ads.o
index 5addbb7..eba3e0c 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
 #include <asm/memory.h>
 #include <asm/mach/map.h>
 #include <asm/arch/common.h>
@@ -127,6 +128,16 @@ static void __init mxc_board_init(void)
        mxc_init_extuart();
 }
 
+static void __init mx31ads_timer_init(void)
+{
+       mxc_clocks_init(26000000);
+       mxc_timer_init("ipg_clk.0");
+}
+
+struct sys_timer mx31ads_timer = {
+       .init   = mx31ads_timer_init,
+};
+
 /*
  * The following uses standard kernel macros defined in arch.h in order to
  * initialize __mach_desc_MX31ADS data structure.
@@ -139,5 +150,5 @@ MACHINE_START(MX31ADS, "Freescale MX31ADS")
        .map_io         = mx31ads_map_io,
        .init_irq       = mxc_init_irq,
        .init_machine   = mxc_board_init,
-       .timer          = &mxc_timer,
+       .timer          = &mx31ads_timer,
 MACHINE_END
diff --git a/arch/arm/mach-mx3/time.c b/arch/arm/mach-mx3/time.c
deleted file mode 100644 (file)
index fb565c9..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * System Timer Interrupt reconfigured to run in free-run mode.
- * Author: Vitaly Wool
- * Copyright 2004 MontaVista Software Inc.
- * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*!
- * @file time.c
- * @brief This file contains OS tick and wdog timer implementations.
- *
- * This file contains OS tick and wdog timer implementations.
- *
- * @ingroup Timers
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <asm/hardware.h>
-#include <asm/mach/time.h>
-#include <asm/io.h>
-#include <asm/arch/common.h>
-
-/*!
- * This is the timer interrupt service routine to do required tasks.
- * It also services the WDOG timer at the frequency of twice per WDOG
- * timeout value. For example, if the WDOG's timeout value is 4 (2
- * seconds since the WDOG runs at 0.5Hz), it will be serviced once
- * every 2/2=1 second.
- *
- * @param  irq          GPT interrupt source number (not used)
- * @param  dev_id       this parameter is not used
- * @return always returns \b IRQ_HANDLED as defined in
- *         include/linux/interrupt.h.
- */
-static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
-{
-       unsigned int next_match;
-
-       if (__raw_readl(MXC_GPT_GPTSR) & GPTSR_OF1) {
-               do {
-                       timer_tick();
-                       next_match = __raw_readl(MXC_GPT_GPTOCR1) + LATCH;
-                       __raw_writel(GPTSR_OF1, MXC_GPT_GPTSR);
-                       __raw_writel(next_match, MXC_GPT_GPTOCR1);
-               } while ((signed long)(next_match -
-                                      __raw_readl(MXC_GPT_GPTCNT)) <= 0);
-       }
-
-       return IRQ_HANDLED;
-}
-
-/*!
- * This function is used to obtain the number of microseconds since the last
- * timer interrupt. Note that interrupts is disabled by do_gettimeofday().
- *
- * @return the number of microseconds since the last timer interrupt.
- */
-static unsigned long mxc_gettimeoffset(void)
-{
-       unsigned long ticks_to_match, elapsed, usec, tick_usec, i;
-
-       /* Get ticks before next timer match */
-       ticks_to_match =
-           __raw_readl(MXC_GPT_GPTOCR1) - __raw_readl(MXC_GPT_GPTCNT);
-
-       /* We need elapsed ticks since last match */
-       elapsed = LATCH - ticks_to_match;
-
-       /* Now convert them to usec */
-       /* Insure no overflow when calculating the usec below */
-       for (i = 1, tick_usec = tick_nsec / 1000;; i *= 2) {
-               tick_usec /= i;
-               if ((0xFFFFFFFF / tick_usec) > elapsed)
-                       break;
-       }
-       usec = (unsigned long)(elapsed * tick_usec) / (LATCH / i);
-
-       return usec;
-}
-
-/*!
- * The OS tick timer interrupt structure.
- */
-static struct irqaction timer_irq = {
-       .name = "MXC Timer Tick",
-       .flags = IRQF_DISABLED | IRQF_TIMER,
-       .handler = mxc_timer_interrupt
-};
-
-/*!
- * This function is used to initialize the GPT to produce an interrupt
- * based on HZ.  It is called by start_kernel() during system startup.
- */
-void __init mxc_init_time(void)
-{
-       u32 reg, v;
-       reg = __raw_readl(MXC_GPT_GPTCR);
-       reg &= ~GPTCR_ENABLE;
-       __raw_writel(reg, MXC_GPT_GPTCR);
-       reg |= GPTCR_SWR;
-       __raw_writel(reg, MXC_GPT_GPTCR);
-
-       while ((__raw_readl(MXC_GPT_GPTCR) & GPTCR_SWR) != 0)
-               cpu_relax();
-
-       reg = GPTCR_FRR | GPTCR_CLKSRC_HIGHFREQ;
-       __raw_writel(reg, MXC_GPT_GPTCR);
-
-       /* TODO: get timer rate from clk driver */
-       v = 66500000;
-
-       __raw_writel((v / CLOCK_TICK_RATE) - 1, MXC_GPT_GPTPR);
-
-       if ((v % CLOCK_TICK_RATE) != 0) {
-               pr_info("\nWARNING: Can't generate CLOCK_TICK_RATE at %d Hz\n",
-                       CLOCK_TICK_RATE);
-       }
-       pr_info("Actual CLOCK_TICK_RATE is %d Hz\n",
-               v / ((__raw_readl(MXC_GPT_GPTPR) & 0xFFF) + 1));
-
-       reg = __raw_readl(MXC_GPT_GPTCNT);
-       reg += LATCH;
-       __raw_writel(reg, MXC_GPT_GPTOCR1);
-
-       setup_irq(MXC_INT_GPT, &timer_irq);
-
-       reg = __raw_readl(MXC_GPT_GPTCR);
-       reg =
-           GPTCR_FRR | GPTCR_CLKSRC_HIGHFREQ | GPTCR_STOPEN | GPTCR_DOZEN |
-           GPTCR_WAITEN | GPTCR_ENMOD | GPTCR_ENABLE;
-       __raw_writel(reg, MXC_GPT_GPTCR);
-
-       __raw_writel(GPTIR_OF1IE, MXC_GPT_GPTIR);
-}
-
-struct sys_timer mxc_timer = {
-       .init = mxc_init_time,
-       .offset = mxc_gettimeoffset,
-};
index 66272a6..e3cc25c 100644 (file)
@@ -3,4 +3,4 @@
 #
 
 # Common support
-obj-y := irq.o clock.o gpio.o
+obj-y := irq.o clock.o gpio.o time.o
diff --git a/arch/arm/plat-mxc/time.c b/arch/arm/plat-mxc/time.c
new file mode 100644 (file)
index 0000000..3bf8634
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ *  linux/arch/arm/plat-mxc/time.c
+ *
+ *  Copyright (C) 2000-2001 Deep Blue Solutions
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *  Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
+ *  Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+
+#include <asm/hardware.h>
+#include <asm/mach/time.h>
+#include <asm/arch/common.h>
+#include <asm/arch/mxc_timer.h>
+
+static struct clock_event_device clockevent_mxc;
+static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
+
+/* clock source for the timer */
+static struct clk *timer_clk;
+
+/* clock source */
+
+static cycle_t mxc_get_cycles(void)
+{
+       return __raw_readl(TIMER_BASE + MXC_TCN);
+}
+
+static struct clocksource clocksource_mxc = {
+       .name           = "mxc_timer1",
+       .rating         = 200,
+       .read           = mxc_get_cycles,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .shift          = 20,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init mxc_clocksource_init(void)
+{
+       unsigned int clock;
+
+       clock = clk_get_rate(timer_clk);
+
+       clocksource_mxc.mult = clocksource_hz2mult(clock,
+                                       clocksource_mxc.shift);
+       clocksource_register(&clocksource_mxc);
+
+       return 0;
+}
+
+/* clock event */
+
+static int mxc_set_next_event(unsigned long evt,
+                             struct clock_event_device *unused)
+{
+       unsigned long tcmp;
+
+       tcmp = __raw_readl(TIMER_BASE + MXC_TCN) + evt;
+       __raw_writel(tcmp, TIMER_BASE + MXC_TCMP);
+
+       return (int)(tcmp - __raw_readl(TIMER_BASE + MXC_TCN)) < 0 ?
+                               -ETIME : 0;
+}
+
+#ifdef DEBUG
+static const char *clock_event_mode_label[] = {
+       [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
+       [CLOCK_EVT_MODE_ONESHOT]  = "CLOCK_EVT_MODE_ONESHOT",
+       [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
+       [CLOCK_EVT_MODE_UNUSED]   = "CLOCK_EVT_MODE_UNUSED"
+};
+#endif /* DEBUG */
+
+static void mxc_set_mode(enum clock_event_mode mode,
+                               struct clock_event_device *evt)
+{
+       unsigned long flags;
+
+       /*
+        * The timer interrupt generation is disabled at least
+        * for enough time to call mxc_set_next_event()
+        */
+       local_irq_save(flags);
+
+       /* Disable interrupt in GPT module */
+       gpt_irq_disable();
+
+       if (mode != clockevent_mode) {
+               /* Set event time into far-far future */
+               __raw_writel(__raw_readl(TIMER_BASE + MXC_TCN) - 3,
+                               TIMER_BASE + MXC_TCMP);
+               /* Clear pending interrupt */
+               gpt_irq_acknowledge();
+       }
+
+#ifdef DEBUG
+       printk(KERN_INFO "mxc_set_mode: changing mode from %s to %s\n",
+               clock_event_mode_label[clockevent_mode],
+               clock_event_mode_label[mode]);
+#endif /* DEBUG */
+
+       /* Remember timer mode */
+       clockevent_mode = mode;
+       local_irq_restore(flags);
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               printk(KERN_ERR"mxc_set_mode: Periodic mode is not "
+                               "supported for i.MX\n");
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+       /*
+        * Do not put overhead of interrupt enable/disable into
+        * mxc_set_next_event(), the core has about 4 minutes
+        * to call mxc_set_next_event() or shutdown clock after
+        * mode switching
+        */
+               local_irq_save(flags);
+               gpt_irq_enable();
+               local_irq_restore(flags);
+               break;
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_RESUME:
+               /* Left event sources disabled, no more interrupts appear */
+               break;
+       }
+}
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = &clockevent_mxc;
+       uint32_t tstat;
+
+       tstat = __raw_readl(TIMER_BASE + MXC_TSTAT);
+
+       gpt_irq_acknowledge();
+
+       evt->event_handler(evt);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction mxc_timer_irq = {
+       .name           = "i.MX Timer Tick",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .handler        = mxc_timer_interrupt,
+};
+
+static struct clock_event_device clockevent_mxc = {
+       .name           = "mxc_timer1",
+       .features       = CLOCK_EVT_FEAT_ONESHOT,
+       .shift          = 32,
+       .set_mode       = mxc_set_mode,
+       .set_next_event = mxc_set_next_event,
+       .rating         = 200,
+};
+
+static int __init mxc_clockevent_init(void)
+{
+       unsigned int clock;
+
+       clock = clk_get_rate(timer_clk);
+
+       clockevent_mxc.mult = div_sc(clock, NSEC_PER_SEC,
+                                       clockevent_mxc.shift);
+       clockevent_mxc.max_delta_ns =
+                       clockevent_delta2ns(0xfffffffe, &clockevent_mxc);
+       clockevent_mxc.min_delta_ns =
+                       clockevent_delta2ns(0xff, &clockevent_mxc);
+
+       clockevent_mxc.cpumask = cpumask_of_cpu(0);
+
+       clockevents_register_device(&clockevent_mxc);
+
+       return 0;
+}
+
+void __init mxc_timer_init(const char *clk_timer)
+{
+       timer_clk = clk_get(NULL, clk_timer);
+       if (!timer_clk) {
+               printk(KERN_ERR"Cannot determine timer clock. Giving up.\n");
+               return;
+       }
+
+       clk_enable(timer_clk);
+
+       /*
+        * Initialise to a known state (all timers off, and timing reset)
+        */
+       __raw_writel(0, TIMER_BASE + MXC_TCTL);
+       __raw_writel(0, TIMER_BASE + MXC_TPRER); /* see datasheet note */
+
+       __raw_writel(TCTL_FRR | /* free running */
+                    TCTL_VAL | /* set clocksource and arch specific bits */
+                    TCTL_TEN,  /* start the timer */
+                    TIMER_BASE + MXC_TCTL);
+
+       /* init and register the timer to the framework */
+       mxc_clocksource_init();
+       mxc_clockevent_init();
+
+       /* Make irqs happen */
+       setup_irq(TIMER_INTERRUPT, &mxc_timer_irq);
+}
+
index 8774783..a6d2e24 100644 (file)
 #ifndef __ASM_ARCH_MXC_COMMON_H__
 #define __ASM_ARCH_MXC_COMMON_H__
 
-struct sys_timer;
-
 extern void mxc_map_io(void);
 extern void mxc_init_irq(void);
-extern struct sys_timer mxc_timer;
+extern void mxc_timer_init(const char *clk_timer);
 extern int mxc_clocks_init(unsigned long fref);
 extern int mxc_register_gpios(void);
 
index 146d3f6..1df4e2f 100644 (file)
@@ -1,11 +1,20 @@
 /*
  * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
  */
 
 #ifndef __ASM_ARCH_MXC_H__
 # define cpu_is_mx31() (0)
 #endif
 
-/*
- *****************************************
- * GPT  Register definitions             *
- *****************************************
- */
-#define MXC_GPT_GPTCR          IO_ADDRESS(GPT1_BASE_ADDR + 0x00)
-#define MXC_GPT_GPTPR          IO_ADDRESS(GPT1_BASE_ADDR + 0x04)
-#define MXC_GPT_GPTSR          IO_ADDRESS(GPT1_BASE_ADDR + 0x08)
-#define MXC_GPT_GPTIR          IO_ADDRESS(GPT1_BASE_ADDR + 0x0C)
-#define MXC_GPT_GPTOCR1                IO_ADDRESS(GPT1_BASE_ADDR + 0x10)
-#define MXC_GPT_GPTOCR2                IO_ADDRESS(GPT1_BASE_ADDR + 0x14)
-#define MXC_GPT_GPTOCR3                IO_ADDRESS(GPT1_BASE_ADDR + 0x18)
-#define MXC_GPT_GPTICR1                IO_ADDRESS(GPT1_BASE_ADDR + 0x1C)
-#define MXC_GPT_GPTICR2                IO_ADDRESS(GPT1_BASE_ADDR + 0x20)
-#define MXC_GPT_GPTCNT         IO_ADDRESS(GPT1_BASE_ADDR + 0x24)
-
-/* GPT Control register bit definitions */
-#define GPTCR_FO3                      (1 << 31)
-#define GPTCR_FO2                      (1 << 30)
-#define GPTCR_FO1                      (1 << 29)
-
-#define GPTCR_OM3_SHIFT                        26
-#define GPTCR_OM3_MASK                 (7 << GPTCR_OM3_SHIFT)
-#define GPTCR_OM3_DISCONNECTED         (0 << GPTCR_OM3_SHIFT)
-#define GPTCR_OM3_TOGGLE               (1 << GPTCR_OM3_SHIFT)
-#define GPTCR_OM3_CLEAR                        (2 << GPTCR_OM3_SHIFT)
-#define GPTCR_OM3_SET                  (3 << GPTCR_OM3_SHIFT)
-#define GPTCR_OM3_GENERATE_LOW         (7 << GPTCR_OM3_SHIFT)
-
-#define GPTCR_OM2_SHIFT                        23
-#define GPTCR_OM2_MASK                 (7 << GPTCR_OM2_SHIFT)
-#define GPTCR_OM2_DISCONNECTED         (0 << GPTCR_OM2_SHIFT)
-#define GPTCR_OM2_TOGGLE               (1 << GPTCR_OM2_SHIFT)
-#define GPTCR_OM2_CLEAR                        (2 << GPTCR_OM2_SHIFT)
-#define GPTCR_OM2_SET                  (3 << GPTCR_OM2_SHIFT)
-#define GPTCR_OM2_GENERATE_LOW         (7 << GPTCR_OM2_SHIFT)
-
-#define GPTCR_OM1_SHIFT                        20
-#define GPTCR_OM1_MASK                 (7 << GPTCR_OM1_SHIFT)
-#define GPTCR_OM1_DISCONNECTED         (0 << GPTCR_OM1_SHIFT)
-#define GPTCR_OM1_TOGGLE               (1 << GPTCR_OM1_SHIFT)
-#define GPTCR_OM1_CLEAR                        (2 << GPTCR_OM1_SHIFT)
-#define GPTCR_OM1_SET                  (3 << GPTCR_OM1_SHIFT)
-#define GPTCR_OM1_GENERATE_LOW         (7 << GPTCR_OM1_SHIFT)
-
-#define GPTCR_IM2_SHIFT                        18
-#define GPTCR_IM2_MASK                 (3 << GPTCR_IM2_SHIFT)
-#define GPTCR_IM2_CAPTURE_DISABLE      (0 << GPTCR_IM2_SHIFT)
-#define GPTCR_IM2_CAPTURE_RISING       (1 << GPTCR_IM2_SHIFT)
-#define GPTCR_IM2_CAPTURE_FALLING      (2 << GPTCR_IM2_SHIFT)
-#define GPTCR_IM2_CAPTURE_BOTH         (3 << GPTCR_IM2_SHIFT)
-
-#define GPTCR_IM1_SHIFT                        16
-#define GPTCR_IM1_MASK                 (3 << GPTCR_IM1_SHIFT)
-#define GPTCR_IM1_CAPTURE_DISABLE      (0 << GPTCR_IM1_SHIFT)
-#define GPTCR_IM1_CAPTURE_RISING       (1 << GPTCR_IM1_SHIFT)
-#define GPTCR_IM1_CAPTURE_FALLING      (2 << GPTCR_IM1_SHIFT)
-#define GPTCR_IM1_CAPTURE_BOTH         (3 << GPTCR_IM1_SHIFT)
-
-#define GPTCR_SWR                      (1 << 15)
-#define GPTCR_FRR                      (1 << 9)
-
-#define GPTCR_CLKSRC_SHIFT             6
-#define GPTCR_CLKSRC_MASK              (7 << GPTCR_CLKSRC_SHIFT)
-#define GPTCR_CLKSRC_NOCLOCK           (0 << GPTCR_CLKSRC_SHIFT)
-#define GPTCR_CLKSRC_HIGHFREQ          (2 << GPTCR_CLKSRC_SHIFT)
-#define GPTCR_CLKSRC_CLKIN             (3 << GPTCR_CLKSRC_SHIFT)
-#define GPTCR_CLKSRC_CLK32K            (7 << GPTCR_CLKSRC_SHIFT)
-
-#define GPTCR_STOPEN                   (1 << 5)
-#define GPTCR_DOZEN                    (1 << 4)
-#define GPTCR_WAITEN                   (1 << 3)
-#define GPTCR_DBGEN                    (1 << 2)
-
-#define GPTCR_ENMOD                    (1 << 1)
-#define GPTCR_ENABLE                   (1 << 0)
-
-#define GPTSR_OF1                      (1 << 0)
-#define GPTSR_OF2                      (1 << 1)
-#define GPTSR_OF3                      (1 << 2)
-#define GPTSR_IF1                      (1 << 3)
-#define GPTSR_IF2                      (1 << 4)
-#define GPTSR_ROV                      (1 << 5)
-
-#define GPTIR_OF1IE                    GPTSR_OF1
-#define GPTIR_OF2IE                    GPTSR_OF2
-#define GPTIR_OF3IE                    GPTSR_OF3
-#define GPTIR_IF1IE                    GPTSR_IF1
-#define GPTIR_IF2IE                    GPTSR_IF2
-#define GPTIR_ROVIE                    GPTSR_ROV
-
 /*
  *****************************************
  * AVIC Registers                        *
diff --git a/include/asm-arm/arch-mxc/mxc_timer.h b/include/asm-arm/arch-mxc/mxc_timer.h
new file mode 100644 (file)
index 0000000..6cb11f4
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * mxc_timer.h
+ *
+ * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
+ *
+ * Platform independent (i.MX1, i.MX2, i.MX3) definition for timer handling.
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __PLAT_MXC_TIMER_H
+#define __PLAT_MXC_TIMER_H
+
+#include <linux/clk.h>
+#include <asm/hardware.h>
+
+#ifdef CONFIG_ARCH_IMX
+#define TIMER_BASE             IO_ADDRESS(TIM1_BASE_ADDR)
+#define TIMER_INTERRUPT                TIM1_INT
+
+#define TCTL_VAL               TCTL_CLK_PCLK1
+#define TCTL_IRQEN             (1<<4)
+#define TCTL_FRR               (1<<8)
+#define TCTL_CLK_PCLK1         (1<<1)
+#define TCTL_CLK_PCLK1_4       (2<<1)
+#define TCTL_CLK_TIN           (3<<1)
+#define TCTL_CLK_32            (4<<1)
+
+#define MXC_TCTL   0x00
+#define MXC_TPRER  0x04
+#define MXC_TCMP   0x08
+#define MXC_TCR    0x0c
+#define MXC_TCN    0x10
+#define MXC_TSTAT  0x14
+#define TSTAT_CAPT             (1<<1)
+#define TSTAT_COMP             (1<<0)
+
+static inline void gpt_irq_disable(void)
+{
+       unsigned int tmp;
+
+       tmp = __raw_readl(TIMER_BASE + MXC_TCTL);
+       __raw_writel(tmp & ~TCTL_IRQEN, TIMER_BASE + MXC_TCTL);
+}
+
+static inline void gpt_irq_enable(void)
+{
+       __raw_writel(__raw_readl(TIMER_BASE + MXC_TCTL) | TCTL_IRQEN,
+                               TIMER_BASE + MXC_TCTL);
+}
+
+static void gpt_irq_acknowledge(void)
+{
+       __raw_writel(0, TIMER_BASE + MXC_TSTAT);
+}
+#endif /* CONFIG_ARCH_IMX */
+
+#ifdef CONFIG_ARCH_MX2
+#define TIMER_BASE             IO_ADDRESS(GPT1_BASE_ADDR)
+#define TIMER_INTERRUPT                MXC_INT_GPT1
+
+#define MXC_TCTL   0x00
+#define TCTL_VAL               TCTL_CLK_PCLK1
+#define TCTL_CLK_PCLK1         (1<<1)
+#define TCTL_CLK_PCLK1_4       (2<<1)
+#define TCTL_IRQEN             (1<<4)
+#define TCTL_FRR               (1<<8)
+#define MXC_TPRER  0x04
+#define MXC_TCMP   0x08
+#define MXC_TCR    0x0c
+#define MXC_TCN    0x10
+#define MXC_TSTAT  0x14
+#define TSTAT_CAPT             (1<<1)
+#define TSTAT_COMP             (1<<0)
+
+static inline void gpt_irq_disable(void)
+{
+       unsigned int tmp;
+
+       tmp = __raw_readl(TIMER_BASE + MXC_TCTL);
+       __raw_writel(tmp & ~TCTL_IRQEN, TIMER_BASE + MXC_TCTL);
+}
+
+static inline void gpt_irq_enable(void)
+{
+       __raw_writel(__raw_readl(TIMER_BASE + MXC_TCTL) | TCTL_IRQEN,
+                               TIMER_BASE + MXC_TCTL);
+}
+
+static void gpt_irq_acknowledge(void)
+{
+       __raw_writel(TSTAT_CAPT | TSTAT_COMP, TIMER_BASE + MXC_TSTAT);
+}
+#endif /* CONFIG_ARCH_MX2 */
+
+#ifdef CONFIG_ARCH_MX3
+#define TIMER_BASE             IO_ADDRESS(GPT1_BASE_ADDR)
+#define TIMER_INTERRUPT                MXC_INT_GPT
+
+#define MXC_TCTL   0x00
+#define TCTL_VAL               (TCTL_CLK_IPG | TCTL_WAITEN)
+#define TCTL_CLK_IPG           (1<<6)
+#define TCTL_FRR               (1<<9)
+#define TCTL_WAITEN            (1<<3)
+
+#define MXC_TPRER  0x04
+#define MXC_TSTAT  0x08
+#define TSTAT_OF1              (1<<0)
+#define TSTAT_OF2              (1<<1)
+#define TSTAT_OF3              (1<<2)
+#define TSTAT_IF1              (1<<3)
+#define TSTAT_IF2              (1<<4)
+#define TSTAT_ROV              (1<<5)
+#define MXC_IR     0x0c
+#define MXC_TCMP   0x10
+#define MXC_TCMP2  0x14
+#define MXC_TCMP3  0x18
+#define MXC_TCR    0x1c
+#define MXC_TCN    0x24
+
+static inline void gpt_irq_disable(void)
+{
+       __raw_writel(0, TIMER_BASE + MXC_IR);
+}
+
+static inline void gpt_irq_enable(void)
+{
+       __raw_writel(1<<0, TIMER_BASE + MXC_IR);
+}
+
+static inline void gpt_irq_acknowledge(void)
+{
+       __raw_writel(TSTAT_OF1, TIMER_BASE + MXC_TSTAT);
+}
+#endif /* CONFIG_ARCH_MX3 */
+
+#define TCTL_SWR               (1<<15)
+#define TCTL_CC                        (1<<10)
+#define TCTL_OM                        (1<<9)
+#define TCTL_CAP_RIS           (1<<6)
+#define TCTL_CAP_FAL           (2<<6)
+#define TCTL_CAP_RIS_FAL       (3<<6)
+#define TCTL_CAP_ENA           (1<<5)
+#define TCTL_TEN               (1<<0)
+
+#endif