From 52c543f90c4095dff71dc125017594b61a753069 Mon Sep 17 00:00:00 2001 From: Quinn Jensen Date: Mon, 9 Jul 2007 22:06:53 +0100 Subject: [ARM] 4461/1: MXC platform and i.MX31ADS core support This patch adds the foundation pieces for the Freescale MXC platforms, including i.MX2 and i.MX3 based systems. The bare-bones MX31 support in this patch boots to the rootdev panic with 8250 serial console configured "console=ttyS0,115200". It assumes that Redboot is the boot loader. Signed-off-by: Quinn Jensen Acked-by: Lennert Buytenhek Signed-off-by: Russell King --- arch/arm/mach-mx3/time.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 arch/arm/mach-mx3/time.c (limited to 'arch/arm/mach-mx3/time.c') diff --git a/arch/arm/mach-mx3/time.c b/arch/arm/mach-mx3/time.c new file mode 100644 index 000000000000..e81fb5c5d7c3 --- /dev/null +++ b/arch/arm/mach-mx3/time.c @@ -0,0 +1,152 @@ +/* + * 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; + + write_seqlock(&xtime_lock); + + 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); + } + + write_sequnlock(&xtime_lock); + + 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, +}; -- cgit v1.2.3