diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-24 12:17:19 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-24 12:17:19 -0700 |
commit | 3fde80e94c2bbffbb13f5faa3340cf438440ebea (patch) | |
tree | 43eeac74dc34596772b9d9883e9208da8ae84184 /arch/m68knommu/platform/coldfire | |
parent | ac9f80ad16e6e934b6c1f12f82d27889c0f9abcc (diff) | |
parent | 9b0e74102494971ca37a425c63031fea68bb5b79 (diff) | |
download | op-kernel-dev-3fde80e94c2bbffbb13f5faa3340cf438440ebea.zip op-kernel-dev-3fde80e94c2bbffbb13f5faa3340cf438440ebea.tar.gz |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu:
m68knommu: put ColdFire head code into .text.head section
m68knommu: remove last use of CONFIG_FADS and CONFIG_RPXCLASSIC
m68knommu: remove RPXCLASSIC from the m68k tree
m68knommu: fec: remove FADS
m68knommu: MCF5307 PIT GENERIC_CLOCKEVENTS support
m68knommu: add read_barrier_depends() and irqs_disabled_flags()
m68knommu: add byteswap assembly opcode for ISA A+
m68knommu: add ffs and __ffs plattform which support ISA A+ or ISA C
m68knommu: add sched_clock() for the DMA timer
m68knommu: complete generic time
m68knommu: move code within time.c
m68knommu: m68knommu: add old stack trace method
m68knommu: Add Coldfire DMA Timer support
m68knommu: defconfig for M5407C3 board
m68knommu: defconfig for M5307C3 board
m68knommu: defconfig for M5275EVB board
m68knommu: defconfig for M5249EVB board
m68knommu: change to a configs directory for board configurations
Diffstat (limited to 'arch/m68knommu/platform/coldfire')
-rw-r--r-- | arch/m68knommu/platform/coldfire/Makefile | 2 | ||||
-rw-r--r-- | arch/m68knommu/platform/coldfire/dma_timer.c | 84 | ||||
-rw-r--r-- | arch/m68knommu/platform/coldfire/head.S | 3 | ||||
-rw-r--r-- | arch/m68knommu/platform/coldfire/pit.c | 91 |
4 files changed, 165 insertions, 15 deletions
diff --git a/arch/m68knommu/platform/coldfire/Makefile b/arch/m68knommu/platform/coldfire/Makefile index 40cf20b..4f416a9 100644 --- a/arch/m68knommu/platform/coldfire/Makefile +++ b/arch/m68knommu/platform/coldfire/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_COLDFIRE) += dma.o entry.o vectors.o obj-$(CONFIG_M5206) += timers.o obj-$(CONFIG_M5206e) += timers.o obj-$(CONFIG_M520x) += pit.o -obj-$(CONFIG_M523x) += pit.o +obj-$(CONFIG_M523x) += pit.o dma_timer.o obj-$(CONFIG_M5249) += timers.o obj-$(CONFIG_M527x) += pit.o obj-$(CONFIG_M5272) += timers.o diff --git a/arch/m68knommu/platform/coldfire/dma_timer.c b/arch/m68knommu/platform/coldfire/dma_timer.c new file mode 100644 index 0000000..772578b --- /dev/null +++ b/arch/m68knommu/platform/coldfire/dma_timer.c @@ -0,0 +1,84 @@ +/* + * dma_timer.c -- Freescale ColdFire DMA Timer. + * + * Copyright (C) 2007, Benedikt Spranger <b.spranger@linutronix.de> + * Copyright (C) 2008. Sebastian Siewior, Linutronix + * + */ + +#include <linux/clocksource.h> +#include <linux/io.h> + +#include <asm/machdep.h> +#include <asm/coldfire.h> +#include <asm/mcfpit.h> +#include <asm/mcfsim.h> + +#define DMA_TIMER_0 (0x00) +#define DMA_TIMER_1 (0x40) +#define DMA_TIMER_2 (0x80) +#define DMA_TIMER_3 (0xc0) + +#define DTMR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x400) +#define DTXMR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x402) +#define DTER0 (MCF_IPSBAR + DMA_TIMER_0 + 0x403) +#define DTRR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x404) +#define DTCR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x408) +#define DTCN0 (MCF_IPSBAR + DMA_TIMER_0 + 0x40c) + +#define DMA_FREQ ((MCF_CLK / 2) / 16) + +/* DTMR */ +#define DMA_DTMR_RESTART (1 << 3) +#define DMA_DTMR_CLK_DIV_1 (1 << 1) +#define DMA_DTMR_CLK_DIV_16 (2 << 1) +#define DMA_DTMR_ENABLE (1 << 0) + +static cycle_t cf_dt_get_cycles(void) +{ + return __raw_readl(DTCN0); +} + +static struct clocksource clocksource_cf_dt = { + .name = "coldfire_dma_timer", + .rating = 200, + .read = cf_dt_get_cycles, + .mask = CLOCKSOURCE_MASK(32), + .shift = 20, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static int __init init_cf_dt_clocksource(void) +{ + /* + * We setup DMA timer 0 in free run mode. This incrementing counter is + * used as a highly precious clock source. With MCF_CLOCK = 150 MHz we + * get a ~213 ns resolution and the 32bit register will overflow almost + * every 15 minutes. + */ + __raw_writeb(0x00, DTXMR0); + __raw_writeb(0x00, DTER0); + __raw_writel(0x00000000, DTRR0); + __raw_writew(DMA_DTMR_CLK_DIV_16 | DMA_DTMR_ENABLE, DTMR0); + clocksource_cf_dt.mult = clocksource_hz2mult(DMA_FREQ, + clocksource_cf_dt.shift); + return clocksource_register(&clocksource_cf_dt); +} + +arch_initcall(init_cf_dt_clocksource); + +#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ +#define CYC2NS_SCALE ((1000000 << CYC2NS_SCALE_FACTOR) / (DMA_FREQ / 1000)) + +static unsigned long long cycles2ns(unsigned long cycl) +{ + return (unsigned long long) ((unsigned long long)cycl * + CYC2NS_SCALE) >> CYC2NS_SCALE_FACTOR; +} + +unsigned long long sched_clock(void) +{ + unsigned long cycl = __raw_readl(DTCN0); + + return cycles2ns(cycl); +} diff --git a/arch/m68knommu/platform/coldfire/head.S b/arch/m68knommu/platform/coldfire/head.S index b9aa0ca..2b0d73c 100644 --- a/arch/m68knommu/platform/coldfire/head.S +++ b/arch/m68knommu/platform/coldfire/head.S @@ -10,6 +10,7 @@ #include <linux/sys.h> #include <linux/linkage.h> +#include <linux/init.h> #include <asm/asm-offsets.h> #include <asm/coldfire.h> #include <asm/mcfcache.h> @@ -126,7 +127,7 @@ _ramend: /*****************************************************************************/ -.text +__HEAD /* * This is the codes first entry point. This is where it all diff --git a/arch/m68knommu/platform/coldfire/pit.c b/arch/m68knommu/platform/coldfire/pit.c index 4290638..c5b9167 100644 --- a/arch/m68knommu/platform/coldfire/pit.c +++ b/arch/m68knommu/platform/coldfire/pit.c @@ -18,7 +18,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/clocksource.h> +#include <linux/clockchips.h> #include <asm/machdep.h> #include <asm/io.h> #include <asm/coldfire.h> @@ -33,22 +33,86 @@ #define FREQ ((MCF_CLK / 2) / 64) #define TA(a) (MCF_IPSBAR + MCFPIT_BASE1 + (a)) #define INTC0 (MCF_IPSBAR + MCFICM_INTC0) +#define PIT_CYCLES_PER_JIFFY (FREQ / HZ) -static u32 pit_cycles_per_jiffy; static u32 pit_cnt; +/* + * Initialize the PIT timer. + * + * This is also called after resume to bring the PIT into operation again. + */ + +static void init_cf_pit_timer(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + + __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); + __raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR)); + __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \ + MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | \ + MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR)); + break; + + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + + __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); + break; + + case CLOCK_EVT_MODE_ONESHOT: + + __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); + __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \ + MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, \ + TA(MCFPIT_PCSR)); + break; + + case CLOCK_EVT_MODE_RESUME: + /* Nothing to do here */ + break; + } +} + +/* + * Program the next event in oneshot mode + * + * Delta is given in PIT ticks + */ +static int cf_pit_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + __raw_writew(delta, TA(MCFPIT_PMR)); + return 0; +} + +struct clock_event_device cf_pit_clockevent = { + .name = "pit", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = init_cf_pit_timer, + .set_next_event = cf_pit_next_event, + .shift = 32, + .irq = MCFINT_VECBASE + MCFINT_PIT1, +}; + + + /***************************************************************************/ static irqreturn_t pit_tick(int irq, void *dummy) { + struct clock_event_device *evt = &cf_pit_clockevent; u16 pcsr; /* Reset the ColdFire timer */ pcsr = __raw_readw(TA(MCFPIT_PCSR)); __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR)); - pit_cnt += pit_cycles_per_jiffy; - return arch_timer_interrupt(irq, dummy); + pit_cnt += PIT_CYCLES_PER_JIFFY; + evt->event_handler(evt); + return IRQ_HANDLED; } /***************************************************************************/ @@ -72,14 +136,14 @@ static cycle_t pit_read_clk(void) cycles = pit_cnt; local_irq_restore(flags); - return cycles + pit_cycles_per_jiffy - pcntr; + return cycles + PIT_CYCLES_PER_JIFFY - pcntr; } /***************************************************************************/ static struct clocksource pit_clk = { .name = "pit", - .rating = 250, + .rating = 100, .read = pit_read_clk, .shift = 20, .mask = CLOCKSOURCE_MASK(32), @@ -92,6 +156,14 @@ void hw_timer_init(void) { u32 imr; + cf_pit_clockevent.cpumask = cpumask_of_cpu(smp_processor_id()); + cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32); + cf_pit_clockevent.max_delta_ns = + clockevent_delta2ns(0xFFFF, &cf_pit_clockevent); + cf_pit_clockevent.min_delta_ns = + clockevent_delta2ns(0x3f, &cf_pit_clockevent); + clockevents_register_device(&cf_pit_clockevent); + setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq); __raw_writeb(ICR_INTRCONF, INTC0 + MCFINTC_ICR0 + MCFINT_PIT1); @@ -99,13 +171,6 @@ void hw_timer_init(void) imr &= ~MCFPIT_IMR_IBIT; __raw_writel(imr, INTC0 + MCFPIT_IMR); - /* Set up PIT timer 1 as poll clock */ - pit_cycles_per_jiffy = FREQ / HZ; - __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); - __raw_writew(pit_cycles_per_jiffy, TA(MCFPIT_PMR)); - __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW | - MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR)); - pit_clk.mult = clocksource_hz2mult(FREQ, pit_clk.shift); clocksource_register(&pit_clk); } |