From d0f349fbce2905607e0473d2358f97f48866e52c Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Sat, 5 Jul 2008 10:02:50 +0200 Subject: [PATCH] i.MXC family: Adding timer support 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 Signed-off-by: Sascha Hauer --- arch/arm/Kconfig | 2 + arch/arm/mach-mx3/Makefile | 2 +- arch/arm/mach-mx3/mx31ads.c | 13 +- arch/arm/mach-mx3/time.c | 148 ----------------- arch/arm/plat-mxc/Makefile | 2 +- arch/arm/plat-mxc/time.c | 228 +++++++++++++++++++++++++++ include/asm-arm/arch-mxc/common.h | 4 +- include/asm-arm/arch-mxc/mxc.h | 112 ++----------- include/asm-arm/arch-mxc/mxc_timer.h | 158 +++++++++++++++++++ 9 files changed, 418 insertions(+), 251 deletions(-) delete mode 100644 arch/arm/mach-mx3/time.c create mode 100644 arch/arm/plat-mxc/time.c create mode 100644 include/asm-arm/arch-mxc/mxc_timer.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 5c8c1a89be7..8a9a84c4adf 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -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 diff --git a/arch/arm/mach-mx3/Makefile b/arch/arm/mach-mx3/Makefile index 68f062b70d3..562c75d2e37 100644 --- a/arch/arm/mach-mx3/Makefile +++ b/arch/arm/mach-mx3/Makefile @@ -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 diff --git a/arch/arm/mach-mx3/mx31ads.c b/arch/arm/mach-mx3/mx31ads.c index 5addbb7f711..eba3e0cd428 100644 --- a/arch/arm/mach-mx3/mx31ads.c +++ b/arch/arm/mach-mx3/mx31ads.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -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 index fb565c98dbf..00000000000 --- a/arch/arm/mach-mx3/time.c +++ /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 -#include -#include -#include -#include -#include -#include -#include - -/*! - * 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, -}; diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index 66272a6fc32..e3cc25c6d46 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -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 index 00000000000..3bf86343fdf --- /dev/null +++ b/arch/arm/plat-mxc/time.c @@ -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 +#include +#include +#include + +#include +#include +#include +#include + +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); +} + diff --git a/include/asm-arm/arch-mxc/common.h b/include/asm-arm/arch-mxc/common.h index 8774783ed98..a6d2e24aab1 100644 --- a/include/asm-arm/arch-mxc/common.h +++ b/include/asm-arm/arch-mxc/common.h @@ -11,11 +11,9 @@ #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); diff --git a/include/asm-arm/arch-mxc/mxc.h b/include/asm-arm/arch-mxc/mxc.h index 146d3f60951..1df4e2f2492 100644 --- a/include/asm-arm/arch-mxc/mxc.h +++ b/include/asm-arm/arch-mxc/mxc.h @@ -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__ @@ -20,97 +29,6 @@ # 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 index 00000000000..6cb11f4f1a0 --- /dev/null +++ b/include/asm-arm/arch-mxc/mxc_timer.h @@ -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 +#include + +#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 -- 2.41.1