diff options
Diffstat (limited to 'arch/m68knommu/platform/coldfire')
-rw-r--r-- | arch/m68knommu/platform/coldfire/Makefile | 5 | ||||
-rw-r--r-- | arch/m68knommu/platform/coldfire/entry.S | 4 | ||||
-rw-r--r-- | arch/m68knommu/platform/coldfire/intc-2.c | 53 | ||||
-rw-r--r-- | arch/m68knommu/platform/coldfire/intc-simr.c | 10 | ||||
-rw-r--r-- | arch/m68knommu/platform/coldfire/intc.c | 8 | ||||
-rw-r--r-- | arch/m68knommu/platform/coldfire/sltimers.c | 145 |
6 files changed, 201 insertions, 24 deletions
diff --git a/arch/m68knommu/platform/coldfire/Makefile b/arch/m68knommu/platform/coldfire/Makefile index f72a0e5d9996..45f501fa4525 100644 --- a/arch/m68knommu/platform/coldfire/Makefile +++ b/arch/m68knommu/platform/coldfire/Makefile @@ -8,8 +8,8 @@ # on the console port whenever a DBG interrupt occurs. You have to # set up you HW breakpoints to trigger a DBG interrupt: # -# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT -# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT +# ccflags-y := -DTRAP_DBG_INTERRUPT +# asflags-y := -DTRAP_DBG_INTERRUPT # asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 @@ -26,6 +26,7 @@ obj-$(CONFIG_M528x) += pit.o intc-2.o obj-$(CONFIG_M5307) += timers.o intc.o obj-$(CONFIG_M532x) += timers.o intc-simr.o obj-$(CONFIG_M5407) += timers.o intc.o +obj-$(CONFIG_M548x) += sltimers.o intc-2.o obj-y += pinmux.o gpio.o extra-y := head.o diff --git a/arch/m68knommu/platform/coldfire/entry.S b/arch/m68knommu/platform/coldfire/entry.S index cd79d7e92ce6..5e92bed94b7e 100644 --- a/arch/m68knommu/platform/coldfire/entry.S +++ b/arch/m68knommu/platform/coldfire/entry.S @@ -88,7 +88,7 @@ ENTRY(system_call) movel %d2,PT_OFF_D0(%sp) /* on syscall entry */ subql #4,%sp SAVE_SWITCH_STACK - jbsr syscall_trace + jbsr syscall_trace_enter RESTORE_SWITCH_STACK addql #4,%sp movel %d3,%a0 @@ -96,7 +96,7 @@ ENTRY(system_call) movel %d0,%sp@(PT_OFF_D0) /* save the return value */ subql #4,%sp /* dummy return address */ SAVE_SWITCH_STACK - jbsr syscall_trace + jbsr syscall_trace_leave ret_from_signal: RESTORE_SWITCH_STACK diff --git a/arch/m68knommu/platform/coldfire/intc-2.c b/arch/m68knommu/platform/coldfire/intc-2.c index 5598c8b8661f..85daa2b3001a 100644 --- a/arch/m68knommu/platform/coldfire/intc-2.c +++ b/arch/m68knommu/platform/coldfire/intc-2.c @@ -1,5 +1,11 @@ /* - * intc-1.c + * intc-2.c + * + * General interrupt controller code for the many ColdFire cores that use + * interrupt controllers with 63 interrupt sources, organized as 56 fully- + * programmable + 7 fixed-level interrupt sources. This includes the 523x + * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such + * controllers, and the 547x and 548x families which have only one of them. * * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com> * @@ -19,21 +25,37 @@ #include <asm/traps.h> /* - * Each vector needs a unique priority and level asscoiated with it. + * Bit definitions for the ICR family of registers. + */ +#define MCFSIM_ICR_LEVEL(l) ((l)<<3) /* Level l intr */ +#define MCFSIM_ICR_PRI(p) (p) /* Priority p intr */ + +/* + * Each vector needs a unique priority and level associated with it. * We don't really care so much what they are, we don't rely on the - * tranditional priority interrupt scheme of the m68k/ColdFire. + * traditional priority interrupt scheme of the m68k/ColdFire. */ -static u8 intc_intpri = 0x36; +static u8 intc_intpri = MCFSIM_ICR_LEVEL(6) | MCFSIM_ICR_PRI(6); + +#ifdef MCFICM_INTC1 +#define NR_VECS 128 +#else +#define NR_VECS 64 +#endif static void intc_irq_mask(unsigned int irq) { - if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) { + if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) { unsigned long imraddr; u32 val, imrbit; irq -= MCFINT_VECBASE; imraddr = MCF_IPSBAR; +#ifdef MCFICM_INTC1 imraddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0; +#else + imraddr += MCFICM_INTC0; +#endif imraddr += (irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL; imrbit = 0x1 << (irq & 0x1f); @@ -44,13 +66,17 @@ static void intc_irq_mask(unsigned int irq) static void intc_irq_unmask(unsigned int irq) { - if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) { + if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) { unsigned long intaddr, imraddr, icraddr; u32 val, imrbit; irq -= MCFINT_VECBASE; intaddr = MCF_IPSBAR; +#ifdef MCFICM_INTC1 intaddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0; +#else + intaddr += MCFICM_INTC0; +#endif imraddr = intaddr + ((irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL); icraddr = intaddr + MCFINTC_ICR0 + (irq & 0x3f); imrbit = 0x1 << (irq & 0x1f); @@ -67,10 +93,16 @@ static void intc_irq_unmask(unsigned int irq) } } +static int intc_irq_set_type(unsigned int irq, unsigned int type) +{ + return 0; +} + static struct irq_chip intc_irq_chip = { .name = "CF-INTC", .mask = intc_irq_mask, .unmask = intc_irq_unmask, + .set_type = intc_irq_set_type, }; void __init init_IRQ(void) @@ -81,13 +113,14 @@ void __init init_IRQ(void) /* Mask all interrupt sources */ __raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL); +#ifdef MCFICM_INTC1 __raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC1 + MCFINTC_IMRL); +#endif for (irq = 0; (irq < NR_IRQS); irq++) { - irq_desc[irq].status = IRQ_DISABLED; - irq_desc[irq].action = NULL; - irq_desc[irq].depth = 1; - irq_desc[irq].chip = &intc_irq_chip; + set_irq_chip(irq, &intc_irq_chip); + set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); + set_irq_handler(irq, handle_level_irq); } } diff --git a/arch/m68knommu/platform/coldfire/intc-simr.c b/arch/m68knommu/platform/coldfire/intc-simr.c index 1b01e79c2f63..bb7048636140 100644 --- a/arch/m68knommu/platform/coldfire/intc-simr.c +++ b/arch/m68knommu/platform/coldfire/intc-simr.c @@ -1,6 +1,8 @@ /* * intc-simr.c * + * Interrupt controller code for the ColdFire 5208, 5207 & 532x parts. + * * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com> * * This file is subject to the terms and conditions of the GNU General Public @@ -68,11 +70,9 @@ void __init init_IRQ(void) __raw_writeb(0xff, MCFINTC1_SIMR); for (irq = 0; (irq < NR_IRQS); irq++) { - irq_desc[irq].status = IRQ_DISABLED; - irq_desc[irq].action = NULL; - irq_desc[irq].depth = 1; - irq_desc[irq].chip = &intc_irq_chip; - intc_irq_set_type(irq, 0); + set_irq_chip(irq, &intc_irq_chip); + set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); + set_irq_handler(irq, handle_level_irq); } } diff --git a/arch/m68knommu/platform/coldfire/intc.c b/arch/m68knommu/platform/coldfire/intc.c index a4560c86db71..60d2fcbe182b 100644 --- a/arch/m68knommu/platform/coldfire/intc.c +++ b/arch/m68knommu/platform/coldfire/intc.c @@ -143,11 +143,9 @@ void __init init_IRQ(void) mcf_maskimr(0xffffffff); for (irq = 0; (irq < NR_IRQS); irq++) { - irq_desc[irq].status = IRQ_DISABLED; - irq_desc[irq].action = NULL; - irq_desc[irq].depth = 1; - irq_desc[irq].chip = &intc_irq_chip; - intc_irq_set_type(irq, 0); + set_irq_chip(irq, &intc_irq_chip); + set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); + set_irq_handler(irq, handle_level_irq); } } diff --git a/arch/m68knommu/platform/coldfire/sltimers.c b/arch/m68knommu/platform/coldfire/sltimers.c new file mode 100644 index 000000000000..0a1b937c3e18 --- /dev/null +++ b/arch/m68knommu/platform/coldfire/sltimers.c @@ -0,0 +1,145 @@ +/***************************************************************************/ + +/* + * sltimers.c -- generic ColdFire slice timer support. + * + * Copyright (C) 2009-2010, Philippe De Muyter <phdm@macqel.be> + * based on + * timers.c -- generic ColdFire hardware timer support. + * Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com> + */ + +/***************************************************************************/ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/profile.h> +#include <linux/clocksource.h> +#include <asm/io.h> +#include <asm/traps.h> +#include <asm/machdep.h> +#include <asm/coldfire.h> +#include <asm/mcfslt.h> +#include <asm/mcfsim.h> + +/***************************************************************************/ + +#ifdef CONFIG_HIGHPROFILE + +/* + * By default use Slice Timer 1 as the profiler clock timer. + */ +#define PA(a) (MCF_MBAR + MCFSLT_TIMER1 + (a)) + +/* + * Choose a reasonably fast profile timer. Make it an odd value to + * try and get good coverage of kernel operations. + */ +#define PROFILEHZ 1013 + +irqreturn_t mcfslt_profile_tick(int irq, void *dummy) +{ + /* Reset Slice Timer 1 */ + __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, PA(MCFSLT_SSR)); + if (current->pid) + profile_tick(CPU_PROFILING); + return IRQ_HANDLED; +} + +static struct irqaction mcfslt_profile_irq = { + .name = "profile timer", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = mcfslt_profile_tick, +}; + +void mcfslt_profile_init(void) +{ + printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n", + PROFILEHZ); + + setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq); + + /* Set up TIMER 2 as high speed profile clock */ + __raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT)); + __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN, + PA(MCFSLT_SCR)); + +} + +#endif /* CONFIG_HIGHPROFILE */ + +/***************************************************************************/ + +/* + * By default use Slice Timer 0 as the system clock timer. + */ +#define TA(a) (MCF_MBAR + MCFSLT_TIMER0 + (a)) + +static u32 mcfslt_cycles_per_jiffy; +static u32 mcfslt_cnt; + +static irqreturn_t mcfslt_tick(int irq, void *dummy) +{ + /* Reset Slice Timer 0 */ + __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR)); + mcfslt_cnt += mcfslt_cycles_per_jiffy; + return arch_timer_interrupt(irq, dummy); +} + +static struct irqaction mcfslt_timer_irq = { + .name = "timer", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = mcfslt_tick, +}; + +static cycle_t mcfslt_read_clk(struct clocksource *cs) +{ + unsigned long flags; + u32 cycles; + u16 scnt; + + local_irq_save(flags); + scnt = __raw_readl(TA(MCFSLT_SCNT)); + cycles = mcfslt_cnt; + local_irq_restore(flags); + + /* substract because slice timers count down */ + return cycles - scnt; +} + +static struct clocksource mcfslt_clk = { + .name = "slt", + .rating = 250, + .read = mcfslt_read_clk, + .shift = 20, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +void hw_timer_init(void) +{ + mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ; + /* + * The coldfire slice timer (SLT) runs from STCNT to 0 included, + * then STCNT again and so on. It counts thus actually + * STCNT + 1 steps for 1 tick, not STCNT. So if you want + * n cycles, initialize STCNT with n - 1. + */ + __raw_writel(mcfslt_cycles_per_jiffy - 1, TA(MCFSLT_STCNT)); + __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN, + TA(MCFSLT_SCR)); + /* initialize mcfslt_cnt knowing that slice timers count down */ + mcfslt_cnt = mcfslt_cycles_per_jiffy; + + setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq); + + mcfslt_clk.mult = clocksource_hz2mult(MCF_BUSCLK, mcfslt_clk.shift); + clocksource_register(&mcfslt_clk); + +#ifdef CONFIG_HIGHPROFILE + mcfslt_profile_init(); +#endif +} |