diff options
author | Greg Ungerer <gerg@uclinux.org> | 2011-03-21 23:39:27 -0400 |
---|---|---|
committer | Greg Ungerer <gerg@uclinux.org> | 2011-03-25 00:05:13 -0400 |
commit | 66d857b08b8c3ed5c72c361f863cce77d2a978d7 (patch) | |
tree | 47222d86f4d78dc0da31baf64188bd2e4b38ac1e /arch/m68k/platform/coldfire | |
parent | d39dd11c3e6a7af5c20bfac40594db36cf270f42 (diff) |
m68k: merge m68k and m68knommu arch directories
There is a lot of common code that could be shared between the m68k
and m68knommu arch branches. It makes sense to merge the two branches
into a single directory structure so that we can more easily share
that common code.
This is a brute force merge, based on a script from Stephen King
<sfking@fdwdc.com>, which was originally written by Arnd Bergmann
<arnd@arndb.de>.
> The script was inspired by the script Sam Ravnborg used to merge the
> includes from m68knommu. For those files common to both arches but
> differing in content, the m68k version of the file is renamed to
> <file>_mm.<ext> and the m68knommu version of the file is moved into the
> corresponding m68k directory and renamed <file>_no.<ext> and a small
> wrapper file <file>.<ext> is used to select between the two version. Files
> that are common to both but don't differ are removed from the m68knommu
> tree and files and directories that are unique to the m68knommu tree are
> moved to the m68k tree. Finally, the arch/m68knommu tree is removed.
>
> To select between the the versions of the files, the wrapper uses
>
> #ifdef CONFIG_MMU
> #include <file>_mm.<ext>
> #else
> #include <file>_no.<ext>
> #endif
On top of this file merge I have done a simplistic merge of m68k and
m68knommu Kconfig, which primarily attempts to keep existing options and
menus in place. Other than a handful of options being moved it produces
identical .config outputs on m68k and m68knommu targets I tested it on.
With this in place there is now quite a bit of scope for merge cleanups
in future patches.
Signed-off-by: Greg Ungerer <gerg@uclinux.org>
Diffstat (limited to 'arch/m68k/platform/coldfire')
-rw-r--r-- | arch/m68k/platform/coldfire/Makefile | 32 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/cache.c | 48 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/clk.c | 45 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/dma.c | 39 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/dma_timer.c | 84 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/entry.S | 203 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/gpio.c | 127 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/head.S | 250 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/intc-2.c | 214 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/intc-simr.c | 191 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/intc.c | 151 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/pinmux.c | 28 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/pit.c | 169 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/sltimers.c | 145 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/timers.c | 174 | ||||
-rw-r--r-- | arch/m68k/platform/coldfire/vectors.c | 80 |
16 files changed, 1980 insertions, 0 deletions
diff --git a/arch/m68k/platform/coldfire/Makefile b/arch/m68k/platform/coldfire/Makefile new file mode 100644 index 000000000000..a8967baabd72 --- /dev/null +++ b/arch/m68k/platform/coldfire/Makefile | |||
@@ -0,0 +1,32 @@ | |||
1 | # | ||
2 | # Makefile for the m68knommu kernel. | ||
3 | # | ||
4 | |||
5 | # | ||
6 | # If you want to play with the HW breakpoints then you will | ||
7 | # need to add define this, which will give you a stack backtrace | ||
8 | # on the console port whenever a DBG interrupt occurs. You have to | ||
9 | # set up you HW breakpoints to trigger a DBG interrupt: | ||
10 | # | ||
11 | # ccflags-y := -DTRAP_DBG_INTERRUPT | ||
12 | # asflags-y := -DTRAP_DBG_INTERRUPT | ||
13 | # | ||
14 | |||
15 | asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 | ||
16 | |||
17 | obj-$(CONFIG_COLDFIRE) += cache.o clk.o dma.o entry.o vectors.o | ||
18 | obj-$(CONFIG_M5206) += timers.o intc.o | ||
19 | obj-$(CONFIG_M5206e) += timers.o intc.o | ||
20 | obj-$(CONFIG_M520x) += pit.o intc-simr.o | ||
21 | obj-$(CONFIG_M523x) += pit.o dma_timer.o intc-2.o | ||
22 | obj-$(CONFIG_M5249) += timers.o intc.o | ||
23 | obj-$(CONFIG_M527x) += pit.o intc-2.o | ||
24 | obj-$(CONFIG_M5272) += timers.o | ||
25 | obj-$(CONFIG_M528x) += pit.o intc-2.o | ||
26 | obj-$(CONFIG_M5307) += timers.o intc.o | ||
27 | obj-$(CONFIG_M532x) += timers.o intc-simr.o | ||
28 | obj-$(CONFIG_M5407) += timers.o intc.o | ||
29 | obj-$(CONFIG_M54xx) += sltimers.o intc-2.o | ||
30 | |||
31 | obj-y += pinmux.o gpio.o | ||
32 | extra-y := head.o | ||
diff --git a/arch/m68k/platform/coldfire/cache.c b/arch/m68k/platform/coldfire/cache.c new file mode 100644 index 000000000000..235d3c4f4f0f --- /dev/null +++ b/arch/m68k/platform/coldfire/cache.c | |||
@@ -0,0 +1,48 @@ | |||
1 | /***************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * cache.c -- general ColdFire Cache maintainence code | ||
5 | * | ||
6 | * Copyright (C) 2010, Greg Ungerer (gerg@snapgear.com) | ||
7 | */ | ||
8 | |||
9 | /***************************************************************************/ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <asm/coldfire.h> | ||
13 | #include <asm/mcfsim.h> | ||
14 | |||
15 | /***************************************************************************/ | ||
16 | #ifdef CACHE_PUSH | ||
17 | /***************************************************************************/ | ||
18 | |||
19 | /* | ||
20 | * Use cpushl to push all dirty cache lines back to memory. | ||
21 | * Older versions of GAS don't seem to know how to generate the | ||
22 | * ColdFire cpushl instruction... Oh well, bit stuff it for now. | ||
23 | */ | ||
24 | |||
25 | void mcf_cache_push(void) | ||
26 | { | ||
27 | __asm__ __volatile__ ( | ||
28 | "clrl %%d0\n\t" | ||
29 | "1:\n\t" | ||
30 | "movel %%d0,%%a0\n\t" | ||
31 | "2:\n\t" | ||
32 | ".word 0xf468\n\t" | ||
33 | "addl %0,%%a0\n\t" | ||
34 | "cmpl %1,%%a0\n\t" | ||
35 | "blt 2b\n\t" | ||
36 | "addql #1,%%d0\n\t" | ||
37 | "cmpil %2,%%d0\n\t" | ||
38 | "bne 1b\n\t" | ||
39 | : /* No output */ | ||
40 | : "i" (CACHE_LINE_SIZE), | ||
41 | "i" (DCACHE_SIZE / CACHE_WAYS), | ||
42 | "i" (CACHE_WAYS) | ||
43 | : "d0", "a0" ); | ||
44 | } | ||
45 | |||
46 | /***************************************************************************/ | ||
47 | #endif /* CACHE_PUSH */ | ||
48 | /***************************************************************************/ | ||
diff --git a/arch/m68k/platform/coldfire/clk.c b/arch/m68k/platform/coldfire/clk.c new file mode 100644 index 000000000000..9f1260c5e2ad --- /dev/null +++ b/arch/m68k/platform/coldfire/clk.c | |||
@@ -0,0 +1,45 @@ | |||
1 | /***************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * clk.c -- general ColdFire CPU kernel clk handling | ||
5 | * | ||
6 | * Copyright (C) 2009, Greg Ungerer (gerg@snapgear.com) | ||
7 | */ | ||
8 | |||
9 | /***************************************************************************/ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/clk.h> | ||
14 | #include <asm/coldfire.h> | ||
15 | |||
16 | /***************************************************************************/ | ||
17 | |||
18 | struct clk *clk_get(struct device *dev, const char *id) | ||
19 | { | ||
20 | return NULL; | ||
21 | } | ||
22 | EXPORT_SYMBOL(clk_get); | ||
23 | |||
24 | int clk_enable(struct clk *clk) | ||
25 | { | ||
26 | return 0; | ||
27 | } | ||
28 | EXPORT_SYMBOL(clk_enable); | ||
29 | |||
30 | void clk_disable(struct clk *clk) | ||
31 | { | ||
32 | } | ||
33 | EXPORT_SYMBOL(clk_disable); | ||
34 | |||
35 | void clk_put(struct clk *clk) | ||
36 | { | ||
37 | } | ||
38 | EXPORT_SYMBOL(clk_put); | ||
39 | |||
40 | unsigned long clk_get_rate(struct clk *clk) | ||
41 | { | ||
42 | return MCF_CLK; | ||
43 | } | ||
44 | EXPORT_SYMBOL(clk_get_rate); | ||
45 | /***************************************************************************/ | ||
diff --git a/arch/m68k/platform/coldfire/dma.c b/arch/m68k/platform/coldfire/dma.c new file mode 100644 index 000000000000..e88b95e2cc62 --- /dev/null +++ b/arch/m68k/platform/coldfire/dma.c | |||
@@ -0,0 +1,39 @@ | |||
1 | /***************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * dma.c -- Freescale ColdFire DMA support | ||
5 | * | ||
6 | * Copyright (C) 2007, Greg Ungerer (gerg@snapgear.com) | ||
7 | */ | ||
8 | |||
9 | /***************************************************************************/ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <asm/dma.h> | ||
13 | #include <asm/coldfire.h> | ||
14 | #include <asm/mcfsim.h> | ||
15 | #include <asm/mcfdma.h> | ||
16 | |||
17 | /***************************************************************************/ | ||
18 | |||
19 | /* | ||
20 | * DMA channel base address table. | ||
21 | */ | ||
22 | unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { | ||
23 | #ifdef MCFDMA_BASE0 | ||
24 | MCFDMA_BASE0, | ||
25 | #endif | ||
26 | #ifdef MCFDMA_BASE1 | ||
27 | MCFDMA_BASE1, | ||
28 | #endif | ||
29 | #ifdef MCFDMA_BASE2 | ||
30 | MCFDMA_BASE2, | ||
31 | #endif | ||
32 | #ifdef MCFDMA_BASE3 | ||
33 | MCFDMA_BASE3, | ||
34 | #endif | ||
35 | }; | ||
36 | |||
37 | unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; | ||
38 | |||
39 | /***************************************************************************/ | ||
diff --git a/arch/m68k/platform/coldfire/dma_timer.c b/arch/m68k/platform/coldfire/dma_timer.c new file mode 100644 index 000000000000..a5f562823d7a --- /dev/null +++ b/arch/m68k/platform/coldfire/dma_timer.c | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * dma_timer.c -- Freescale ColdFire DMA Timer. | ||
3 | * | ||
4 | * Copyright (C) 2007, Benedikt Spranger <b.spranger@linutronix.de> | ||
5 | * Copyright (C) 2008. Sebastian Siewior, Linutronix | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #include <linux/clocksource.h> | ||
10 | #include <linux/io.h> | ||
11 | |||
12 | #include <asm/machdep.h> | ||
13 | #include <asm/coldfire.h> | ||
14 | #include <asm/mcfpit.h> | ||
15 | #include <asm/mcfsim.h> | ||
16 | |||
17 | #define DMA_TIMER_0 (0x00) | ||
18 | #define DMA_TIMER_1 (0x40) | ||
19 | #define DMA_TIMER_2 (0x80) | ||
20 | #define DMA_TIMER_3 (0xc0) | ||
21 | |||
22 | #define DTMR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x400) | ||
23 | #define DTXMR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x402) | ||
24 | #define DTER0 (MCF_IPSBAR + DMA_TIMER_0 + 0x403) | ||
25 | #define DTRR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x404) | ||
26 | #define DTCR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x408) | ||
27 | #define DTCN0 (MCF_IPSBAR + DMA_TIMER_0 + 0x40c) | ||
28 | |||
29 | #define DMA_FREQ ((MCF_CLK / 2) / 16) | ||
30 | |||
31 | /* DTMR */ | ||
32 | #define DMA_DTMR_RESTART (1 << 3) | ||
33 | #define DMA_DTMR_CLK_DIV_1 (1 << 1) | ||
34 | #define DMA_DTMR_CLK_DIV_16 (2 << 1) | ||
35 | #define DMA_DTMR_ENABLE (1 << 0) | ||
36 | |||
37 | static cycle_t cf_dt_get_cycles(struct clocksource *cs) | ||
38 | { | ||
39 | return __raw_readl(DTCN0); | ||
40 | } | ||
41 | |||
42 | static struct clocksource clocksource_cf_dt = { | ||
43 | .name = "coldfire_dma_timer", | ||
44 | .rating = 200, | ||
45 | .read = cf_dt_get_cycles, | ||
46 | .mask = CLOCKSOURCE_MASK(32), | ||
47 | .shift = 20, | ||
48 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
49 | }; | ||
50 | |||
51 | static int __init init_cf_dt_clocksource(void) | ||
52 | { | ||
53 | /* | ||
54 | * We setup DMA timer 0 in free run mode. This incrementing counter is | ||
55 | * used as a highly precious clock source. With MCF_CLOCK = 150 MHz we | ||
56 | * get a ~213 ns resolution and the 32bit register will overflow almost | ||
57 | * every 15 minutes. | ||
58 | */ | ||
59 | __raw_writeb(0x00, DTXMR0); | ||
60 | __raw_writeb(0x00, DTER0); | ||
61 | __raw_writel(0x00000000, DTRR0); | ||
62 | __raw_writew(DMA_DTMR_CLK_DIV_16 | DMA_DTMR_ENABLE, DTMR0); | ||
63 | clocksource_cf_dt.mult = clocksource_hz2mult(DMA_FREQ, | ||
64 | clocksource_cf_dt.shift); | ||
65 | return clocksource_register(&clocksource_cf_dt); | ||
66 | } | ||
67 | |||
68 | arch_initcall(init_cf_dt_clocksource); | ||
69 | |||
70 | #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ | ||
71 | #define CYC2NS_SCALE ((1000000 << CYC2NS_SCALE_FACTOR) / (DMA_FREQ / 1000)) | ||
72 | |||
73 | static unsigned long long cycles2ns(unsigned long cycl) | ||
74 | { | ||
75 | return (unsigned long long) ((unsigned long long)cycl * | ||
76 | CYC2NS_SCALE) >> CYC2NS_SCALE_FACTOR; | ||
77 | } | ||
78 | |||
79 | unsigned long long sched_clock(void) | ||
80 | { | ||
81 | unsigned long cycl = __raw_readl(DTCN0); | ||
82 | |||
83 | return cycles2ns(cycl); | ||
84 | } | ||
diff --git a/arch/m68k/platform/coldfire/entry.S b/arch/m68k/platform/coldfire/entry.S new file mode 100644 index 000000000000..5837cf080b6d --- /dev/null +++ b/arch/m68k/platform/coldfire/entry.S | |||
@@ -0,0 +1,203 @@ | |||
1 | /* | ||
2 | * linux/arch/m68knommu/platform/5307/entry.S | ||
3 | * | ||
4 | * Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com) | ||
5 | * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>, | ||
6 | * Kenneth Albanowski <kjahds@kjahds.com>, | ||
7 | * Copyright (C) 2000 Lineo Inc. (www.lineo.com) | ||
8 | * Copyright (C) 2004-2006 Macq Electronique SA. (www.macqel.com) | ||
9 | * | ||
10 | * Based on: | ||
11 | * | ||
12 | * linux/arch/m68k/kernel/entry.S | ||
13 | * | ||
14 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
15 | * | ||
16 | * This file is subject to the terms and conditions of the GNU General Public | ||
17 | * License. See the file README.legal in the main directory of this archive | ||
18 | * for more details. | ||
19 | * | ||
20 | * Linux/m68k support by Hamish Macdonald | ||
21 | * | ||
22 | * 68060 fixes by Jesper Skov | ||
23 | * ColdFire support by Greg Ungerer (gerg@snapgear.com) | ||
24 | * 5307 fixes by David W. Miller | ||
25 | * linux 2.4 support David McCullough <davidm@snapgear.com> | ||
26 | * Bug, speed and maintainability fixes by Philippe De Muyter <phdm@macqel.be> | ||
27 | */ | ||
28 | |||
29 | #include <linux/sys.h> | ||
30 | #include <linux/linkage.h> | ||
31 | #include <asm/unistd.h> | ||
32 | #include <asm/thread_info.h> | ||
33 | #include <asm/errno.h> | ||
34 | #include <asm/setup.h> | ||
35 | #include <asm/segment.h> | ||
36 | #include <asm/asm-offsets.h> | ||
37 | #include <asm/entry.h> | ||
38 | |||
39 | #ifdef CONFIG_COLDFIRE_SW_A7 | ||
40 | /* | ||
41 | * Define software copies of the supervisor and user stack pointers. | ||
42 | */ | ||
43 | .bss | ||
44 | sw_ksp: | ||
45 | .long 0 | ||
46 | sw_usp: | ||
47 | .long 0 | ||
48 | #endif /* CONFIG_COLDFIRE_SW_A7 */ | ||
49 | |||
50 | .text | ||
51 | |||
52 | .globl system_call | ||
53 | .globl resume | ||
54 | .globl ret_from_exception | ||
55 | .globl ret_from_signal | ||
56 | .globl sys_call_table | ||
57 | .globl inthandler | ||
58 | .globl fasthandler | ||
59 | |||
60 | enosys: | ||
61 | mov.l #sys_ni_syscall,%d3 | ||
62 | bra 1f | ||
63 | |||
64 | ENTRY(system_call) | ||
65 | SAVE_ALL | ||
66 | move #0x2000,%sr /* enable intrs again */ | ||
67 | |||
68 | cmpl #NR_syscalls,%d0 | ||
69 | jcc enosys | ||
70 | lea sys_call_table,%a0 | ||
71 | lsll #2,%d0 /* movel %a0@(%d0:l:4),%d3 */ | ||
72 | movel %a0@(%d0),%d3 | ||
73 | jeq enosys | ||
74 | |||
75 | 1: | ||
76 | movel %sp,%d2 /* get thread_info pointer */ | ||
77 | andl #-THREAD_SIZE,%d2 /* at start of kernel stack */ | ||
78 | movel %d2,%a0 | ||
79 | movel %a0@,%a1 /* save top of frame */ | ||
80 | movel %sp,%a1@(TASK_THREAD+THREAD_ESP0) | ||
81 | btst #(TIF_SYSCALL_TRACE%8),%a0@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8) | ||
82 | bnes 1f | ||
83 | |||
84 | movel %d3,%a0 | ||
85 | jbsr %a0@ | ||
86 | movel %d0,%sp@(PT_OFF_D0) /* save the return value */ | ||
87 | jra ret_from_exception | ||
88 | 1: | ||
89 | movel #-ENOSYS,%d2 /* strace needs -ENOSYS in PT_OFF_D0 */ | ||
90 | movel %d2,PT_OFF_D0(%sp) /* on syscall entry */ | ||
91 | subql #4,%sp | ||
92 | SAVE_SWITCH_STACK | ||
93 | jbsr syscall_trace_enter | ||
94 | RESTORE_SWITCH_STACK | ||
95 | addql #4,%sp | ||
96 | movel %d3,%a0 | ||
97 | jbsr %a0@ | ||
98 | movel %d0,%sp@(PT_OFF_D0) /* save the return value */ | ||
99 | subql #4,%sp /* dummy return address */ | ||
100 | SAVE_SWITCH_STACK | ||
101 | jbsr syscall_trace_leave | ||
102 | |||
103 | ret_from_signal: | ||
104 | RESTORE_SWITCH_STACK | ||
105 | addql #4,%sp | ||
106 | |||
107 | ret_from_exception: | ||
108 | move #0x2700,%sr /* disable intrs */ | ||
109 | btst #5,%sp@(PT_OFF_SR) /* check if returning to kernel */ | ||
110 | jeq Luser_return /* if so, skip resched, signals */ | ||
111 | |||
112 | #ifdef CONFIG_PREEMPT | ||
113 | movel %sp,%d1 /* get thread_info pointer */ | ||
114 | andl #-THREAD_SIZE,%d1 /* at base of kernel stack */ | ||
115 | movel %d1,%a0 | ||
116 | movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */ | ||
117 | andl #(1<<TIF_NEED_RESCHED),%d1 | ||
118 | jeq Lkernel_return | ||
119 | |||
120 | movel %a0@(TI_PREEMPTCOUNT),%d1 | ||
121 | cmpl #0,%d1 | ||
122 | jne Lkernel_return | ||
123 | |||
124 | pea Lkernel_return | ||
125 | jmp preempt_schedule_irq /* preempt the kernel */ | ||
126 | #endif | ||
127 | |||
128 | Lkernel_return: | ||
129 | moveml %sp@,%d1-%d5/%a0-%a2 | ||
130 | lea %sp@(32),%sp /* space for 8 regs */ | ||
131 | movel %sp@+,%d0 | ||
132 | addql #4,%sp /* orig d0 */ | ||
133 | addl %sp@+,%sp /* stk adj */ | ||
134 | rte | ||
135 | |||
136 | Luser_return: | ||
137 | movel %sp,%d1 /* get thread_info pointer */ | ||
138 | andl #-THREAD_SIZE,%d1 /* at base of kernel stack */ | ||
139 | movel %d1,%a0 | ||
140 | movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */ | ||
141 | jne Lwork_to_do /* still work to do */ | ||
142 | |||
143 | Lreturn: | ||
144 | RESTORE_USER | ||
145 | |||
146 | Lwork_to_do: | ||
147 | movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */ | ||
148 | move #0x2000,%sr /* enable intrs again */ | ||
149 | btst #TIF_NEED_RESCHED,%d1 | ||
150 | jne reschedule | ||
151 | |||
152 | /* GERG: do we need something here for TRACEing?? */ | ||
153 | |||
154 | Lsignal_return: | ||
155 | subql #4,%sp /* dummy return address */ | ||
156 | SAVE_SWITCH_STACK | ||
157 | pea %sp@(SWITCH_STACK_SIZE) | ||
158 | jsr do_signal | ||
159 | addql #4,%sp | ||
160 | RESTORE_SWITCH_STACK | ||
161 | addql #4,%sp | ||
162 | jmp Luser_return | ||
163 | |||
164 | /* | ||
165 | * This is the generic interrupt handler (for all hardware interrupt | ||
166 | * sources). Calls upto high level code to do all the work. | ||
167 | */ | ||
168 | ENTRY(inthandler) | ||
169 | SAVE_ALL | ||
170 | moveq #-1,%d0 | ||
171 | movel %d0,%sp@(PT_OFF_ORIG_D0) | ||
172 | |||
173 | movew %sp@(PT_OFF_FORMATVEC),%d0 /* put exception # in d0 */ | ||
174 | andl #0x03fc,%d0 /* mask out vector only */ | ||
175 | |||
176 | movel %sp,%sp@- /* push regs arg */ | ||
177 | lsrl #2,%d0 /* calculate real vector # */ | ||
178 | movel %d0,%sp@- /* push vector number */ | ||
179 | jbsr do_IRQ /* call high level irq handler */ | ||
180 | lea %sp@(8),%sp /* pop args off stack */ | ||
181 | |||
182 | bra ret_from_exception | ||
183 | |||
184 | /* | ||
185 | * Beware - when entering resume, prev (the current task) is | ||
186 | * in a0, next (the new task) is in a1,so don't change these | ||
187 | * registers until their contents are no longer needed. | ||
188 | * This is always called in supervisor mode, so don't bother to save | ||
189 | * and restore sr; user's process sr is actually in the stack. | ||
190 | */ | ||
191 | ENTRY(resume) | ||
192 | movel %a0, %d1 /* get prev thread in d1 */ | ||
193 | RDUSP | ||
194 | movel %a2,%a0@(TASK_THREAD+THREAD_USP) | ||
195 | |||
196 | SAVE_SWITCH_STACK | ||
197 | movel %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */ | ||
198 | movel %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */ | ||
199 | RESTORE_SWITCH_STACK | ||
200 | |||
201 | movel %a1@(TASK_THREAD+THREAD_USP),%a0 /* restore thread user stack */ | ||
202 | WRUSP | ||
203 | rts | ||
diff --git a/arch/m68k/platform/coldfire/gpio.c b/arch/m68k/platform/coldfire/gpio.c new file mode 100644 index 000000000000..ff0045793450 --- /dev/null +++ b/arch/m68k/platform/coldfire/gpio.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * Coldfire generic GPIO support. | ||
3 | * | ||
4 | * (C) Copyright 2009, Steven King <sfking@fdwdc.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/sysdev.h> | ||
19 | |||
20 | #include <asm/gpio.h> | ||
21 | #include <asm/pinmux.h> | ||
22 | #include <asm/mcfgpio.h> | ||
23 | |||
24 | #define MCF_CHIP(chip) container_of(chip, struct mcf_gpio_chip, gpio_chip) | ||
25 | |||
26 | int mcf_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
27 | { | ||
28 | unsigned long flags; | ||
29 | MCFGPIO_PORTTYPE dir; | ||
30 | struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip); | ||
31 | |||
32 | local_irq_save(flags); | ||
33 | dir = mcfgpio_read(mcf_chip->pddr); | ||
34 | dir &= ~mcfgpio_bit(chip->base + offset); | ||
35 | mcfgpio_write(dir, mcf_chip->pddr); | ||
36 | local_irq_restore(flags); | ||
37 | |||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | int mcf_gpio_get_value(struct gpio_chip *chip, unsigned offset) | ||
42 | { | ||
43 | struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip); | ||
44 | |||
45 | return mcfgpio_read(mcf_chip->ppdr) & mcfgpio_bit(chip->base + offset); | ||
46 | } | ||
47 | |||
48 | int mcf_gpio_direction_output(struct gpio_chip *chip, unsigned offset, | ||
49 | int value) | ||
50 | { | ||
51 | unsigned long flags; | ||
52 | MCFGPIO_PORTTYPE data; | ||
53 | struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip); | ||
54 | |||
55 | local_irq_save(flags); | ||
56 | /* write the value to the output latch */ | ||
57 | data = mcfgpio_read(mcf_chip->podr); | ||
58 | if (value) | ||
59 | data |= mcfgpio_bit(chip->base + offset); | ||
60 | else | ||
61 | data &= ~mcfgpio_bit(chip->base + offset); | ||
62 | mcfgpio_write(data, mcf_chip->podr); | ||
63 | |||
64 | /* now set the direction to output */ | ||
65 | data = mcfgpio_read(mcf_chip->pddr); | ||
66 | data |= mcfgpio_bit(chip->base + offset); | ||
67 | mcfgpio_write(data, mcf_chip->pddr); | ||
68 | local_irq_restore(flags); | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | void mcf_gpio_set_value(struct gpio_chip *chip, unsigned offset, int value) | ||
74 | { | ||
75 | struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip); | ||
76 | |||
77 | unsigned long flags; | ||
78 | MCFGPIO_PORTTYPE data; | ||
79 | |||
80 | local_irq_save(flags); | ||
81 | data = mcfgpio_read(mcf_chip->podr); | ||
82 | if (value) | ||
83 | data |= mcfgpio_bit(chip->base + offset); | ||
84 | else | ||
85 | data &= ~mcfgpio_bit(chip->base + offset); | ||
86 | mcfgpio_write(data, mcf_chip->podr); | ||
87 | local_irq_restore(flags); | ||
88 | } | ||
89 | |||
90 | void mcf_gpio_set_value_fast(struct gpio_chip *chip, unsigned offset, int value) | ||
91 | { | ||
92 | struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip); | ||
93 | |||
94 | if (value) | ||
95 | mcfgpio_write(mcfgpio_bit(chip->base + offset), mcf_chip->setr); | ||
96 | else | ||
97 | mcfgpio_write(~mcfgpio_bit(chip->base + offset), mcf_chip->clrr); | ||
98 | } | ||
99 | |||
100 | int mcf_gpio_request(struct gpio_chip *chip, unsigned offset) | ||
101 | { | ||
102 | struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip); | ||
103 | |||
104 | return mcf_chip->gpio_to_pinmux ? | ||
105 | mcf_pinmux_request(mcf_chip->gpio_to_pinmux[offset], 0) : 0; | ||
106 | } | ||
107 | |||
108 | void mcf_gpio_free(struct gpio_chip *chip, unsigned offset) | ||
109 | { | ||
110 | struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip); | ||
111 | |||
112 | mcf_gpio_direction_input(chip, offset); | ||
113 | |||
114 | if (mcf_chip->gpio_to_pinmux) | ||
115 | mcf_pinmux_release(mcf_chip->gpio_to_pinmux[offset], 0); | ||
116 | } | ||
117 | |||
118 | struct sysdev_class mcf_gpio_sysclass = { | ||
119 | .name = "gpio", | ||
120 | }; | ||
121 | |||
122 | static int __init mcf_gpio_sysinit(void) | ||
123 | { | ||
124 | return sysdev_class_register(&mcf_gpio_sysclass); | ||
125 | } | ||
126 | |||
127 | core_initcall(mcf_gpio_sysinit); | ||
diff --git a/arch/m68k/platform/coldfire/head.S b/arch/m68k/platform/coldfire/head.S new file mode 100644 index 000000000000..129bff4956b5 --- /dev/null +++ b/arch/m68k/platform/coldfire/head.S | |||
@@ -0,0 +1,250 @@ | |||
1 | /*****************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * head.S -- common startup code for ColdFire CPUs. | ||
5 | * | ||
6 | * (C) Copyright 1999-2010, Greg Ungerer <gerg@snapgear.com>. | ||
7 | */ | ||
8 | |||
9 | /*****************************************************************************/ | ||
10 | |||
11 | #include <linux/sys.h> | ||
12 | #include <linux/linkage.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <asm/asm-offsets.h> | ||
15 | #include <asm/coldfire.h> | ||
16 | #include <asm/mcfsim.h> | ||
17 | #include <asm/thread_info.h> | ||
18 | |||
19 | /*****************************************************************************/ | ||
20 | |||
21 | /* | ||
22 | * If we don't have a fixed memory size, then lets build in code | ||
23 | * to auto detect the DRAM size. Obviously this is the prefered | ||
24 | * method, and should work for most boards. It won't work for those | ||
25 | * that do not have their RAM starting at address 0, and it only | ||
26 | * works on SDRAM (not boards fitted with SRAM). | ||
27 | */ | ||
28 | #if CONFIG_RAMSIZE != 0 | ||
29 | .macro GET_MEM_SIZE | ||
30 | movel #CONFIG_RAMSIZE,%d0 /* hard coded memory size */ | ||
31 | .endm | ||
32 | |||
33 | #elif defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \ | ||
34 | defined(CONFIG_M5249) || defined(CONFIG_M527x) || \ | ||
35 | defined(CONFIG_M528x) || defined(CONFIG_M5307) || \ | ||
36 | defined(CONFIG_M5407) | ||
37 | /* | ||
38 | * Not all these devices have exactly the same DRAM controller, | ||
39 | * but the DCMR register is virtually identical - give or take | ||
40 | * a couple of bits. The only exception is the 5272 devices, their | ||
41 | * DRAM controller is quite different. | ||
42 | */ | ||
43 | .macro GET_MEM_SIZE | ||
44 | movel MCFSIM_DMR0,%d0 /* get mask for 1st bank */ | ||
45 | btst #0,%d0 /* check if region enabled */ | ||
46 | beq 1f | ||
47 | andl #0xfffc0000,%d0 | ||
48 | beq 1f | ||
49 | addl #0x00040000,%d0 /* convert mask to size */ | ||
50 | 1: | ||
51 | movel MCFSIM_DMR1,%d1 /* get mask for 2nd bank */ | ||
52 | btst #0,%d1 /* check if region enabled */ | ||
53 | beq 2f | ||
54 | andl #0xfffc0000,%d1 | ||
55 | beq 2f | ||
56 | addl #0x00040000,%d1 | ||
57 | addl %d1,%d0 /* total mem size in d0 */ | ||
58 | 2: | ||
59 | .endm | ||
60 | |||
61 | #elif defined(CONFIG_M5272) | ||
62 | .macro GET_MEM_SIZE | ||
63 | movel MCF_MBAR+MCFSIM_CSOR7,%d0 /* get SDRAM address mask */ | ||
64 | andil #0xfffff000,%d0 /* mask out chip select options */ | ||
65 | negl %d0 /* negate bits */ | ||
66 | .endm | ||
67 | |||
68 | #elif defined(CONFIG_M520x) | ||
69 | .macro GET_MEM_SIZE | ||
70 | clrl %d0 | ||
71 | movel MCFSIM_SDCS0, %d2 /* Get SDRAM chip select 0 config */ | ||
72 | andl #0x1f, %d2 /* Get only the chip select size */ | ||
73 | beq 3f /* Check if it is enabled */ | ||
74 | addql #1, %d2 /* Form exponent */ | ||
75 | moveql #1, %d0 | ||
76 | lsll %d2, %d0 /* 2 ^ exponent */ | ||
77 | 3: | ||
78 | movel MCFSIM_SDCS1, %d2 /* Get SDRAM chip select 1 config */ | ||
79 | andl #0x1f, %d2 /* Get only the chip select size */ | ||
80 | beq 4f /* Check if it is enabled */ | ||
81 | addql #1, %d2 /* Form exponent */ | ||
82 | moveql #1, %d1 | ||
83 | lsll %d2, %d1 /* 2 ^ exponent */ | ||
84 | addl %d1, %d0 /* Total size of SDRAM in d0 */ | ||
85 | 4: | ||
86 | .endm | ||
87 | |||
88 | #else | ||
89 | #error "ERROR: I don't know how to probe your boards memory size?" | ||
90 | #endif | ||
91 | |||
92 | /*****************************************************************************/ | ||
93 | |||
94 | /* | ||
95 | * Boards and platforms can do specific early hardware setup if | ||
96 | * they need to. Most don't need this, define away if not required. | ||
97 | */ | ||
98 | #ifndef PLATFORM_SETUP | ||
99 | #define PLATFORM_SETUP | ||
100 | #endif | ||
101 | |||
102 | /*****************************************************************************/ | ||
103 | |||
104 | .global _start | ||
105 | .global _rambase | ||
106 | .global _ramvec | ||
107 | .global _ramstart | ||
108 | .global _ramend | ||
109 | #if defined(CONFIG_UBOOT) | ||
110 | .global _init_sp | ||
111 | #endif | ||
112 | |||
113 | /*****************************************************************************/ | ||
114 | |||
115 | .data | ||
116 | |||
117 | /* | ||
118 | * During startup we store away the RAM setup. These are not in the | ||
119 | * bss, since their values are determined and written before the bss | ||
120 | * has been cleared. | ||
121 | */ | ||
122 | _rambase: | ||
123 | .long 0 | ||
124 | _ramvec: | ||
125 | .long 0 | ||
126 | _ramstart: | ||
127 | .long 0 | ||
128 | _ramend: | ||
129 | .long 0 | ||
130 | #if defined(CONFIG_UBOOT) | ||
131 | _init_sp: | ||
132 | .long 0 | ||
133 | #endif | ||
134 | |||
135 | /*****************************************************************************/ | ||
136 | |||
137 | __HEAD | ||
138 | |||
139 | /* | ||
140 | * This is the codes first entry point. This is where it all | ||
141 | * begins... | ||
142 | */ | ||
143 | |||
144 | _start: | ||
145 | nop /* filler */ | ||
146 | movew #0x2700, %sr /* no interrupts */ | ||
147 | #if defined(CONFIG_UBOOT) | ||
148 | movel %sp,_init_sp /* save initial stack pointer */ | ||
149 | #endif | ||
150 | |||
151 | /* | ||
152 | * Do any platform or board specific setup now. Most boards | ||
153 | * don't need anything. Those exceptions are define this in | ||
154 | * their board specific includes. | ||
155 | */ | ||
156 | PLATFORM_SETUP | ||
157 | |||
158 | /* | ||
159 | * Create basic memory configuration. Set VBR accordingly, | ||
160 | * and size memory. | ||
161 | */ | ||
162 | movel #CONFIG_VECTORBASE,%a7 | ||
163 | movec %a7,%VBR /* set vectors addr */ | ||
164 | movel %a7,_ramvec | ||
165 | |||
166 | movel #CONFIG_RAMBASE,%a7 /* mark the base of RAM */ | ||
167 | movel %a7,_rambase | ||
168 | |||
169 | GET_MEM_SIZE /* macro code determines size */ | ||
170 | addl %a7,%d0 | ||
171 | movel %d0,_ramend /* set end ram addr */ | ||
172 | |||
173 | /* | ||
174 | * Now that we know what the memory is, lets enable cache | ||
175 | * and get things moving. This is Coldfire CPU specific. Not | ||
176 | * all version cores have identical cache register setup. But | ||
177 | * it is very similar. Define the exact settings in the headers | ||
178 | * then the code here is the same for all. | ||
179 | */ | ||
180 | movel #CACHE_INIT,%d0 /* invalidate whole cache */ | ||
181 | movec %d0,%CACR | ||
182 | nop | ||
183 | movel #ACR0_MODE,%d0 /* set RAM region for caching */ | ||
184 | movec %d0,%ACR0 | ||
185 | movel #ACR1_MODE,%d0 /* anything else to cache? */ | ||
186 | movec %d0,%ACR1 | ||
187 | #ifdef ACR2_MODE | ||
188 | movel #ACR2_MODE,%d0 | ||
189 | movec %d0,%ACR2 | ||
190 | movel #ACR3_MODE,%d0 | ||
191 | movec %d0,%ACR3 | ||
192 | #endif | ||
193 | movel #CACHE_MODE,%d0 /* enable cache */ | ||
194 | movec %d0,%CACR | ||
195 | nop | ||
196 | |||
197 | #ifdef CONFIG_ROMFS_FS | ||
198 | /* | ||
199 | * Move ROM filesystem above bss :-) | ||
200 | */ | ||
201 | lea _sbss,%a0 /* get start of bss */ | ||
202 | lea _ebss,%a1 /* set up destination */ | ||
203 | movel %a0,%a2 /* copy of bss start */ | ||
204 | |||
205 | movel 8(%a0),%d0 /* get size of ROMFS */ | ||
206 | addql #8,%d0 /* allow for rounding */ | ||
207 | andl #0xfffffffc, %d0 /* whole words */ | ||
208 | |||
209 | addl %d0,%a0 /* copy from end */ | ||
210 | addl %d0,%a1 /* copy from end */ | ||
211 | movel %a1,_ramstart /* set start of ram */ | ||
212 | |||
213 | _copy_romfs: | ||
214 | movel -(%a0),%d0 /* copy dword */ | ||
215 | movel %d0,-(%a1) | ||
216 | cmpl %a0,%a2 /* check if at end */ | ||
217 | bne _copy_romfs | ||
218 | |||
219 | #else /* CONFIG_ROMFS_FS */ | ||
220 | lea _ebss,%a1 | ||
221 | movel %a1,_ramstart | ||
222 | #endif /* CONFIG_ROMFS_FS */ | ||
223 | |||
224 | |||
225 | /* | ||
226 | * Zero out the bss region. | ||
227 | */ | ||
228 | lea _sbss,%a0 /* get start of bss */ | ||
229 | lea _ebss,%a1 /* get end of bss */ | ||
230 | clrl %d0 /* set value */ | ||
231 | _clear_bss: | ||
232 | movel %d0,(%a0)+ /* clear each word */ | ||
233 | cmpl %a0,%a1 /* check if at end */ | ||
234 | bne _clear_bss | ||
235 | |||
236 | /* | ||
237 | * Load the current task pointer and stack. | ||
238 | */ | ||
239 | lea init_thread_union,%a0 | ||
240 | lea THREAD_SIZE(%a0),%sp | ||
241 | |||
242 | /* | ||
243 | * Assember start up done, start code proper. | ||
244 | */ | ||
245 | jsr start_kernel /* start Linux kernel */ | ||
246 | |||
247 | _exit: | ||
248 | jmp _exit /* should never get here */ | ||
249 | |||
250 | /*****************************************************************************/ | ||
diff --git a/arch/m68k/platform/coldfire/intc-2.c b/arch/m68k/platform/coldfire/intc-2.c new file mode 100644 index 000000000000..2cbfbf035db9 --- /dev/null +++ b/arch/m68k/platform/coldfire/intc-2.c | |||
@@ -0,0 +1,214 @@ | |||
1 | /* | ||
2 | * intc-2.c | ||
3 | * | ||
4 | * General interrupt controller code for the many ColdFire cores that use | ||
5 | * interrupt controllers with 63 interrupt sources, organized as 56 fully- | ||
6 | * programmable + 7 fixed-level interrupt sources. This includes the 523x | ||
7 | * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such | ||
8 | * controllers, and the 547x and 548x families which have only one of them. | ||
9 | * | ||
10 | * The external 7 fixed interrupts are part the the Edge Port unit of these | ||
11 | * ColdFire parts. They can be configured as level or edge triggered. | ||
12 | * | ||
13 | * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com> | ||
14 | * | ||
15 | * This file is subject to the terms and conditions of the GNU General Public | ||
16 | * License. See the file COPYING in the main directory of this archive | ||
17 | * for more details. | ||
18 | */ | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/irq.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <asm/coldfire.h> | ||
27 | #include <asm/mcfsim.h> | ||
28 | #include <asm/traps.h> | ||
29 | |||
30 | /* | ||
31 | * Bit definitions for the ICR family of registers. | ||
32 | */ | ||
33 | #define MCFSIM_ICR_LEVEL(l) ((l)<<3) /* Level l intr */ | ||
34 | #define MCFSIM_ICR_PRI(p) (p) /* Priority p intr */ | ||
35 | |||
36 | /* | ||
37 | * The EDGE Port interrupts are the fixed 7 external interrupts. | ||
38 | * They need some special treatment, for example they need to be acked. | ||
39 | */ | ||
40 | #define EINT0 64 /* Is not actually used, but spot reserved for it */ | ||
41 | #define EINT1 65 /* EDGE Port interrupt 1 */ | ||
42 | #define EINT7 71 /* EDGE Port interrupt 7 */ | ||
43 | |||
44 | #ifdef MCFICM_INTC1 | ||
45 | #define NR_VECS 128 | ||
46 | #else | ||
47 | #define NR_VECS 64 | ||
48 | #endif | ||
49 | |||
50 | static void intc_irq_mask(struct irq_data *d) | ||
51 | { | ||
52 | unsigned int irq = d->irq - MCFINT_VECBASE; | ||
53 | unsigned long imraddr; | ||
54 | u32 val, imrbit; | ||
55 | |||
56 | #ifdef MCFICM_INTC1 | ||
57 | imraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0; | ||
58 | #else | ||
59 | imraddr = MCFICM_INTC0; | ||
60 | #endif | ||
61 | imraddr += (irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL; | ||
62 | imrbit = 0x1 << (irq & 0x1f); | ||
63 | |||
64 | val = __raw_readl(imraddr); | ||
65 | __raw_writel(val | imrbit, imraddr); | ||
66 | } | ||
67 | |||
68 | static void intc_irq_unmask(struct irq_data *d) | ||
69 | { | ||
70 | unsigned int irq = d->irq - MCFINT_VECBASE; | ||
71 | unsigned long imraddr; | ||
72 | u32 val, imrbit; | ||
73 | |||
74 | #ifdef MCFICM_INTC1 | ||
75 | imraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0; | ||
76 | #else | ||
77 | imraddr = MCFICM_INTC0; | ||
78 | #endif | ||
79 | imraddr += ((irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL); | ||
80 | imrbit = 0x1 << (irq & 0x1f); | ||
81 | |||
82 | /* Don't set the "maskall" bit! */ | ||
83 | if ((irq & 0x20) == 0) | ||
84 | imrbit |= 0x1; | ||
85 | |||
86 | val = __raw_readl(imraddr); | ||
87 | __raw_writel(val & ~imrbit, imraddr); | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Only the external (or EDGE Port) interrupts need to be acknowledged | ||
92 | * here, as part of the IRQ handler. They only really need to be ack'ed | ||
93 | * if they are in edge triggered mode, but there is no harm in doing it | ||
94 | * for all types. | ||
95 | */ | ||
96 | static void intc_irq_ack(struct irq_data *d) | ||
97 | { | ||
98 | unsigned int irq = d->irq; | ||
99 | |||
100 | __raw_writeb(0x1 << (irq - EINT0), MCFEPORT_EPFR); | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * Each vector needs a unique priority and level associated with it. | ||
105 | * We don't really care so much what they are, we don't rely on the | ||
106 | * traditional priority interrupt scheme of the m68k/ColdFire. This | ||
107 | * only needs to be set once for an interrupt, and we will never change | ||
108 | * these values once we have set them. | ||
109 | */ | ||
110 | static u8 intc_intpri = MCFSIM_ICR_LEVEL(6) | MCFSIM_ICR_PRI(6); | ||
111 | |||
112 | static unsigned int intc_irq_startup(struct irq_data *d) | ||
113 | { | ||
114 | unsigned int irq = d->irq - MCFINT_VECBASE; | ||
115 | unsigned long icraddr; | ||
116 | |||
117 | #ifdef MCFICM_INTC1 | ||
118 | icraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0; | ||
119 | #else | ||
120 | icraddr = MCFICM_INTC0; | ||
121 | #endif | ||
122 | icraddr += MCFINTC_ICR0 + (irq & 0x3f); | ||
123 | if (__raw_readb(icraddr) == 0) | ||
124 | __raw_writeb(intc_intpri--, icraddr); | ||
125 | |||
126 | irq = d->irq; | ||
127 | if ((irq >= EINT1) && (irq <= EINT7)) { | ||
128 | u8 v; | ||
129 | |||
130 | irq -= EINT0; | ||
131 | |||
132 | /* Set EPORT line as input */ | ||
133 | v = __raw_readb(MCFEPORT_EPDDR); | ||
134 | __raw_writeb(v & ~(0x1 << irq), MCFEPORT_EPDDR); | ||
135 | |||
136 | /* Set EPORT line as interrupt source */ | ||
137 | v = __raw_readb(MCFEPORT_EPIER); | ||
138 | __raw_writeb(v | (0x1 << irq), MCFEPORT_EPIER); | ||
139 | } | ||
140 | |||
141 | intc_irq_unmask(d); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int intc_irq_set_type(struct irq_data *d, unsigned int type) | ||
146 | { | ||
147 | unsigned int irq = d->irq; | ||
148 | u16 pa, tb; | ||
149 | |||
150 | switch (type) { | ||
151 | case IRQ_TYPE_EDGE_RISING: | ||
152 | tb = 0x1; | ||
153 | break; | ||
154 | case IRQ_TYPE_EDGE_FALLING: | ||
155 | tb = 0x2; | ||
156 | break; | ||
157 | case IRQ_TYPE_EDGE_BOTH: | ||
158 | tb = 0x3; | ||
159 | break; | ||
160 | default: | ||
161 | /* Level triggered */ | ||
162 | tb = 0; | ||
163 | break; | ||
164 | } | ||
165 | |||
166 | if (tb) | ||
167 | set_irq_handler(irq, handle_edge_irq); | ||
168 | |||
169 | irq -= EINT0; | ||
170 | pa = __raw_readw(MCFEPORT_EPPAR); | ||
171 | pa = (pa & ~(0x3 << (irq * 2))) | (tb << (irq * 2)); | ||
172 | __raw_writew(pa, MCFEPORT_EPPAR); | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static struct irq_chip intc_irq_chip = { | ||
178 | .name = "CF-INTC", | ||
179 | .irq_startup = intc_irq_startup, | ||
180 | .irq_mask = intc_irq_mask, | ||
181 | .irq_unmask = intc_irq_unmask, | ||
182 | }; | ||
183 | |||
184 | static struct irq_chip intc_irq_chip_edge_port = { | ||
185 | .name = "CF-INTC-EP", | ||
186 | .irq_startup = intc_irq_startup, | ||
187 | .irq_mask = intc_irq_mask, | ||
188 | .irq_unmask = intc_irq_unmask, | ||
189 | .irq_ack = intc_irq_ack, | ||
190 | .irq_set_type = intc_irq_set_type, | ||
191 | }; | ||
192 | |||
193 | void __init init_IRQ(void) | ||
194 | { | ||
195 | int irq; | ||
196 | |||
197 | init_vectors(); | ||
198 | |||
199 | /* Mask all interrupt sources */ | ||
200 | __raw_writel(0x1, MCFICM_INTC0 + MCFINTC_IMRL); | ||
201 | #ifdef MCFICM_INTC1 | ||
202 | __raw_writel(0x1, MCFICM_INTC1 + MCFINTC_IMRL); | ||
203 | #endif | ||
204 | |||
205 | for (irq = MCFINT_VECBASE; (irq < MCFINT_VECBASE + NR_VECS); irq++) { | ||
206 | if ((irq >= EINT1) && (irq <=EINT7)) | ||
207 | set_irq_chip(irq, &intc_irq_chip_edge_port); | ||
208 | else | ||
209 | set_irq_chip(irq, &intc_irq_chip); | ||
210 | set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); | ||
211 | set_irq_handler(irq, handle_level_irq); | ||
212 | } | ||
213 | } | ||
214 | |||
diff --git a/arch/m68k/platform/coldfire/intc-simr.c b/arch/m68k/platform/coldfire/intc-simr.c new file mode 100644 index 000000000000..e642b24ab729 --- /dev/null +++ b/arch/m68k/platform/coldfire/intc-simr.c | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * intc-simr.c | ||
3 | * | ||
4 | * Interrupt controller code for the ColdFire 5208, 5207 & 532x parts. | ||
5 | * | ||
6 | * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com> | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file COPYING in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/types.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <asm/coldfire.h> | ||
20 | #include <asm/mcfsim.h> | ||
21 | #include <asm/traps.h> | ||
22 | |||
23 | /* | ||
24 | * The EDGE Port interrupts are the fixed 7 external interrupts. | ||
25 | * They need some special treatment, for example they need to be acked. | ||
26 | */ | ||
27 | #ifdef CONFIG_M520x | ||
28 | /* | ||
29 | * The 520x parts only support a limited range of these external | ||
30 | * interrupts, only 1, 4 and 7 (as interrupts 65, 66 and 67). | ||
31 | */ | ||
32 | #define EINT0 64 /* Is not actually used, but spot reserved for it */ | ||
33 | #define EINT1 65 /* EDGE Port interrupt 1 */ | ||
34 | #define EINT4 66 /* EDGE Port interrupt 4 */ | ||
35 | #define EINT7 67 /* EDGE Port interrupt 7 */ | ||
36 | |||
37 | static unsigned int irqebitmap[] = { 0, 1, 4, 7 }; | ||
38 | static unsigned int inline irq2ebit(unsigned int irq) | ||
39 | { | ||
40 | return irqebitmap[irq - EINT0]; | ||
41 | } | ||
42 | |||
43 | #else | ||
44 | |||
45 | /* | ||
46 | * Most of the ColdFire parts with the EDGE Port module just have | ||
47 | * a strait direct mapping of the 7 external interrupts. Although | ||
48 | * there is a bit reserved for 0, it is not used. | ||
49 | */ | ||
50 | #define EINT0 64 /* Is not actually used, but spot reserved for it */ | ||
51 | #define EINT1 65 /* EDGE Port interrupt 1 */ | ||
52 | #define EINT7 71 /* EDGE Port interrupt 7 */ | ||
53 | |||
54 | static unsigned int inline irq2ebit(unsigned int irq) | ||
55 | { | ||
56 | return irq - EINT0; | ||
57 | } | ||
58 | |||
59 | #endif | ||
60 | |||
61 | /* | ||
62 | * There maybe one or two interrupt control units, each has 64 | ||
63 | * interrupts. If there is no second unit then MCFINTC1_* defines | ||
64 | * will be 0 (and code for them optimized away). | ||
65 | */ | ||
66 | |||
67 | static void intc_irq_mask(struct irq_data *d) | ||
68 | { | ||
69 | unsigned int irq = d->irq - MCFINT_VECBASE; | ||
70 | |||
71 | if (MCFINTC1_SIMR && (irq > 64)) | ||
72 | __raw_writeb(irq - 64, MCFINTC1_SIMR); | ||
73 | else | ||
74 | __raw_writeb(irq, MCFINTC0_SIMR); | ||
75 | } | ||
76 | |||
77 | static void intc_irq_unmask(struct irq_data *d) | ||
78 | { | ||
79 | unsigned int irq = d->irq - MCFINT_VECBASE; | ||
80 | |||
81 | if (MCFINTC1_CIMR && (irq > 64)) | ||
82 | __raw_writeb(irq - 64, MCFINTC1_CIMR); | ||
83 | else | ||
84 | __raw_writeb(irq, MCFINTC0_CIMR); | ||
85 | } | ||
86 | |||
87 | static void intc_irq_ack(struct irq_data *d) | ||
88 | { | ||
89 | unsigned int ebit = irq2ebit(d->irq); | ||
90 | |||
91 | __raw_writeb(0x1 << ebit, MCFEPORT_EPFR); | ||
92 | } | ||
93 | |||
94 | static unsigned int intc_irq_startup(struct irq_data *d) | ||
95 | { | ||
96 | unsigned int irq = d->irq; | ||
97 | |||
98 | if ((irq >= EINT1) && (irq <= EINT7)) { | ||
99 | unsigned int ebit = irq2ebit(irq); | ||
100 | u8 v; | ||
101 | |||
102 | /* Set EPORT line as input */ | ||
103 | v = __raw_readb(MCFEPORT_EPDDR); | ||
104 | __raw_writeb(v & ~(0x1 << ebit), MCFEPORT_EPDDR); | ||
105 | |||
106 | /* Set EPORT line as interrupt source */ | ||
107 | v = __raw_readb(MCFEPORT_EPIER); | ||
108 | __raw_writeb(v | (0x1 << ebit), MCFEPORT_EPIER); | ||
109 | } | ||
110 | |||
111 | irq -= MCFINT_VECBASE; | ||
112 | if (MCFINTC1_ICR0 && (irq > 64)) | ||
113 | __raw_writeb(5, MCFINTC1_ICR0 + irq - 64); | ||
114 | else | ||
115 | __raw_writeb(5, MCFINTC0_ICR0 + irq); | ||
116 | |||
117 | |||
118 | intc_irq_unmask(d); | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static int intc_irq_set_type(struct irq_data *d, unsigned int type) | ||
123 | { | ||
124 | unsigned int ebit, irq = d->irq; | ||
125 | u16 pa, tb; | ||
126 | |||
127 | switch (type) { | ||
128 | case IRQ_TYPE_EDGE_RISING: | ||
129 | tb = 0x1; | ||
130 | break; | ||
131 | case IRQ_TYPE_EDGE_FALLING: | ||
132 | tb = 0x2; | ||
133 | break; | ||
134 | case IRQ_TYPE_EDGE_BOTH: | ||
135 | tb = 0x3; | ||
136 | break; | ||
137 | default: | ||
138 | /* Level triggered */ | ||
139 | tb = 0; | ||
140 | break; | ||
141 | } | ||
142 | |||
143 | if (tb) | ||
144 | set_irq_handler(irq, handle_edge_irq); | ||
145 | |||
146 | ebit = irq2ebit(irq) * 2; | ||
147 | pa = __raw_readw(MCFEPORT_EPPAR); | ||
148 | pa = (pa & ~(0x3 << ebit)) | (tb << ebit); | ||
149 | __raw_writew(pa, MCFEPORT_EPPAR); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static struct irq_chip intc_irq_chip = { | ||
155 | .name = "CF-INTC", | ||
156 | .irq_startup = intc_irq_startup, | ||
157 | .irq_mask = intc_irq_mask, | ||
158 | .irq_unmask = intc_irq_unmask, | ||
159 | }; | ||
160 | |||
161 | static struct irq_chip intc_irq_chip_edge_port = { | ||
162 | .name = "CF-INTC-EP", | ||
163 | .irq_startup = intc_irq_startup, | ||
164 | .irq_mask = intc_irq_mask, | ||
165 | .irq_unmask = intc_irq_unmask, | ||
166 | .irq_ack = intc_irq_ack, | ||
167 | .irq_set_type = intc_irq_set_type, | ||
168 | }; | ||
169 | |||
170 | void __init init_IRQ(void) | ||
171 | { | ||
172 | int irq, eirq; | ||
173 | |||
174 | init_vectors(); | ||
175 | |||
176 | /* Mask all interrupt sources */ | ||
177 | __raw_writeb(0xff, MCFINTC0_SIMR); | ||
178 | if (MCFINTC1_SIMR) | ||
179 | __raw_writeb(0xff, MCFINTC1_SIMR); | ||
180 | |||
181 | eirq = MCFINT_VECBASE + 64 + (MCFINTC1_ICR0 ? 64 : 0); | ||
182 | for (irq = MCFINT_VECBASE; (irq < eirq); irq++) { | ||
183 | if ((irq >= EINT1) && (irq <= EINT7)) | ||
184 | set_irq_chip(irq, &intc_irq_chip_edge_port); | ||
185 | else | ||
186 | set_irq_chip(irq, &intc_irq_chip); | ||
187 | set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); | ||
188 | set_irq_handler(irq, handle_level_irq); | ||
189 | } | ||
190 | } | ||
191 | |||
diff --git a/arch/m68k/platform/coldfire/intc.c b/arch/m68k/platform/coldfire/intc.c new file mode 100644 index 000000000000..d648081a63f6 --- /dev/null +++ b/arch/m68k/platform/coldfire/intc.c | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | * intc.c -- support for the old ColdFire interrupt controller | ||
3 | * | ||
4 | * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com> | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/types.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <asm/traps.h> | ||
18 | #include <asm/coldfire.h> | ||
19 | #include <asm/mcfsim.h> | ||
20 | |||
21 | /* | ||
22 | * The mapping of irq number to a mask register bit is not one-to-one. | ||
23 | * The irq numbers are either based on "level" of interrupt or fixed | ||
24 | * for an autovector-able interrupt. So we keep a local data structure | ||
25 | * that maps from irq to mask register. Not all interrupts will have | ||
26 | * an IMR bit. | ||
27 | */ | ||
28 | unsigned char mcf_irq2imr[NR_IRQS]; | ||
29 | |||
30 | /* | ||
31 | * Define the miniumun and maximum external interrupt numbers. | ||
32 | * This is also used as the "level" interrupt numbers. | ||
33 | */ | ||
34 | #define EIRQ1 25 | ||
35 | #define EIRQ7 31 | ||
36 | |||
37 | /* | ||
38 | * In the early version 2 core ColdFire parts the IMR register was 16 bits | ||
39 | * in size. Version 3 (and later version 2) core parts have a 32 bit | ||
40 | * sized IMR register. Provide some size independant methods to access the | ||
41 | * IMR register. | ||
42 | */ | ||
43 | #ifdef MCFSIM_IMR_IS_16BITS | ||
44 | |||
45 | void mcf_setimr(int index) | ||
46 | { | ||
47 | u16 imr; | ||
48 | imr = __raw_readw(MCF_MBAR + MCFSIM_IMR); | ||
49 | __raw_writew(imr | (0x1 << index), MCF_MBAR + MCFSIM_IMR); | ||
50 | } | ||
51 | |||
52 | void mcf_clrimr(int index) | ||
53 | { | ||
54 | u16 imr; | ||
55 | imr = __raw_readw(MCF_MBAR + MCFSIM_IMR); | ||
56 | __raw_writew(imr & ~(0x1 << index), MCF_MBAR + MCFSIM_IMR); | ||
57 | } | ||
58 | |||
59 | void mcf_maskimr(unsigned int mask) | ||
60 | { | ||
61 | u16 imr; | ||
62 | imr = __raw_readw(MCF_MBAR + MCFSIM_IMR); | ||
63 | imr |= mask; | ||
64 | __raw_writew(imr, MCF_MBAR + MCFSIM_IMR); | ||
65 | } | ||
66 | |||
67 | #else | ||
68 | |||
69 | void mcf_setimr(int index) | ||
70 | { | ||
71 | u32 imr; | ||
72 | imr = __raw_readl(MCF_MBAR + MCFSIM_IMR); | ||
73 | __raw_writel(imr | (0x1 << index), MCF_MBAR + MCFSIM_IMR); | ||
74 | } | ||
75 | |||
76 | void mcf_clrimr(int index) | ||
77 | { | ||
78 | u32 imr; | ||
79 | imr = __raw_readl(MCF_MBAR + MCFSIM_IMR); | ||
80 | __raw_writel(imr & ~(0x1 << index), MCF_MBAR + MCFSIM_IMR); | ||
81 | } | ||
82 | |||
83 | void mcf_maskimr(unsigned int mask) | ||
84 | { | ||
85 | u32 imr; | ||
86 | imr = __raw_readl(MCF_MBAR + MCFSIM_IMR); | ||
87 | imr |= mask; | ||
88 | __raw_writel(imr, MCF_MBAR + MCFSIM_IMR); | ||
89 | } | ||
90 | |||
91 | #endif | ||
92 | |||
93 | /* | ||
94 | * Interrupts can be "vectored" on the ColdFire cores that support this old | ||
95 | * interrupt controller. That is, the device raising the interrupt can also | ||
96 | * supply the vector number to interrupt through. The AVR register of the | ||
97 | * interrupt controller enables or disables this for each external interrupt, | ||
98 | * so provide generic support for this. Setting this up is out-of-band for | ||
99 | * the interrupt system API's, and needs to be done by the driver that | ||
100 | * supports this device. Very few devices actually use this. | ||
101 | */ | ||
102 | void mcf_autovector(int irq) | ||
103 | { | ||
104 | #ifdef MCFSIM_AVR | ||
105 | if ((irq >= EIRQ1) && (irq <= EIRQ7)) { | ||
106 | u8 avec; | ||
107 | avec = __raw_readb(MCF_MBAR + MCFSIM_AVR); | ||
108 | avec |= (0x1 << (irq - EIRQ1 + 1)); | ||
109 | __raw_writeb(avec, MCF_MBAR + MCFSIM_AVR); | ||
110 | } | ||
111 | #endif | ||
112 | } | ||
113 | |||
114 | static void intc_irq_mask(struct irq_data *d) | ||
115 | { | ||
116 | if (mcf_irq2imr[d->irq]) | ||
117 | mcf_setimr(mcf_irq2imr[d->irq]); | ||
118 | } | ||
119 | |||
120 | static void intc_irq_unmask(struct irq_data *d) | ||
121 | { | ||
122 | if (mcf_irq2imr[d->irq]) | ||
123 | mcf_clrimr(mcf_irq2imr[d->irq]); | ||
124 | } | ||
125 | |||
126 | static int intc_irq_set_type(struct irq_data *d, unsigned int type) | ||
127 | { | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static struct irq_chip intc_irq_chip = { | ||
132 | .name = "CF-INTC", | ||
133 | .irq_mask = intc_irq_mask, | ||
134 | .irq_unmask = intc_irq_unmask, | ||
135 | .irq_set_type = intc_irq_set_type, | ||
136 | }; | ||
137 | |||
138 | void __init init_IRQ(void) | ||
139 | { | ||
140 | int irq; | ||
141 | |||
142 | init_vectors(); | ||
143 | mcf_maskimr(0xffffffff); | ||
144 | |||
145 | for (irq = 0; (irq < NR_IRQS); irq++) { | ||
146 | set_irq_chip(irq, &intc_irq_chip); | ||
147 | set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); | ||
148 | set_irq_handler(irq, handle_level_irq); | ||
149 | } | ||
150 | } | ||
151 | |||
diff --git a/arch/m68k/platform/coldfire/pinmux.c b/arch/m68k/platform/coldfire/pinmux.c new file mode 100644 index 000000000000..8c62b825939f --- /dev/null +++ b/arch/m68k/platform/coldfire/pinmux.c | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Coldfire generic GPIO pinmux support. | ||
3 | * | ||
4 | * (C) Copyright 2009, Steven King <sfking@fdwdc.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | |||
19 | #include <asm/pinmux.h> | ||
20 | |||
21 | int mcf_pinmux_request(unsigned pinmux, unsigned func) | ||
22 | { | ||
23 | return 0; | ||
24 | } | ||
25 | |||
26 | void mcf_pinmux_release(unsigned pinmux, unsigned func) | ||
27 | { | ||
28 | } | ||
diff --git a/arch/m68k/platform/coldfire/pit.c b/arch/m68k/platform/coldfire/pit.c new file mode 100644 index 000000000000..c2b980926bec --- /dev/null +++ b/arch/m68k/platform/coldfire/pit.c | |||
@@ -0,0 +1,169 @@ | |||
1 | /***************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * pit.c -- Freescale ColdFire PIT timer. Currently this type of | ||
5 | * hardware timer only exists in the Freescale ColdFire | ||
6 | * 5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire | ||
7 | * family members will probably use it too. | ||
8 | * | ||
9 | * Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com) | ||
10 | * Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com) | ||
11 | */ | ||
12 | |||
13 | /***************************************************************************/ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/param.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <linux/clockchips.h> | ||
22 | #include <asm/machdep.h> | ||
23 | #include <asm/io.h> | ||
24 | #include <asm/coldfire.h> | ||
25 | #include <asm/mcfpit.h> | ||
26 | #include <asm/mcfsim.h> | ||
27 | |||
28 | /***************************************************************************/ | ||
29 | |||
30 | /* | ||
31 | * By default use timer1 as the system clock timer. | ||
32 | */ | ||
33 | #define FREQ ((MCF_CLK / 2) / 64) | ||
34 | #define TA(a) (MCFPIT_BASE1 + (a)) | ||
35 | #define PIT_CYCLES_PER_JIFFY (FREQ / HZ) | ||
36 | |||
37 | static u32 pit_cnt; | ||
38 | |||
39 | /* | ||
40 | * Initialize the PIT timer. | ||
41 | * | ||
42 | * This is also called after resume to bring the PIT into operation again. | ||
43 | */ | ||
44 | |||
45 | static void init_cf_pit_timer(enum clock_event_mode mode, | ||
46 | struct clock_event_device *evt) | ||
47 | { | ||
48 | switch (mode) { | ||
49 | case CLOCK_EVT_MODE_PERIODIC: | ||
50 | |||
51 | __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); | ||
52 | __raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR)); | ||
53 | __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \ | ||
54 | MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | \ | ||
55 | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR)); | ||
56 | break; | ||
57 | |||
58 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
59 | case CLOCK_EVT_MODE_UNUSED: | ||
60 | |||
61 | __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); | ||
62 | break; | ||
63 | |||
64 | case CLOCK_EVT_MODE_ONESHOT: | ||
65 | |||
66 | __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); | ||
67 | __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \ | ||
68 | MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, \ | ||
69 | TA(MCFPIT_PCSR)); | ||
70 | break; | ||
71 | |||
72 | case CLOCK_EVT_MODE_RESUME: | ||
73 | /* Nothing to do here */ | ||
74 | break; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * Program the next event in oneshot mode | ||
80 | * | ||
81 | * Delta is given in PIT ticks | ||
82 | */ | ||
83 | static int cf_pit_next_event(unsigned long delta, | ||
84 | struct clock_event_device *evt) | ||
85 | { | ||
86 | __raw_writew(delta, TA(MCFPIT_PMR)); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | struct clock_event_device cf_pit_clockevent = { | ||
91 | .name = "pit", | ||
92 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
93 | .set_mode = init_cf_pit_timer, | ||
94 | .set_next_event = cf_pit_next_event, | ||
95 | .shift = 32, | ||
96 | .irq = MCFINT_VECBASE + MCFINT_PIT1, | ||
97 | }; | ||
98 | |||
99 | |||
100 | |||
101 | /***************************************************************************/ | ||
102 | |||
103 | static irqreturn_t pit_tick(int irq, void *dummy) | ||
104 | { | ||
105 | struct clock_event_device *evt = &cf_pit_clockevent; | ||
106 | u16 pcsr; | ||
107 | |||
108 | /* Reset the ColdFire timer */ | ||
109 | pcsr = __raw_readw(TA(MCFPIT_PCSR)); | ||
110 | __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR)); | ||
111 | |||
112 | pit_cnt += PIT_CYCLES_PER_JIFFY; | ||
113 | evt->event_handler(evt); | ||
114 | return IRQ_HANDLED; | ||
115 | } | ||
116 | |||
117 | /***************************************************************************/ | ||
118 | |||
119 | static struct irqaction pit_irq = { | ||
120 | .name = "timer", | ||
121 | .flags = IRQF_DISABLED | IRQF_TIMER, | ||
122 | .handler = pit_tick, | ||
123 | }; | ||
124 | |||
125 | /***************************************************************************/ | ||
126 | |||
127 | static cycle_t pit_read_clk(struct clocksource *cs) | ||
128 | { | ||
129 | unsigned long flags; | ||
130 | u32 cycles; | ||
131 | u16 pcntr; | ||
132 | |||
133 | local_irq_save(flags); | ||
134 | pcntr = __raw_readw(TA(MCFPIT_PCNTR)); | ||
135 | cycles = pit_cnt; | ||
136 | local_irq_restore(flags); | ||
137 | |||
138 | return cycles + PIT_CYCLES_PER_JIFFY - pcntr; | ||
139 | } | ||
140 | |||
141 | /***************************************************************************/ | ||
142 | |||
143 | static struct clocksource pit_clk = { | ||
144 | .name = "pit", | ||
145 | .rating = 100, | ||
146 | .read = pit_read_clk, | ||
147 | .shift = 20, | ||
148 | .mask = CLOCKSOURCE_MASK(32), | ||
149 | }; | ||
150 | |||
151 | /***************************************************************************/ | ||
152 | |||
153 | void hw_timer_init(void) | ||
154 | { | ||
155 | cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id()); | ||
156 | cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32); | ||
157 | cf_pit_clockevent.max_delta_ns = | ||
158 | clockevent_delta2ns(0xFFFF, &cf_pit_clockevent); | ||
159 | cf_pit_clockevent.min_delta_ns = | ||
160 | clockevent_delta2ns(0x3f, &cf_pit_clockevent); | ||
161 | clockevents_register_device(&cf_pit_clockevent); | ||
162 | |||
163 | setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq); | ||
164 | |||
165 | pit_clk.mult = clocksource_hz2mult(FREQ, pit_clk.shift); | ||
166 | clocksource_register(&pit_clk); | ||
167 | } | ||
168 | |||
169 | /***************************************************************************/ | ||
diff --git a/arch/m68k/platform/coldfire/sltimers.c b/arch/m68k/platform/coldfire/sltimers.c new file mode 100644 index 000000000000..0a1b937c3e18 --- /dev/null +++ b/arch/m68k/platform/coldfire/sltimers.c | |||
@@ -0,0 +1,145 @@ | |||
1 | /***************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * sltimers.c -- generic ColdFire slice timer support. | ||
5 | * | ||
6 | * Copyright (C) 2009-2010, Philippe De Muyter <phdm@macqel.be> | ||
7 | * based on | ||
8 | * timers.c -- generic ColdFire hardware timer support. | ||
9 | * Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com> | ||
10 | */ | ||
11 | |||
12 | /***************************************************************************/ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/irq.h> | ||
19 | #include <linux/profile.h> | ||
20 | #include <linux/clocksource.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/traps.h> | ||
23 | #include <asm/machdep.h> | ||
24 | #include <asm/coldfire.h> | ||
25 | #include <asm/mcfslt.h> | ||
26 | #include <asm/mcfsim.h> | ||
27 | |||
28 | /***************************************************************************/ | ||
29 | |||
30 | #ifdef CONFIG_HIGHPROFILE | ||
31 | |||
32 | /* | ||
33 | * By default use Slice Timer 1 as the profiler clock timer. | ||
34 | */ | ||
35 | #define PA(a) (MCF_MBAR + MCFSLT_TIMER1 + (a)) | ||
36 | |||
37 | /* | ||
38 | * Choose a reasonably fast profile timer. Make it an odd value to | ||
39 | * try and get good coverage of kernel operations. | ||
40 | */ | ||
41 | #define PROFILEHZ 1013 | ||
42 | |||
43 | irqreturn_t mcfslt_profile_tick(int irq, void *dummy) | ||
44 | { | ||
45 | /* Reset Slice Timer 1 */ | ||
46 | __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, PA(MCFSLT_SSR)); | ||
47 | if (current->pid) | ||
48 | profile_tick(CPU_PROFILING); | ||
49 | return IRQ_HANDLED; | ||
50 | } | ||
51 | |||
52 | static struct irqaction mcfslt_profile_irq = { | ||
53 | .name = "profile timer", | ||
54 | .flags = IRQF_DISABLED | IRQF_TIMER, | ||
55 | .handler = mcfslt_profile_tick, | ||
56 | }; | ||
57 | |||
58 | void mcfslt_profile_init(void) | ||
59 | { | ||
60 | printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n", | ||
61 | PROFILEHZ); | ||
62 | |||
63 | setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq); | ||
64 | |||
65 | /* Set up TIMER 2 as high speed profile clock */ | ||
66 | __raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT)); | ||
67 | __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN, | ||
68 | PA(MCFSLT_SCR)); | ||
69 | |||
70 | } | ||
71 | |||
72 | #endif /* CONFIG_HIGHPROFILE */ | ||
73 | |||
74 | /***************************************************************************/ | ||
75 | |||
76 | /* | ||
77 | * By default use Slice Timer 0 as the system clock timer. | ||
78 | */ | ||
79 | #define TA(a) (MCF_MBAR + MCFSLT_TIMER0 + (a)) | ||
80 | |||
81 | static u32 mcfslt_cycles_per_jiffy; | ||
82 | static u32 mcfslt_cnt; | ||
83 | |||
84 | static irqreturn_t mcfslt_tick(int irq, void *dummy) | ||
85 | { | ||
86 | /* Reset Slice Timer 0 */ | ||
87 | __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR)); | ||
88 | mcfslt_cnt += mcfslt_cycles_per_jiffy; | ||
89 | return arch_timer_interrupt(irq, dummy); | ||
90 | } | ||
91 | |||
92 | static struct irqaction mcfslt_timer_irq = { | ||
93 | .name = "timer", | ||
94 | .flags = IRQF_DISABLED | IRQF_TIMER, | ||
95 | .handler = mcfslt_tick, | ||
96 | }; | ||
97 | |||
98 | static cycle_t mcfslt_read_clk(struct clocksource *cs) | ||
99 | { | ||
100 | unsigned long flags; | ||
101 | u32 cycles; | ||
102 | u16 scnt; | ||
103 | |||
104 | local_irq_save(flags); | ||
105 | scnt = __raw_readl(TA(MCFSLT_SCNT)); | ||
106 | cycles = mcfslt_cnt; | ||
107 | local_irq_restore(flags); | ||
108 | |||
109 | /* substract because slice timers count down */ | ||
110 | return cycles - scnt; | ||
111 | } | ||
112 | |||
113 | static struct clocksource mcfslt_clk = { | ||
114 | .name = "slt", | ||
115 | .rating = 250, | ||
116 | .read = mcfslt_read_clk, | ||
117 | .shift = 20, | ||
118 | .mask = CLOCKSOURCE_MASK(32), | ||
119 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
120 | }; | ||
121 | |||
122 | void hw_timer_init(void) | ||
123 | { | ||
124 | mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ; | ||
125 | /* | ||
126 | * The coldfire slice timer (SLT) runs from STCNT to 0 included, | ||
127 | * then STCNT again and so on. It counts thus actually | ||
128 | * STCNT + 1 steps for 1 tick, not STCNT. So if you want | ||
129 | * n cycles, initialize STCNT with n - 1. | ||
130 | */ | ||
131 | __raw_writel(mcfslt_cycles_per_jiffy - 1, TA(MCFSLT_STCNT)); | ||
132 | __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN, | ||
133 | TA(MCFSLT_SCR)); | ||
134 | /* initialize mcfslt_cnt knowing that slice timers count down */ | ||
135 | mcfslt_cnt = mcfslt_cycles_per_jiffy; | ||
136 | |||
137 | setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq); | ||
138 | |||
139 | mcfslt_clk.mult = clocksource_hz2mult(MCF_BUSCLK, mcfslt_clk.shift); | ||
140 | clocksource_register(&mcfslt_clk); | ||
141 | |||
142 | #ifdef CONFIG_HIGHPROFILE | ||
143 | mcfslt_profile_init(); | ||
144 | #endif | ||
145 | } | ||
diff --git a/arch/m68k/platform/coldfire/timers.c b/arch/m68k/platform/coldfire/timers.c new file mode 100644 index 000000000000..60242f65fea9 --- /dev/null +++ b/arch/m68k/platform/coldfire/timers.c | |||
@@ -0,0 +1,174 @@ | |||
1 | /***************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * timers.c -- generic ColdFire hardware timer support. | ||
5 | * | ||
6 | * Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com> | ||
7 | */ | ||
8 | |||
9 | /***************************************************************************/ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <linux/profile.h> | ||
17 | #include <linux/clocksource.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <asm/traps.h> | ||
20 | #include <asm/machdep.h> | ||
21 | #include <asm/coldfire.h> | ||
22 | #include <asm/mcftimer.h> | ||
23 | #include <asm/mcfsim.h> | ||
24 | |||
25 | /***************************************************************************/ | ||
26 | |||
27 | /* | ||
28 | * By default use timer1 as the system clock timer. | ||
29 | */ | ||
30 | #define FREQ (MCF_BUSCLK / 16) | ||
31 | #define TA(a) (MCFTIMER_BASE1 + (a)) | ||
32 | |||
33 | /* | ||
34 | * These provide the underlying interrupt vector support. | ||
35 | * Unfortunately it is a little different on each ColdFire. | ||
36 | */ | ||
37 | void coldfire_profile_init(void); | ||
38 | |||
39 | #if defined(CONFIG_M532x) | ||
40 | #define __raw_readtrr __raw_readl | ||
41 | #define __raw_writetrr __raw_writel | ||
42 | #else | ||
43 | #define __raw_readtrr __raw_readw | ||
44 | #define __raw_writetrr __raw_writew | ||
45 | #endif | ||
46 | |||
47 | static u32 mcftmr_cycles_per_jiffy; | ||
48 | static u32 mcftmr_cnt; | ||
49 | |||
50 | /***************************************************************************/ | ||
51 | |||
52 | static irqreturn_t mcftmr_tick(int irq, void *dummy) | ||
53 | { | ||
54 | /* Reset the ColdFire timer */ | ||
55 | __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER)); | ||
56 | |||
57 | mcftmr_cnt += mcftmr_cycles_per_jiffy; | ||
58 | return arch_timer_interrupt(irq, dummy); | ||
59 | } | ||
60 | |||
61 | /***************************************************************************/ | ||
62 | |||
63 | static struct irqaction mcftmr_timer_irq = { | ||
64 | .name = "timer", | ||
65 | .flags = IRQF_DISABLED | IRQF_TIMER, | ||
66 | .handler = mcftmr_tick, | ||
67 | }; | ||
68 | |||
69 | /***************************************************************************/ | ||
70 | |||
71 | static cycle_t mcftmr_read_clk(struct clocksource *cs) | ||
72 | { | ||
73 | unsigned long flags; | ||
74 | u32 cycles; | ||
75 | u16 tcn; | ||
76 | |||
77 | local_irq_save(flags); | ||
78 | tcn = __raw_readw(TA(MCFTIMER_TCN)); | ||
79 | cycles = mcftmr_cnt; | ||
80 | local_irq_restore(flags); | ||
81 | |||
82 | return cycles + tcn; | ||
83 | } | ||
84 | |||
85 | /***************************************************************************/ | ||
86 | |||
87 | static struct clocksource mcftmr_clk = { | ||
88 | .name = "tmr", | ||
89 | .rating = 250, | ||
90 | .read = mcftmr_read_clk, | ||
91 | .shift = 20, | ||
92 | .mask = CLOCKSOURCE_MASK(32), | ||
93 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
94 | }; | ||
95 | |||
96 | /***************************************************************************/ | ||
97 | |||
98 | void hw_timer_init(void) | ||
99 | { | ||
100 | __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); | ||
101 | mcftmr_cycles_per_jiffy = FREQ / HZ; | ||
102 | /* | ||
103 | * The coldfire timer runs from 0 to TRR included, then 0 | ||
104 | * again and so on. It counts thus actually TRR + 1 steps | ||
105 | * for 1 tick, not TRR. So if you want n cycles, | ||
106 | * initialize TRR with n - 1. | ||
107 | */ | ||
108 | __raw_writetrr(mcftmr_cycles_per_jiffy - 1, TA(MCFTIMER_TRR)); | ||
109 | __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | | ||
110 | MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR)); | ||
111 | |||
112 | mcftmr_clk.mult = clocksource_hz2mult(FREQ, mcftmr_clk.shift); | ||
113 | clocksource_register(&mcftmr_clk); | ||
114 | |||
115 | setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq); | ||
116 | |||
117 | #ifdef CONFIG_HIGHPROFILE | ||
118 | coldfire_profile_init(); | ||
119 | #endif | ||
120 | } | ||
121 | |||
122 | /***************************************************************************/ | ||
123 | #ifdef CONFIG_HIGHPROFILE | ||
124 | /***************************************************************************/ | ||
125 | |||
126 | /* | ||
127 | * By default use timer2 as the profiler clock timer. | ||
128 | */ | ||
129 | #define PA(a) (MCFTIMER_BASE2 + (a)) | ||
130 | |||
131 | /* | ||
132 | * Choose a reasonably fast profile timer. Make it an odd value to | ||
133 | * try and get good coverage of kernel operations. | ||
134 | */ | ||
135 | #define PROFILEHZ 1013 | ||
136 | |||
137 | /* | ||
138 | * Use the other timer to provide high accuracy profiling info. | ||
139 | */ | ||
140 | irqreturn_t coldfire_profile_tick(int irq, void *dummy) | ||
141 | { | ||
142 | /* Reset ColdFire timer2 */ | ||
143 | __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER)); | ||
144 | if (current->pid) | ||
145 | profile_tick(CPU_PROFILING); | ||
146 | return IRQ_HANDLED; | ||
147 | } | ||
148 | |||
149 | /***************************************************************************/ | ||
150 | |||
151 | static struct irqaction coldfire_profile_irq = { | ||
152 | .name = "profile timer", | ||
153 | .flags = IRQF_DISABLED | IRQF_TIMER, | ||
154 | .handler = coldfire_profile_tick, | ||
155 | }; | ||
156 | |||
157 | void coldfire_profile_init(void) | ||
158 | { | ||
159 | printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n", | ||
160 | PROFILEHZ); | ||
161 | |||
162 | /* Set up TIMER 2 as high speed profile clock */ | ||
163 | __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR)); | ||
164 | |||
165 | __raw_writetrr(((MCF_BUSCLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR)); | ||
166 | __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | | ||
167 | MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR)); | ||
168 | |||
169 | setup_irq(MCF_IRQ_PROFILER, &coldfire_profile_irq); | ||
170 | } | ||
171 | |||
172 | /***************************************************************************/ | ||
173 | #endif /* CONFIG_HIGHPROFILE */ | ||
174 | /***************************************************************************/ | ||
diff --git a/arch/m68k/platform/coldfire/vectors.c b/arch/m68k/platform/coldfire/vectors.c new file mode 100644 index 000000000000..a21d3f870b7a --- /dev/null +++ b/arch/m68k/platform/coldfire/vectors.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /***************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * linux/arch/m68knommu/platform/coldfire/vectors.c | ||
5 | * | ||
6 | * Copyright (C) 1999-2007, Greg Ungerer <gerg@snapgear.com> | ||
7 | */ | ||
8 | |||
9 | /***************************************************************************/ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/irq.h> | ||
14 | #include <asm/traps.h> | ||
15 | #include <asm/machdep.h> | ||
16 | #include <asm/coldfire.h> | ||
17 | #include <asm/mcfsim.h> | ||
18 | #include <asm/mcfwdebug.h> | ||
19 | |||
20 | /***************************************************************************/ | ||
21 | |||
22 | #ifdef TRAP_DBG_INTERRUPT | ||
23 | |||
24 | asmlinkage void dbginterrupt_c(struct frame *fp) | ||
25 | { | ||
26 | extern void dump(struct pt_regs *fp); | ||
27 | printk(KERN_DEBUG "%s(%d): BUS ERROR TRAP\n", __FILE__, __LINE__); | ||
28 | dump((struct pt_regs *) fp); | ||
29 | asm("halt"); | ||
30 | } | ||
31 | |||
32 | #endif | ||
33 | |||
34 | /***************************************************************************/ | ||
35 | |||
36 | extern e_vector *_ramvec; | ||
37 | |||
38 | void set_evector(int vecnum, void (*handler)(void)) | ||
39 | { | ||
40 | if (vecnum >= 0 && vecnum <= 255) | ||
41 | _ramvec[vecnum] = handler; | ||
42 | } | ||
43 | |||
44 | /***************************************************************************/ | ||
45 | |||
46 | /* Assembler routines */ | ||
47 | asmlinkage void buserr(void); | ||
48 | asmlinkage void trap(void); | ||
49 | asmlinkage void system_call(void); | ||
50 | asmlinkage void inthandler(void); | ||
51 | |||
52 | void __init init_vectors(void) | ||
53 | { | ||
54 | int i; | ||
55 | |||
56 | /* | ||
57 | * There is a common trap handler and common interrupt | ||
58 | * handler that handle almost every vector. We treat | ||
59 | * the system call and bus error special, they get their | ||
60 | * own first level handlers. | ||
61 | */ | ||
62 | for (i = 3; (i <= 23); i++) | ||
63 | _ramvec[i] = trap; | ||
64 | for (i = 33; (i <= 63); i++) | ||
65 | _ramvec[i] = trap; | ||
66 | for (i = 24; (i <= 31); i++) | ||
67 | _ramvec[i] = inthandler; | ||
68 | for (i = 64; (i < 255); i++) | ||
69 | _ramvec[i] = inthandler; | ||
70 | _ramvec[255] = 0; | ||
71 | |||
72 | _ramvec[2] = buserr; | ||
73 | _ramvec[32] = system_call; | ||
74 | |||
75 | #ifdef TRAP_DBG_INTERRUPT | ||
76 | _ramvec[12] = dbginterrupt; | ||
77 | #endif | ||
78 | } | ||
79 | |||
80 | /***************************************************************************/ | ||