diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/mips/vr41xx |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/mips/vr41xx')
26 files changed, 3315 insertions, 0 deletions
diff --git a/arch/mips/vr41xx/casio-e55/Makefile b/arch/mips/vr41xx/casio-e55/Makefile new file mode 100644 index 000000000000..d4c03cc8eb05 --- /dev/null +++ b/arch/mips/vr41xx/casio-e55/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for the CASIO CASSIOPEIA E-55/65 specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y += setup.o | ||
diff --git a/arch/mips/vr41xx/casio-e55/setup.c b/arch/mips/vr41xx/casio-e55/setup.c new file mode 100644 index 000000000000..aa8605ab76ff --- /dev/null +++ b/arch/mips/vr41xx/casio-e55/setup.c | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * setup.c, Setup for the CASIO CASSIOPEIA E-11/15/55/65. | ||
3 | * | ||
4 | * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
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; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/ioport.h> | ||
22 | |||
23 | #include <asm/io.h> | ||
24 | #include <asm/vr41xx/e55.h> | ||
25 | |||
26 | const char *get_system_type(void) | ||
27 | { | ||
28 | return "CASIO CASSIOPEIA E-11/15/55/65"; | ||
29 | } | ||
30 | |||
31 | static int __init casio_e55_setup(void) | ||
32 | { | ||
33 | set_io_port_base(IO_PORT_BASE); | ||
34 | ioport_resource.start = IO_PORT_RESOURCE_START; | ||
35 | ioport_resource.end = IO_PORT_RESOURCE_END; | ||
36 | |||
37 | return 0; | ||
38 | } | ||
39 | |||
40 | arch_initcall(casio_e55_setup); | ||
diff --git a/arch/mips/vr41xx/common/Makefile b/arch/mips/vr41xx/common/Makefile new file mode 100644 index 000000000000..92c11e9bbb3f --- /dev/null +++ b/arch/mips/vr41xx/common/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for common code of the NEC VR4100 series. | ||
3 | # | ||
4 | |||
5 | obj-y += bcu.o cmu.o giu.o icu.o init.o int-handler.o pmu.o | ||
6 | obj-$(CONFIG_VRC4173) += vrc4173.o | ||
7 | |||
8 | EXTRA_AFLAGS := $(CFLAGS) | ||
diff --git a/arch/mips/vr41xx/common/bcu.c b/arch/mips/vr41xx/common/bcu.c new file mode 100644 index 000000000000..cdfa4273a1c5 --- /dev/null +++ b/arch/mips/vr41xx/common/bcu.c | |||
@@ -0,0 +1,222 @@ | |||
1 | /* | ||
2 | * bcu.c, Bus Control Unit routines for the NEC VR4100 series. | ||
3 | * | ||
4 | * Copyright (C) 2002 MontaVista Software Inc. | ||
5 | * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com> | ||
6 | * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | /* | ||
23 | * Changes: | ||
24 | * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com> | ||
25 | * - New creation, NEC VR4122 and VR4131 are supported. | ||
26 | * - Added support for NEC VR4111 and VR4121. | ||
27 | * | ||
28 | * Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
29 | * - Added support for NEC VR4133. | ||
30 | */ | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/smp.h> | ||
34 | #include <linux/types.h> | ||
35 | |||
36 | #include <asm/cpu.h> | ||
37 | #include <asm/io.h> | ||
38 | |||
39 | #define CLKSPEEDREG_TYPE1 (void __iomem *)KSEG1ADDR(0x0b000014) | ||
40 | #define CLKSPEEDREG_TYPE2 (void __iomem *)KSEG1ADDR(0x0f000014) | ||
41 | #define CLKSP(x) ((x) & 0x001f) | ||
42 | #define CLKSP_VR4133(x) ((x) & 0x0007) | ||
43 | |||
44 | #define DIV2B 0x8000 | ||
45 | #define DIV3B 0x4000 | ||
46 | #define DIV4B 0x2000 | ||
47 | |||
48 | #define DIVT(x) (((x) & 0xf000) >> 12) | ||
49 | #define DIVVT(x) (((x) & 0x0f00) >> 8) | ||
50 | |||
51 | #define TDIVMODE(x) (2 << (((x) & 0x1000) >> 12)) | ||
52 | #define VTDIVMODE(x) (((x) & 0x0700) >> 8) | ||
53 | |||
54 | static unsigned long vr41xx_vtclock; | ||
55 | static unsigned long vr41xx_tclock; | ||
56 | |||
57 | unsigned long vr41xx_get_vtclock_frequency(void) | ||
58 | { | ||
59 | return vr41xx_vtclock; | ||
60 | } | ||
61 | |||
62 | EXPORT_SYMBOL_GPL(vr41xx_get_vtclock_frequency); | ||
63 | |||
64 | unsigned long vr41xx_get_tclock_frequency(void) | ||
65 | { | ||
66 | return vr41xx_tclock; | ||
67 | } | ||
68 | |||
69 | EXPORT_SYMBOL_GPL(vr41xx_get_tclock_frequency); | ||
70 | |||
71 | static inline uint16_t read_clkspeed(void) | ||
72 | { | ||
73 | switch (current_cpu_data.cputype) { | ||
74 | case CPU_VR4111: | ||
75 | case CPU_VR4121: return readw(CLKSPEEDREG_TYPE1); | ||
76 | case CPU_VR4122: | ||
77 | case CPU_VR4131: | ||
78 | case CPU_VR4133: return readw(CLKSPEEDREG_TYPE2); | ||
79 | default: | ||
80 | printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); | ||
81 | break; | ||
82 | } | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static inline unsigned long calculate_pclock(uint16_t clkspeed) | ||
88 | { | ||
89 | unsigned long pclock = 0; | ||
90 | |||
91 | switch (current_cpu_data.cputype) { | ||
92 | case CPU_VR4111: | ||
93 | case CPU_VR4121: | ||
94 | pclock = 18432000 * 64; | ||
95 | pclock /= CLKSP(clkspeed); | ||
96 | break; | ||
97 | case CPU_VR4122: | ||
98 | pclock = 18432000 * 98; | ||
99 | pclock /= CLKSP(clkspeed); | ||
100 | break; | ||
101 | case CPU_VR4131: | ||
102 | pclock = 18432000 * 108; | ||
103 | pclock /= CLKSP(clkspeed); | ||
104 | break; | ||
105 | case CPU_VR4133: | ||
106 | switch (CLKSP_VR4133(clkspeed)) { | ||
107 | case 0: | ||
108 | pclock = 133000000; | ||
109 | break; | ||
110 | case 1: | ||
111 | pclock = 149000000; | ||
112 | break; | ||
113 | case 2: | ||
114 | pclock = 165900000; | ||
115 | break; | ||
116 | case 3: | ||
117 | pclock = 199100000; | ||
118 | break; | ||
119 | case 4: | ||
120 | pclock = 265900000; | ||
121 | break; | ||
122 | default: | ||
123 | printk(KERN_INFO "Unknown PClock speed for NEC VR4133\n"); | ||
124 | break; | ||
125 | } | ||
126 | break; | ||
127 | default: | ||
128 | printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); | ||
129 | break; | ||
130 | } | ||
131 | |||
132 | printk(KERN_INFO "PClock: %ldHz\n", pclock); | ||
133 | |||
134 | return pclock; | ||
135 | } | ||
136 | |||
137 | static inline unsigned long calculate_vtclock(uint16_t clkspeed, unsigned long pclock) | ||
138 | { | ||
139 | unsigned long vtclock = 0; | ||
140 | |||
141 | switch (current_cpu_data.cputype) { | ||
142 | case CPU_VR4111: | ||
143 | /* The NEC VR4111 doesn't have the VTClock. */ | ||
144 | break; | ||
145 | case CPU_VR4121: | ||
146 | vtclock = pclock; | ||
147 | /* DIVVT == 9 Divide by 1.5 . VTClock = (PClock * 6) / 9 */ | ||
148 | if (DIVVT(clkspeed) == 9) | ||
149 | vtclock = pclock * 6; | ||
150 | /* DIVVT == 10 Divide by 2.5 . VTClock = (PClock * 4) / 10 */ | ||
151 | else if (DIVVT(clkspeed) == 10) | ||
152 | vtclock = pclock * 4; | ||
153 | vtclock /= DIVVT(clkspeed); | ||
154 | printk(KERN_INFO "VTClock: %ldHz\n", vtclock); | ||
155 | break; | ||
156 | case CPU_VR4122: | ||
157 | if(VTDIVMODE(clkspeed) == 7) | ||
158 | vtclock = pclock / 1; | ||
159 | else if(VTDIVMODE(clkspeed) == 1) | ||
160 | vtclock = pclock / 2; | ||
161 | else | ||
162 | vtclock = pclock / VTDIVMODE(clkspeed); | ||
163 | printk(KERN_INFO "VTClock: %ldHz\n", vtclock); | ||
164 | break; | ||
165 | case CPU_VR4131: | ||
166 | case CPU_VR4133: | ||
167 | vtclock = pclock / VTDIVMODE(clkspeed); | ||
168 | printk(KERN_INFO "VTClock: %ldHz\n", vtclock); | ||
169 | break; | ||
170 | default: | ||
171 | printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); | ||
172 | break; | ||
173 | } | ||
174 | |||
175 | return vtclock; | ||
176 | } | ||
177 | |||
178 | static inline unsigned long calculate_tclock(uint16_t clkspeed, unsigned long pclock, | ||
179 | unsigned long vtclock) | ||
180 | { | ||
181 | unsigned long tclock = 0; | ||
182 | |||
183 | switch (current_cpu_data.cputype) { | ||
184 | case CPU_VR4111: | ||
185 | if (!(clkspeed & DIV2B)) | ||
186 | tclock = pclock / 2; | ||
187 | else if (!(clkspeed & DIV3B)) | ||
188 | tclock = pclock / 3; | ||
189 | else if (!(clkspeed & DIV4B)) | ||
190 | tclock = pclock / 4; | ||
191 | break; | ||
192 | case CPU_VR4121: | ||
193 | tclock = pclock / DIVT(clkspeed); | ||
194 | break; | ||
195 | case CPU_VR4122: | ||
196 | case CPU_VR4131: | ||
197 | case CPU_VR4133: | ||
198 | tclock = vtclock / TDIVMODE(clkspeed); | ||
199 | break; | ||
200 | default: | ||
201 | printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); | ||
202 | break; | ||
203 | } | ||
204 | |||
205 | printk(KERN_INFO "TClock: %ldHz\n", tclock); | ||
206 | |||
207 | return tclock; | ||
208 | } | ||
209 | |||
210 | void vr41xx_calculate_clock_frequency(void) | ||
211 | { | ||
212 | unsigned long pclock; | ||
213 | uint16_t clkspeed; | ||
214 | |||
215 | clkspeed = read_clkspeed(); | ||
216 | |||
217 | pclock = calculate_pclock(clkspeed); | ||
218 | vr41xx_vtclock = calculate_vtclock(clkspeed, pclock); | ||
219 | vr41xx_tclock = calculate_tclock(clkspeed, pclock, vr41xx_vtclock); | ||
220 | } | ||
221 | |||
222 | EXPORT_SYMBOL_GPL(vr41xx_calculate_clock_frequency); | ||
diff --git a/arch/mips/vr41xx/common/cmu.c b/arch/mips/vr41xx/common/cmu.c new file mode 100644 index 000000000000..fcd3cb8cdd9d --- /dev/null +++ b/arch/mips/vr41xx/common/cmu.c | |||
@@ -0,0 +1,257 @@ | |||
1 | /* | ||
2 | * cmu.c, Clock Mask Unit routines for the NEC VR4100 series. | ||
3 | * | ||
4 | * Copyright (C) 2001-2002 MontaVista Software Inc. | ||
5 | * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com> | ||
6 | * Copuright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | /* | ||
23 | * Changes: | ||
24 | * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com> | ||
25 | * - New creation, NEC VR4122 and VR4131 are supported. | ||
26 | * - Added support for NEC VR4111 and VR4121. | ||
27 | * | ||
28 | * Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
29 | * - Added support for NEC VR4133. | ||
30 | */ | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/ioport.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/smp.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/types.h> | ||
37 | |||
38 | #include <asm/cpu.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <asm/vr41xx/vr41xx.h> | ||
41 | |||
42 | #define CMU_TYPE1_BASE 0x0b000060UL | ||
43 | #define CMU_TYPE1_SIZE 0x4 | ||
44 | |||
45 | #define CMU_TYPE2_BASE 0x0f000060UL | ||
46 | #define CMU_TYPE2_SIZE 0x4 | ||
47 | |||
48 | #define CMU_TYPE3_BASE 0x0f000060UL | ||
49 | #define CMU_TYPE3_SIZE 0x8 | ||
50 | |||
51 | #define CMUCLKMSK 0x0 | ||
52 | #define MSKPIU 0x0001 | ||
53 | #define MSKSIU 0x0002 | ||
54 | #define MSKAIU 0x0004 | ||
55 | #define MSKKIU 0x0008 | ||
56 | #define MSKFIR 0x0010 | ||
57 | #define MSKDSIU 0x0820 | ||
58 | #define MSKCSI 0x0040 | ||
59 | #define MSKPCIU 0x0080 | ||
60 | #define MSKSSIU 0x0100 | ||
61 | #define MSKSHSP 0x0200 | ||
62 | #define MSKFFIR 0x0400 | ||
63 | #define MSKSCSI 0x1000 | ||
64 | #define MSKPPCIU 0x2000 | ||
65 | #define CMUCLKMSK2 0x4 | ||
66 | #define MSKCEU 0x0001 | ||
67 | #define MSKMAC0 0x0002 | ||
68 | #define MSKMAC1 0x0004 | ||
69 | |||
70 | static void __iomem *cmu_base; | ||
71 | static uint16_t cmuclkmsk, cmuclkmsk2; | ||
72 | static spinlock_t cmu_lock; | ||
73 | |||
74 | #define cmu_read(offset) readw(cmu_base + (offset)) | ||
75 | #define cmu_write(offset, value) writew((value), cmu_base + (offset)) | ||
76 | |||
77 | void vr41xx_supply_clock(vr41xx_clock_t clock) | ||
78 | { | ||
79 | spin_lock_irq(&cmu_lock); | ||
80 | |||
81 | switch (clock) { | ||
82 | case PIU_CLOCK: | ||
83 | cmuclkmsk |= MSKPIU; | ||
84 | break; | ||
85 | case SIU_CLOCK: | ||
86 | cmuclkmsk |= MSKSIU | MSKSSIU; | ||
87 | break; | ||
88 | case AIU_CLOCK: | ||
89 | cmuclkmsk |= MSKAIU; | ||
90 | break; | ||
91 | case KIU_CLOCK: | ||
92 | cmuclkmsk |= MSKKIU; | ||
93 | break; | ||
94 | case FIR_CLOCK: | ||
95 | cmuclkmsk |= MSKFIR | MSKFFIR; | ||
96 | break; | ||
97 | case DSIU_CLOCK: | ||
98 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
99 | current_cpu_data.cputype == CPU_VR4121) | ||
100 | cmuclkmsk |= MSKDSIU; | ||
101 | else | ||
102 | cmuclkmsk |= MSKSIU | MSKDSIU; | ||
103 | break; | ||
104 | case CSI_CLOCK: | ||
105 | cmuclkmsk |= MSKCSI | MSKSCSI; | ||
106 | break; | ||
107 | case PCIU_CLOCK: | ||
108 | cmuclkmsk |= MSKPCIU; | ||
109 | break; | ||
110 | case HSP_CLOCK: | ||
111 | cmuclkmsk |= MSKSHSP; | ||
112 | break; | ||
113 | case PCI_CLOCK: | ||
114 | cmuclkmsk |= MSKPPCIU; | ||
115 | break; | ||
116 | case CEU_CLOCK: | ||
117 | cmuclkmsk2 |= MSKCEU; | ||
118 | break; | ||
119 | case ETHER0_CLOCK: | ||
120 | cmuclkmsk2 |= MSKMAC0; | ||
121 | break; | ||
122 | case ETHER1_CLOCK: | ||
123 | cmuclkmsk2 |= MSKMAC1; | ||
124 | break; | ||
125 | default: | ||
126 | break; | ||
127 | } | ||
128 | |||
129 | if (clock == CEU_CLOCK || clock == ETHER0_CLOCK || | ||
130 | clock == ETHER1_CLOCK) | ||
131 | cmu_write(CMUCLKMSK2, cmuclkmsk2); | ||
132 | else | ||
133 | cmu_write(CMUCLKMSK, cmuclkmsk); | ||
134 | |||
135 | spin_unlock_irq(&cmu_lock); | ||
136 | } | ||
137 | |||
138 | EXPORT_SYMBOL_GPL(vr41xx_supply_clock); | ||
139 | |||
140 | void vr41xx_mask_clock(vr41xx_clock_t clock) | ||
141 | { | ||
142 | spin_lock_irq(&cmu_lock); | ||
143 | |||
144 | switch (clock) { | ||
145 | case PIU_CLOCK: | ||
146 | cmuclkmsk &= ~MSKPIU; | ||
147 | break; | ||
148 | case SIU_CLOCK: | ||
149 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
150 | current_cpu_data.cputype == CPU_VR4121) { | ||
151 | cmuclkmsk &= ~(MSKSIU | MSKSSIU); | ||
152 | } else { | ||
153 | if (cmuclkmsk & MSKDSIU) | ||
154 | cmuclkmsk &= ~MSKSSIU; | ||
155 | else | ||
156 | cmuclkmsk &= ~(MSKSIU | MSKSSIU); | ||
157 | } | ||
158 | break; | ||
159 | case AIU_CLOCK: | ||
160 | cmuclkmsk &= ~MSKAIU; | ||
161 | break; | ||
162 | case KIU_CLOCK: | ||
163 | cmuclkmsk &= ~MSKKIU; | ||
164 | break; | ||
165 | case FIR_CLOCK: | ||
166 | cmuclkmsk &= ~(MSKFIR | MSKFFIR); | ||
167 | break; | ||
168 | case DSIU_CLOCK: | ||
169 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
170 | current_cpu_data.cputype == CPU_VR4121) { | ||
171 | cmuclkmsk &= ~MSKDSIU; | ||
172 | } else { | ||
173 | if (cmuclkmsk & MSKSSIU) | ||
174 | cmuclkmsk &= ~MSKDSIU; | ||
175 | else | ||
176 | cmuclkmsk &= ~(MSKSIU | MSKDSIU); | ||
177 | } | ||
178 | break; | ||
179 | case CSI_CLOCK: | ||
180 | cmuclkmsk &= ~(MSKCSI | MSKSCSI); | ||
181 | break; | ||
182 | case PCIU_CLOCK: | ||
183 | cmuclkmsk &= ~MSKPCIU; | ||
184 | break; | ||
185 | case HSP_CLOCK: | ||
186 | cmuclkmsk &= ~MSKSHSP; | ||
187 | break; | ||
188 | case PCI_CLOCK: | ||
189 | cmuclkmsk &= ~MSKPPCIU; | ||
190 | break; | ||
191 | case CEU_CLOCK: | ||
192 | cmuclkmsk2 &= ~MSKCEU; | ||
193 | break; | ||
194 | case ETHER0_CLOCK: | ||
195 | cmuclkmsk2 &= ~MSKMAC0; | ||
196 | break; | ||
197 | case ETHER1_CLOCK: | ||
198 | cmuclkmsk2 &= ~MSKMAC1; | ||
199 | break; | ||
200 | default: | ||
201 | break; | ||
202 | } | ||
203 | |||
204 | if (clock == CEU_CLOCK || clock == ETHER0_CLOCK || | ||
205 | clock == ETHER1_CLOCK) | ||
206 | cmu_write(CMUCLKMSK2, cmuclkmsk2); | ||
207 | else | ||
208 | cmu_write(CMUCLKMSK, cmuclkmsk); | ||
209 | |||
210 | spin_unlock_irq(&cmu_lock); | ||
211 | } | ||
212 | |||
213 | EXPORT_SYMBOL_GPL(vr41xx_mask_clock); | ||
214 | |||
215 | static int __init vr41xx_cmu_init(void) | ||
216 | { | ||
217 | unsigned long start, size; | ||
218 | |||
219 | switch (current_cpu_data.cputype) { | ||
220 | case CPU_VR4111: | ||
221 | case CPU_VR4121: | ||
222 | start = CMU_TYPE1_BASE; | ||
223 | size = CMU_TYPE1_SIZE; | ||
224 | break; | ||
225 | case CPU_VR4122: | ||
226 | case CPU_VR4131: | ||
227 | start = CMU_TYPE2_BASE; | ||
228 | size = CMU_TYPE2_SIZE; | ||
229 | break; | ||
230 | case CPU_VR4133: | ||
231 | start = CMU_TYPE3_BASE; | ||
232 | size = CMU_TYPE3_SIZE; | ||
233 | break; | ||
234 | default: | ||
235 | panic("Unexpected CPU of NEC VR4100 series"); | ||
236 | break; | ||
237 | } | ||
238 | |||
239 | if (request_mem_region(start, size, "CMU") == NULL) | ||
240 | return -EBUSY; | ||
241 | |||
242 | cmu_base = ioremap(start, size); | ||
243 | if (cmu_base == NULL) { | ||
244 | release_mem_region(start, size); | ||
245 | return -EBUSY; | ||
246 | } | ||
247 | |||
248 | cmuclkmsk = cmu_read(CMUCLKMSK); | ||
249 | if (current_cpu_data.cputype == CPU_VR4133) | ||
250 | cmuclkmsk2 = cmu_read(CMUCLKMSK2); | ||
251 | |||
252 | spin_lock_init(&cmu_lock); | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | core_initcall(vr41xx_cmu_init); | ||
diff --git a/arch/mips/vr41xx/common/giu.c b/arch/mips/vr41xx/common/giu.c new file mode 100644 index 000000000000..9c6b21a79e8f --- /dev/null +++ b/arch/mips/vr41xx/common/giu.c | |||
@@ -0,0 +1,455 @@ | |||
1 | /* | ||
2 | * giu.c, General-purpose I/O Unit Interrupt routines for NEC VR4100 series. | ||
3 | * | ||
4 | * Copyright (C) 2002 MontaVista Software Inc. | ||
5 | * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com> | ||
6 | * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
7 | * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | /* | ||
24 | * Changes: | ||
25 | * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com> | ||
26 | * - New creation, NEC VR4111, VR4121, VR4122 and VR4131 are supported. | ||
27 | * | ||
28 | * Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
29 | * - Added support for NEC VR4133. | ||
30 | * - Removed board_irq_init. | ||
31 | */ | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/irq.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/smp.h> | ||
38 | #include <linux/types.h> | ||
39 | |||
40 | #include <asm/cpu.h> | ||
41 | #include <asm/io.h> | ||
42 | #include <asm/vr41xx/vr41xx.h> | ||
43 | |||
44 | #define GIUIOSELL_TYPE1 KSEG1ADDR(0x0b000100) | ||
45 | #define GIUIOSELL_TYPE2 KSEG1ADDR(0x0f000140) | ||
46 | |||
47 | #define GIUIOSELL 0x00 | ||
48 | #define GIUIOSELH 0x02 | ||
49 | #define GIUINTSTATL 0x08 | ||
50 | #define GIUINTSTATH 0x0a | ||
51 | #define GIUINTENL 0x0c | ||
52 | #define GIUINTENH 0x0e | ||
53 | #define GIUINTTYPL 0x10 | ||
54 | #define GIUINTTYPH 0x12 | ||
55 | #define GIUINTALSELL 0x14 | ||
56 | #define GIUINTALSELH 0x16 | ||
57 | #define GIUINTHTSELL 0x18 | ||
58 | #define GIUINTHTSELH 0x1a | ||
59 | #define GIUFEDGEINHL 0x20 | ||
60 | #define GIUFEDGEINHH 0x22 | ||
61 | #define GIUREDGEINHL 0x24 | ||
62 | #define GIUREDGEINHH 0x26 | ||
63 | |||
64 | static uint32_t giu_base; | ||
65 | |||
66 | static struct irqaction giu_cascade = { | ||
67 | .handler = no_action, | ||
68 | .mask = CPU_MASK_NONE, | ||
69 | .name = "cascade", | ||
70 | }; | ||
71 | |||
72 | #define read_giuint(offset) readw(giu_base + (offset)) | ||
73 | #define write_giuint(val, offset) writew((val), giu_base + (offset)) | ||
74 | |||
75 | #define GIUINT_HIGH_OFFSET 16 | ||
76 | |||
77 | static inline uint16_t set_giuint(uint8_t offset, uint16_t set) | ||
78 | { | ||
79 | uint16_t res; | ||
80 | |||
81 | res = read_giuint(offset); | ||
82 | res |= set; | ||
83 | write_giuint(res, offset); | ||
84 | |||
85 | return res; | ||
86 | } | ||
87 | |||
88 | static inline uint16_t clear_giuint(uint8_t offset, uint16_t clear) | ||
89 | { | ||
90 | uint16_t res; | ||
91 | |||
92 | res = read_giuint(offset); | ||
93 | res &= ~clear; | ||
94 | write_giuint(res, offset); | ||
95 | |||
96 | return res; | ||
97 | } | ||
98 | |||
99 | static unsigned int startup_giuint_low_irq(unsigned int irq) | ||
100 | { | ||
101 | unsigned int pin; | ||
102 | |||
103 | pin = GIU_IRQ_TO_PIN(irq); | ||
104 | write_giuint((uint16_t)1 << pin, GIUINTSTATL); | ||
105 | set_giuint(GIUINTENL, (uint16_t)1 << pin); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static void shutdown_giuint_low_irq(unsigned int irq) | ||
111 | { | ||
112 | clear_giuint(GIUINTENL, (uint16_t)1 << GIU_IRQ_TO_PIN(irq)); | ||
113 | } | ||
114 | |||
115 | static void enable_giuint_low_irq(unsigned int irq) | ||
116 | { | ||
117 | set_giuint(GIUINTENL, (uint16_t)1 << GIU_IRQ_TO_PIN(irq)); | ||
118 | } | ||
119 | |||
120 | #define disable_giuint_low_irq shutdown_giuint_low_irq | ||
121 | |||
122 | static void ack_giuint_low_irq(unsigned int irq) | ||
123 | { | ||
124 | unsigned int pin; | ||
125 | |||
126 | pin = GIU_IRQ_TO_PIN(irq); | ||
127 | clear_giuint(GIUINTENL, (uint16_t)1 << pin); | ||
128 | write_giuint((uint16_t)1 << pin, GIUINTSTATL); | ||
129 | } | ||
130 | |||
131 | static void end_giuint_low_irq(unsigned int irq) | ||
132 | { | ||
133 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
134 | set_giuint(GIUINTENL, (uint16_t)1 << GIU_IRQ_TO_PIN(irq)); | ||
135 | } | ||
136 | |||
137 | static struct hw_interrupt_type giuint_low_irq_type = { | ||
138 | .typename = "GIUINTL", | ||
139 | .startup = startup_giuint_low_irq, | ||
140 | .shutdown = shutdown_giuint_low_irq, | ||
141 | .enable = enable_giuint_low_irq, | ||
142 | .disable = disable_giuint_low_irq, | ||
143 | .ack = ack_giuint_low_irq, | ||
144 | .end = end_giuint_low_irq, | ||
145 | }; | ||
146 | |||
147 | static unsigned int startup_giuint_high_irq(unsigned int irq) | ||
148 | { | ||
149 | unsigned int pin; | ||
150 | |||
151 | pin = GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET); | ||
152 | write_giuint((uint16_t)1 << pin, GIUINTSTATH); | ||
153 | set_giuint(GIUINTENH, (uint16_t)1 << pin); | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static void shutdown_giuint_high_irq(unsigned int irq) | ||
159 | { | ||
160 | clear_giuint(GIUINTENH, (uint16_t)1 << GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET)); | ||
161 | } | ||
162 | |||
163 | static void enable_giuint_high_irq(unsigned int irq) | ||
164 | { | ||
165 | set_giuint(GIUINTENH, (uint16_t)1 << GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET)); | ||
166 | } | ||
167 | |||
168 | #define disable_giuint_high_irq shutdown_giuint_high_irq | ||
169 | |||
170 | static void ack_giuint_high_irq(unsigned int irq) | ||
171 | { | ||
172 | unsigned int pin; | ||
173 | |||
174 | pin = GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET); | ||
175 | clear_giuint(GIUINTENH, (uint16_t)1 << pin); | ||
176 | write_giuint((uint16_t)1 << pin, GIUINTSTATH); | ||
177 | } | ||
178 | |||
179 | static void end_giuint_high_irq(unsigned int irq) | ||
180 | { | ||
181 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
182 | set_giuint(GIUINTENH, (uint16_t)1 << GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET)); | ||
183 | } | ||
184 | |||
185 | static struct hw_interrupt_type giuint_high_irq_type = { | ||
186 | .typename = "GIUINTH", | ||
187 | .startup = startup_giuint_high_irq, | ||
188 | .shutdown = shutdown_giuint_high_irq, | ||
189 | .enable = enable_giuint_high_irq, | ||
190 | .disable = disable_giuint_high_irq, | ||
191 | .ack = ack_giuint_high_irq, | ||
192 | .end = end_giuint_high_irq, | ||
193 | }; | ||
194 | |||
195 | void __init init_vr41xx_giuint_irq(void) | ||
196 | { | ||
197 | int i; | ||
198 | |||
199 | for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { | ||
200 | if (i < (GIU_IRQ_BASE + GIUINT_HIGH_OFFSET)) | ||
201 | irq_desc[i].handler = &giuint_low_irq_type; | ||
202 | else | ||
203 | irq_desc[i].handler = &giuint_high_irq_type; | ||
204 | } | ||
205 | |||
206 | setup_irq(GIUINT_CASCADE_IRQ, &giu_cascade); | ||
207 | } | ||
208 | |||
209 | void vr41xx_set_irq_trigger(int pin, int trigger, int hold) | ||
210 | { | ||
211 | uint16_t mask; | ||
212 | |||
213 | if (pin < GIUINT_HIGH_OFFSET) { | ||
214 | mask = (uint16_t)1 << pin; | ||
215 | if (trigger != TRIGGER_LEVEL) { | ||
216 | set_giuint(GIUINTTYPL, mask); | ||
217 | if (hold == SIGNAL_HOLD) | ||
218 | set_giuint(GIUINTHTSELL, mask); | ||
219 | else | ||
220 | clear_giuint(GIUINTHTSELL, mask); | ||
221 | if (current_cpu_data.cputype == CPU_VR4133) { | ||
222 | switch (trigger) { | ||
223 | case TRIGGER_EDGE_FALLING: | ||
224 | set_giuint(GIUFEDGEINHL, mask); | ||
225 | clear_giuint(GIUREDGEINHL, mask); | ||
226 | break; | ||
227 | case TRIGGER_EDGE_RISING: | ||
228 | clear_giuint(GIUFEDGEINHL, mask); | ||
229 | set_giuint(GIUREDGEINHL, mask); | ||
230 | break; | ||
231 | default: | ||
232 | set_giuint(GIUFEDGEINHL, mask); | ||
233 | set_giuint(GIUREDGEINHL, mask); | ||
234 | break; | ||
235 | } | ||
236 | } | ||
237 | } else { | ||
238 | clear_giuint(GIUINTTYPL, mask); | ||
239 | clear_giuint(GIUINTHTSELL, mask); | ||
240 | } | ||
241 | write_giuint(mask, GIUINTSTATL); | ||
242 | } else { | ||
243 | mask = (uint16_t)1 << (pin - GIUINT_HIGH_OFFSET); | ||
244 | if (trigger != TRIGGER_LEVEL) { | ||
245 | set_giuint(GIUINTTYPH, mask); | ||
246 | if (hold == SIGNAL_HOLD) | ||
247 | set_giuint(GIUINTHTSELH, mask); | ||
248 | else | ||
249 | clear_giuint(GIUINTHTSELH, mask); | ||
250 | if (current_cpu_data.cputype == CPU_VR4133) { | ||
251 | switch (trigger) { | ||
252 | case TRIGGER_EDGE_FALLING: | ||
253 | set_giuint(GIUFEDGEINHH, mask); | ||
254 | clear_giuint(GIUREDGEINHH, mask); | ||
255 | break; | ||
256 | case TRIGGER_EDGE_RISING: | ||
257 | clear_giuint(GIUFEDGEINHH, mask); | ||
258 | set_giuint(GIUREDGEINHH, mask); | ||
259 | break; | ||
260 | default: | ||
261 | set_giuint(GIUFEDGEINHH, mask); | ||
262 | set_giuint(GIUREDGEINHH, mask); | ||
263 | break; | ||
264 | } | ||
265 | } | ||
266 | } else { | ||
267 | clear_giuint(GIUINTTYPH, mask); | ||
268 | clear_giuint(GIUINTHTSELH, mask); | ||
269 | } | ||
270 | write_giuint(mask, GIUINTSTATH); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | EXPORT_SYMBOL(vr41xx_set_irq_trigger); | ||
275 | |||
276 | void vr41xx_set_irq_level(int pin, int level) | ||
277 | { | ||
278 | uint16_t mask; | ||
279 | |||
280 | if (pin < GIUINT_HIGH_OFFSET) { | ||
281 | mask = (uint16_t)1 << pin; | ||
282 | if (level == LEVEL_HIGH) | ||
283 | set_giuint(GIUINTALSELL, mask); | ||
284 | else | ||
285 | clear_giuint(GIUINTALSELL, mask); | ||
286 | write_giuint(mask, GIUINTSTATL); | ||
287 | } else { | ||
288 | mask = (uint16_t)1 << (pin - GIUINT_HIGH_OFFSET); | ||
289 | if (level == LEVEL_HIGH) | ||
290 | set_giuint(GIUINTALSELH, mask); | ||
291 | else | ||
292 | clear_giuint(GIUINTALSELH, mask); | ||
293 | write_giuint(mask, GIUINTSTATH); | ||
294 | } | ||
295 | } | ||
296 | |||
297 | EXPORT_SYMBOL(vr41xx_set_irq_level); | ||
298 | |||
299 | #define GIUINT_NR_IRQS 32 | ||
300 | |||
301 | enum { | ||
302 | GIUINT_NO_CASCADE, | ||
303 | GIUINT_CASCADE | ||
304 | }; | ||
305 | |||
306 | struct vr41xx_giuint_cascade { | ||
307 | unsigned int flag; | ||
308 | int (*get_irq_number)(int irq); | ||
309 | }; | ||
310 | |||
311 | static struct vr41xx_giuint_cascade giuint_cascade[GIUINT_NR_IRQS]; | ||
312 | |||
313 | static int no_irq_number(int irq) | ||
314 | { | ||
315 | return -EINVAL; | ||
316 | } | ||
317 | |||
318 | int vr41xx_cascade_irq(unsigned int irq, int (*get_irq_number)(int irq)) | ||
319 | { | ||
320 | unsigned int pin; | ||
321 | int retval; | ||
322 | |||
323 | if (irq < GIU_IRQ(0) || irq > GIU_IRQ(31)) | ||
324 | return -EINVAL; | ||
325 | |||
326 | if(!get_irq_number) | ||
327 | return -EINVAL; | ||
328 | |||
329 | pin = GIU_IRQ_TO_PIN(irq); | ||
330 | giuint_cascade[pin].flag = GIUINT_CASCADE; | ||
331 | giuint_cascade[pin].get_irq_number = get_irq_number; | ||
332 | |||
333 | retval = setup_irq(irq, &giu_cascade); | ||
334 | if (retval != 0) { | ||
335 | giuint_cascade[pin].flag = GIUINT_NO_CASCADE; | ||
336 | giuint_cascade[pin].get_irq_number = no_irq_number; | ||
337 | } | ||
338 | |||
339 | return retval; | ||
340 | } | ||
341 | |||
342 | EXPORT_SYMBOL(vr41xx_cascade_irq); | ||
343 | |||
344 | static inline int get_irq_pin_number(void) | ||
345 | { | ||
346 | uint16_t pendl, pendh, maskl, maskh; | ||
347 | int i; | ||
348 | |||
349 | pendl = read_giuint(GIUINTSTATL); | ||
350 | pendh = read_giuint(GIUINTSTATH); | ||
351 | maskl = read_giuint(GIUINTENL); | ||
352 | maskh = read_giuint(GIUINTENH); | ||
353 | |||
354 | maskl &= pendl; | ||
355 | maskh &= pendh; | ||
356 | |||
357 | if (maskl) { | ||
358 | for (i = 0; i < 16; i++) { | ||
359 | if (maskl & ((uint16_t)1 << i)) | ||
360 | return i; | ||
361 | } | ||
362 | } else if (maskh) { | ||
363 | for (i = 0; i < 16; i++) { | ||
364 | if (maskh & ((uint16_t)1 << i)) | ||
365 | return i + GIUINT_HIGH_OFFSET; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n", | ||
370 | maskl, pendl, maskh, pendh); | ||
371 | |||
372 | atomic_inc(&irq_err_count); | ||
373 | |||
374 | return -1; | ||
375 | } | ||
376 | |||
377 | static inline void ack_giuint_irq(int pin) | ||
378 | { | ||
379 | if (pin < GIUINT_HIGH_OFFSET) { | ||
380 | clear_giuint(GIUINTENL, (uint16_t)1 << pin); | ||
381 | write_giuint((uint16_t)1 << pin, GIUINTSTATL); | ||
382 | } else { | ||
383 | pin -= GIUINT_HIGH_OFFSET; | ||
384 | clear_giuint(GIUINTENH, (uint16_t)1 << pin); | ||
385 | write_giuint((uint16_t)1 << pin, GIUINTSTATH); | ||
386 | } | ||
387 | } | ||
388 | |||
389 | static inline void end_giuint_irq(int pin) | ||
390 | { | ||
391 | if (pin < GIUINT_HIGH_OFFSET) | ||
392 | set_giuint(GIUINTENL, (uint16_t)1 << pin); | ||
393 | else | ||
394 | set_giuint(GIUINTENH, (uint16_t)1 << (pin - GIUINT_HIGH_OFFSET)); | ||
395 | } | ||
396 | |||
397 | void giuint_irq_dispatch(struct pt_regs *regs) | ||
398 | { | ||
399 | struct vr41xx_giuint_cascade *cascade; | ||
400 | unsigned int giuint_irq; | ||
401 | int pin; | ||
402 | |||
403 | pin = get_irq_pin_number(); | ||
404 | if (pin < 0) | ||
405 | return; | ||
406 | |||
407 | disable_irq(GIUINT_CASCADE_IRQ); | ||
408 | |||
409 | cascade = &giuint_cascade[pin]; | ||
410 | giuint_irq = GIU_IRQ(pin); | ||
411 | if (cascade->flag == GIUINT_CASCADE) { | ||
412 | int irq = cascade->get_irq_number(giuint_irq); | ||
413 | ack_giuint_irq(pin); | ||
414 | if (irq >= 0) | ||
415 | do_IRQ(irq, regs); | ||
416 | end_giuint_irq(pin); | ||
417 | } else { | ||
418 | do_IRQ(giuint_irq, regs); | ||
419 | } | ||
420 | |||
421 | enable_irq(GIUINT_CASCADE_IRQ); | ||
422 | } | ||
423 | |||
424 | static int __init vr41xx_giu_init(void) | ||
425 | { | ||
426 | int i; | ||
427 | |||
428 | switch (current_cpu_data.cputype) { | ||
429 | case CPU_VR4111: | ||
430 | case CPU_VR4121: | ||
431 | giu_base = GIUIOSELL_TYPE1; | ||
432 | break; | ||
433 | case CPU_VR4122: | ||
434 | case CPU_VR4131: | ||
435 | case CPU_VR4133: | ||
436 | giu_base = GIUIOSELL_TYPE2; | ||
437 | break; | ||
438 | default: | ||
439 | printk(KERN_ERR "GIU: Unexpected CPU of NEC VR4100 series\n"); | ||
440 | return -EINVAL; | ||
441 | } | ||
442 | |||
443 | for (i = 0; i < GIUINT_NR_IRQS; i++) { | ||
444 | if (i < GIUINT_HIGH_OFFSET) | ||
445 | clear_giuint(GIUINTENL, (uint16_t)1 << i); | ||
446 | else | ||
447 | clear_giuint(GIUINTENH, (uint16_t)1 << (i - GIUINT_HIGH_OFFSET)); | ||
448 | giuint_cascade[i].flag = GIUINT_NO_CASCADE; | ||
449 | giuint_cascade[i].get_irq_number = no_irq_number; | ||
450 | } | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | early_initcall(vr41xx_giu_init); | ||
diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c new file mode 100644 index 000000000000..c842661144cb --- /dev/null +++ b/arch/mips/vr41xx/common/icu.c | |||
@@ -0,0 +1,757 @@ | |||
1 | /* | ||
2 | * icu.c, Interrupt Control Unit routines for the NEC VR4100 series. | ||
3 | * | ||
4 | * Copyright (C) 2001-2002 MontaVista Software Inc. | ||
5 | * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com> | ||
6 | * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
7 | * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | /* | ||
24 | * Changes: | ||
25 | * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com> | ||
26 | * - New creation, NEC VR4122 and VR4131 are supported. | ||
27 | * - Added support for NEC VR4111 and VR4121. | ||
28 | * | ||
29 | * Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
30 | * - Coped with INTASSIGN of NEC VR4133. | ||
31 | */ | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/irq.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/smp.h> | ||
38 | #include <linux/types.h> | ||
39 | |||
40 | #include <asm/cpu.h> | ||
41 | #include <asm/io.h> | ||
42 | #include <asm/irq.h> | ||
43 | #include <asm/irq_cpu.h> | ||
44 | #include <asm/vr41xx/vr41xx.h> | ||
45 | |||
46 | extern asmlinkage void vr41xx_handle_interrupt(void); | ||
47 | |||
48 | extern void init_vr41xx_giuint_irq(void); | ||
49 | extern void giuint_irq_dispatch(struct pt_regs *regs); | ||
50 | |||
51 | static uint32_t icu1_base; | ||
52 | static uint32_t icu2_base; | ||
53 | |||
54 | static struct irqaction icu_cascade = { | ||
55 | .handler = no_action, | ||
56 | .mask = CPU_MASK_NONE, | ||
57 | .name = "cascade", | ||
58 | }; | ||
59 | |||
60 | static unsigned char sysint1_assign[16] = { | ||
61 | 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
62 | static unsigned char sysint2_assign[16] = { | ||
63 | 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
64 | |||
65 | #define SYSINT1REG_TYPE1 KSEG1ADDR(0x0b000080) | ||
66 | #define SYSINT2REG_TYPE1 KSEG1ADDR(0x0b000200) | ||
67 | |||
68 | #define SYSINT1REG_TYPE2 KSEG1ADDR(0x0f000080) | ||
69 | #define SYSINT2REG_TYPE2 KSEG1ADDR(0x0f0000a0) | ||
70 | |||
71 | #define SYSINT1REG 0x00 | ||
72 | #define PIUINTREG 0x02 | ||
73 | #define INTASSIGN0 0x04 | ||
74 | #define INTASSIGN1 0x06 | ||
75 | #define GIUINTLREG 0x08 | ||
76 | #define DSIUINTREG 0x0a | ||
77 | #define MSYSINT1REG 0x0c | ||
78 | #define MPIUINTREG 0x0e | ||
79 | #define MAIUINTREG 0x10 | ||
80 | #define MKIUINTREG 0x12 | ||
81 | #define MGIUINTLREG 0x14 | ||
82 | #define MDSIUINTREG 0x16 | ||
83 | #define NMIREG 0x18 | ||
84 | #define SOFTREG 0x1a | ||
85 | #define INTASSIGN2 0x1c | ||
86 | #define INTASSIGN3 0x1e | ||
87 | |||
88 | #define SYSINT2REG 0x00 | ||
89 | #define GIUINTHREG 0x02 | ||
90 | #define FIRINTREG 0x04 | ||
91 | #define MSYSINT2REG 0x06 | ||
92 | #define MGIUINTHREG 0x08 | ||
93 | #define MFIRINTREG 0x0a | ||
94 | #define PCIINTREG 0x0c | ||
95 | #define PCIINT0 0x0001 | ||
96 | #define SCUINTREG 0x0e | ||
97 | #define SCUINT0 0x0001 | ||
98 | #define CSIINTREG 0x10 | ||
99 | #define MPCIINTREG 0x12 | ||
100 | #define MSCUINTREG 0x14 | ||
101 | #define MCSIINTREG 0x16 | ||
102 | #define BCUINTREG 0x18 | ||
103 | #define BCUINTR 0x0001 | ||
104 | #define MBCUINTREG 0x1a | ||
105 | |||
106 | #define SYSINT1_IRQ_TO_PIN(x) ((x) - SYSINT1_IRQ_BASE) /* Pin 0-15 */ | ||
107 | #define SYSINT2_IRQ_TO_PIN(x) ((x) - SYSINT2_IRQ_BASE) /* Pin 0-15 */ | ||
108 | |||
109 | #define read_icu1(offset) readw(icu1_base + (offset)) | ||
110 | #define write_icu1(val, offset) writew((val), icu1_base + (offset)) | ||
111 | |||
112 | #define read_icu2(offset) readw(icu2_base + (offset)) | ||
113 | #define write_icu2(val, offset) writew((val), icu2_base + (offset)) | ||
114 | |||
115 | #define INTASSIGN_MAX 4 | ||
116 | #define INTASSIGN_MASK 0x0007 | ||
117 | |||
118 | static inline uint16_t set_icu1(uint8_t offset, uint16_t set) | ||
119 | { | ||
120 | uint16_t res; | ||
121 | |||
122 | res = read_icu1(offset); | ||
123 | res |= set; | ||
124 | write_icu1(res, offset); | ||
125 | |||
126 | return res; | ||
127 | } | ||
128 | |||
129 | static inline uint16_t clear_icu1(uint8_t offset, uint16_t clear) | ||
130 | { | ||
131 | uint16_t res; | ||
132 | |||
133 | res = read_icu1(offset); | ||
134 | res &= ~clear; | ||
135 | write_icu1(res, offset); | ||
136 | |||
137 | return res; | ||
138 | } | ||
139 | |||
140 | static inline uint16_t set_icu2(uint8_t offset, uint16_t set) | ||
141 | { | ||
142 | uint16_t res; | ||
143 | |||
144 | res = read_icu2(offset); | ||
145 | res |= set; | ||
146 | write_icu2(res, offset); | ||
147 | |||
148 | return res; | ||
149 | } | ||
150 | |||
151 | static inline uint16_t clear_icu2(uint8_t offset, uint16_t clear) | ||
152 | { | ||
153 | uint16_t res; | ||
154 | |||
155 | res = read_icu2(offset); | ||
156 | res &= ~clear; | ||
157 | write_icu2(res, offset); | ||
158 | |||
159 | return res; | ||
160 | } | ||
161 | |||
162 | /*=======================================================================*/ | ||
163 | |||
164 | void vr41xx_enable_piuint(uint16_t mask) | ||
165 | { | ||
166 | irq_desc_t *desc = irq_desc + PIU_IRQ; | ||
167 | unsigned long flags; | ||
168 | |||
169 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
170 | current_cpu_data.cputype == CPU_VR4121) { | ||
171 | spin_lock_irqsave(&desc->lock, flags); | ||
172 | set_icu1(MPIUINTREG, mask); | ||
173 | spin_unlock_irqrestore(&desc->lock, flags); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | EXPORT_SYMBOL(vr41xx_enable_piuint); | ||
178 | |||
179 | void vr41xx_disable_piuint(uint16_t mask) | ||
180 | { | ||
181 | irq_desc_t *desc = irq_desc + PIU_IRQ; | ||
182 | unsigned long flags; | ||
183 | |||
184 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
185 | current_cpu_data.cputype == CPU_VR4121) { | ||
186 | spin_lock_irqsave(&desc->lock, flags); | ||
187 | clear_icu1(MPIUINTREG, mask); | ||
188 | spin_unlock_irqrestore(&desc->lock, flags); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | EXPORT_SYMBOL(vr41xx_disable_piuint); | ||
193 | |||
194 | void vr41xx_enable_aiuint(uint16_t mask) | ||
195 | { | ||
196 | irq_desc_t *desc = irq_desc + AIU_IRQ; | ||
197 | unsigned long flags; | ||
198 | |||
199 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
200 | current_cpu_data.cputype == CPU_VR4121) { | ||
201 | spin_lock_irqsave(&desc->lock, flags); | ||
202 | set_icu1(MAIUINTREG, mask); | ||
203 | spin_unlock_irqrestore(&desc->lock, flags); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | EXPORT_SYMBOL(vr41xx_enable_aiuint); | ||
208 | |||
209 | void vr41xx_disable_aiuint(uint16_t mask) | ||
210 | { | ||
211 | irq_desc_t *desc = irq_desc + AIU_IRQ; | ||
212 | unsigned long flags; | ||
213 | |||
214 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
215 | current_cpu_data.cputype == CPU_VR4121) { | ||
216 | spin_lock_irqsave(&desc->lock, flags); | ||
217 | clear_icu1(MAIUINTREG, mask); | ||
218 | spin_unlock_irqrestore(&desc->lock, flags); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | EXPORT_SYMBOL(vr41xx_disable_aiuint); | ||
223 | |||
224 | void vr41xx_enable_kiuint(uint16_t mask) | ||
225 | { | ||
226 | irq_desc_t *desc = irq_desc + KIU_IRQ; | ||
227 | unsigned long flags; | ||
228 | |||
229 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
230 | current_cpu_data.cputype == CPU_VR4121) { | ||
231 | spin_lock_irqsave(&desc->lock, flags); | ||
232 | set_icu1(MKIUINTREG, mask); | ||
233 | spin_unlock_irqrestore(&desc->lock, flags); | ||
234 | } | ||
235 | } | ||
236 | |||
237 | EXPORT_SYMBOL(vr41xx_enable_kiuint); | ||
238 | |||
239 | void vr41xx_disable_kiuint(uint16_t mask) | ||
240 | { | ||
241 | irq_desc_t *desc = irq_desc + KIU_IRQ; | ||
242 | unsigned long flags; | ||
243 | |||
244 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
245 | current_cpu_data.cputype == CPU_VR4121) { | ||
246 | spin_lock_irqsave(&desc->lock, flags); | ||
247 | clear_icu1(MKIUINTREG, mask); | ||
248 | spin_unlock_irqrestore(&desc->lock, flags); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | EXPORT_SYMBOL(vr41xx_disable_kiuint); | ||
253 | |||
254 | void vr41xx_enable_dsiuint(uint16_t mask) | ||
255 | { | ||
256 | irq_desc_t *desc = irq_desc + DSIU_IRQ; | ||
257 | unsigned long flags; | ||
258 | |||
259 | spin_lock_irqsave(&desc->lock, flags); | ||
260 | set_icu1(MDSIUINTREG, mask); | ||
261 | spin_unlock_irqrestore(&desc->lock, flags); | ||
262 | } | ||
263 | |||
264 | EXPORT_SYMBOL(vr41xx_enable_dsiuint); | ||
265 | |||
266 | void vr41xx_disable_dsiuint(uint16_t mask) | ||
267 | { | ||
268 | irq_desc_t *desc = irq_desc + DSIU_IRQ; | ||
269 | unsigned long flags; | ||
270 | |||
271 | spin_lock_irqsave(&desc->lock, flags); | ||
272 | clear_icu1(MDSIUINTREG, mask); | ||
273 | spin_unlock_irqrestore(&desc->lock, flags); | ||
274 | } | ||
275 | |||
276 | EXPORT_SYMBOL(vr41xx_disable_dsiuint); | ||
277 | |||
278 | void vr41xx_enable_firint(uint16_t mask) | ||
279 | { | ||
280 | irq_desc_t *desc = irq_desc + FIR_IRQ; | ||
281 | unsigned long flags; | ||
282 | |||
283 | spin_lock_irqsave(&desc->lock, flags); | ||
284 | set_icu2(MFIRINTREG, mask); | ||
285 | spin_unlock_irqrestore(&desc->lock, flags); | ||
286 | } | ||
287 | |||
288 | EXPORT_SYMBOL(vr41xx_enable_firint); | ||
289 | |||
290 | void vr41xx_disable_firint(uint16_t mask) | ||
291 | { | ||
292 | irq_desc_t *desc = irq_desc + FIR_IRQ; | ||
293 | unsigned long flags; | ||
294 | |||
295 | spin_lock_irqsave(&desc->lock, flags); | ||
296 | clear_icu2(MFIRINTREG, mask); | ||
297 | spin_unlock_irqrestore(&desc->lock, flags); | ||
298 | } | ||
299 | |||
300 | EXPORT_SYMBOL(vr41xx_disable_firint); | ||
301 | |||
302 | void vr41xx_enable_pciint(void) | ||
303 | { | ||
304 | irq_desc_t *desc = irq_desc + PCI_IRQ; | ||
305 | unsigned long flags; | ||
306 | |||
307 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
308 | current_cpu_data.cputype == CPU_VR4131 || | ||
309 | current_cpu_data.cputype == CPU_VR4133) { | ||
310 | spin_lock_irqsave(&desc->lock, flags); | ||
311 | write_icu2(PCIINT0, MPCIINTREG); | ||
312 | spin_unlock_irqrestore(&desc->lock, flags); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | EXPORT_SYMBOL(vr41xx_enable_pciint); | ||
317 | |||
318 | void vr41xx_disable_pciint(void) | ||
319 | { | ||
320 | irq_desc_t *desc = irq_desc + PCI_IRQ; | ||
321 | unsigned long flags; | ||
322 | |||
323 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
324 | current_cpu_data.cputype == CPU_VR4131 || | ||
325 | current_cpu_data.cputype == CPU_VR4133) { | ||
326 | spin_lock_irqsave(&desc->lock, flags); | ||
327 | write_icu2(0, MPCIINTREG); | ||
328 | spin_unlock_irqrestore(&desc->lock, flags); | ||
329 | } | ||
330 | } | ||
331 | |||
332 | EXPORT_SYMBOL(vr41xx_disable_pciint); | ||
333 | |||
334 | void vr41xx_enable_scuint(void) | ||
335 | { | ||
336 | irq_desc_t *desc = irq_desc + SCU_IRQ; | ||
337 | unsigned long flags; | ||
338 | |||
339 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
340 | current_cpu_data.cputype == CPU_VR4131 || | ||
341 | current_cpu_data.cputype == CPU_VR4133) { | ||
342 | spin_lock_irqsave(&desc->lock, flags); | ||
343 | write_icu2(SCUINT0, MSCUINTREG); | ||
344 | spin_unlock_irqrestore(&desc->lock, flags); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | EXPORT_SYMBOL(vr41xx_enable_scuint); | ||
349 | |||
350 | void vr41xx_disable_scuint(void) | ||
351 | { | ||
352 | irq_desc_t *desc = irq_desc + SCU_IRQ; | ||
353 | unsigned long flags; | ||
354 | |||
355 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
356 | current_cpu_data.cputype == CPU_VR4131 || | ||
357 | current_cpu_data.cputype == CPU_VR4133) { | ||
358 | spin_lock_irqsave(&desc->lock, flags); | ||
359 | write_icu2(0, MSCUINTREG); | ||
360 | spin_unlock_irqrestore(&desc->lock, flags); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | EXPORT_SYMBOL(vr41xx_disable_scuint); | ||
365 | |||
366 | void vr41xx_enable_csiint(uint16_t mask) | ||
367 | { | ||
368 | irq_desc_t *desc = irq_desc + CSI_IRQ; | ||
369 | unsigned long flags; | ||
370 | |||
371 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
372 | current_cpu_data.cputype == CPU_VR4131 || | ||
373 | current_cpu_data.cputype == CPU_VR4133) { | ||
374 | spin_lock_irqsave(&desc->lock, flags); | ||
375 | set_icu2(MCSIINTREG, mask); | ||
376 | spin_unlock_irqrestore(&desc->lock, flags); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | EXPORT_SYMBOL(vr41xx_enable_csiint); | ||
381 | |||
382 | void vr41xx_disable_csiint(uint16_t mask) | ||
383 | { | ||
384 | irq_desc_t *desc = irq_desc + CSI_IRQ; | ||
385 | unsigned long flags; | ||
386 | |||
387 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
388 | current_cpu_data.cputype == CPU_VR4131 || | ||
389 | current_cpu_data.cputype == CPU_VR4133) { | ||
390 | spin_lock_irqsave(&desc->lock, flags); | ||
391 | clear_icu2(MCSIINTREG, mask); | ||
392 | spin_unlock_irqrestore(&desc->lock, flags); | ||
393 | } | ||
394 | } | ||
395 | |||
396 | EXPORT_SYMBOL(vr41xx_disable_csiint); | ||
397 | |||
398 | void vr41xx_enable_bcuint(void) | ||
399 | { | ||
400 | irq_desc_t *desc = irq_desc + BCU_IRQ; | ||
401 | unsigned long flags; | ||
402 | |||
403 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
404 | current_cpu_data.cputype == CPU_VR4131 || | ||
405 | current_cpu_data.cputype == CPU_VR4133) { | ||
406 | spin_lock_irqsave(&desc->lock, flags); | ||
407 | write_icu2(BCUINTR, MBCUINTREG); | ||
408 | spin_unlock_irqrestore(&desc->lock, flags); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | EXPORT_SYMBOL(vr41xx_enable_bcuint); | ||
413 | |||
414 | void vr41xx_disable_bcuint(void) | ||
415 | { | ||
416 | irq_desc_t *desc = irq_desc + BCU_IRQ; | ||
417 | unsigned long flags; | ||
418 | |||
419 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
420 | current_cpu_data.cputype == CPU_VR4131 || | ||
421 | current_cpu_data.cputype == CPU_VR4133) { | ||
422 | spin_lock_irqsave(&desc->lock, flags); | ||
423 | write_icu2(0, MBCUINTREG); | ||
424 | spin_unlock_irqrestore(&desc->lock, flags); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | EXPORT_SYMBOL(vr41xx_disable_bcuint); | ||
429 | |||
430 | /*=======================================================================*/ | ||
431 | |||
432 | static unsigned int startup_sysint1_irq(unsigned int irq) | ||
433 | { | ||
434 | set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); | ||
435 | |||
436 | return 0; /* never anything pending */ | ||
437 | } | ||
438 | |||
439 | static void shutdown_sysint1_irq(unsigned int irq) | ||
440 | { | ||
441 | clear_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); | ||
442 | } | ||
443 | |||
444 | static void enable_sysint1_irq(unsigned int irq) | ||
445 | { | ||
446 | set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); | ||
447 | } | ||
448 | |||
449 | #define disable_sysint1_irq shutdown_sysint1_irq | ||
450 | #define ack_sysint1_irq shutdown_sysint1_irq | ||
451 | |||
452 | static void end_sysint1_irq(unsigned int irq) | ||
453 | { | ||
454 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
455 | set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); | ||
456 | } | ||
457 | |||
458 | static struct hw_interrupt_type sysint1_irq_type = { | ||
459 | .typename = "SYSINT1", | ||
460 | .startup = startup_sysint1_irq, | ||
461 | .shutdown = shutdown_sysint1_irq, | ||
462 | .enable = enable_sysint1_irq, | ||
463 | .disable = disable_sysint1_irq, | ||
464 | .ack = ack_sysint1_irq, | ||
465 | .end = end_sysint1_irq, | ||
466 | }; | ||
467 | |||
468 | /*=======================================================================*/ | ||
469 | |||
470 | static unsigned int startup_sysint2_irq(unsigned int irq) | ||
471 | { | ||
472 | set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); | ||
473 | |||
474 | return 0; /* never anything pending */ | ||
475 | } | ||
476 | |||
477 | static void shutdown_sysint2_irq(unsigned int irq) | ||
478 | { | ||
479 | clear_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); | ||
480 | } | ||
481 | |||
482 | static void enable_sysint2_irq(unsigned int irq) | ||
483 | { | ||
484 | set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); | ||
485 | } | ||
486 | |||
487 | #define disable_sysint2_irq shutdown_sysint2_irq | ||
488 | #define ack_sysint2_irq shutdown_sysint2_irq | ||
489 | |||
490 | static void end_sysint2_irq(unsigned int irq) | ||
491 | { | ||
492 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
493 | set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); | ||
494 | } | ||
495 | |||
496 | static struct hw_interrupt_type sysint2_irq_type = { | ||
497 | .typename = "SYSINT2", | ||
498 | .startup = startup_sysint2_irq, | ||
499 | .shutdown = shutdown_sysint2_irq, | ||
500 | .enable = enable_sysint2_irq, | ||
501 | .disable = disable_sysint2_irq, | ||
502 | .ack = ack_sysint2_irq, | ||
503 | .end = end_sysint2_irq, | ||
504 | }; | ||
505 | |||
506 | /*=======================================================================*/ | ||
507 | |||
508 | static inline int set_sysint1_assign(unsigned int irq, unsigned char assign) | ||
509 | { | ||
510 | irq_desc_t *desc = irq_desc + irq; | ||
511 | uint16_t intassign0, intassign1; | ||
512 | unsigned int pin; | ||
513 | |||
514 | pin = SYSINT1_IRQ_TO_PIN(irq); | ||
515 | |||
516 | spin_lock_irq(&desc->lock); | ||
517 | |||
518 | intassign0 = read_icu1(INTASSIGN0); | ||
519 | intassign1 = read_icu1(INTASSIGN1); | ||
520 | |||
521 | switch (pin) { | ||
522 | case 0: | ||
523 | intassign0 &= ~INTASSIGN_MASK; | ||
524 | intassign0 |= (uint16_t)assign; | ||
525 | break; | ||
526 | case 1: | ||
527 | intassign0 &= ~(INTASSIGN_MASK << 3); | ||
528 | intassign0 |= (uint16_t)assign << 3; | ||
529 | break; | ||
530 | case 2: | ||
531 | intassign0 &= ~(INTASSIGN_MASK << 6); | ||
532 | intassign0 |= (uint16_t)assign << 6; | ||
533 | break; | ||
534 | case 3: | ||
535 | intassign0 &= ~(INTASSIGN_MASK << 9); | ||
536 | intassign0 |= (uint16_t)assign << 9; | ||
537 | break; | ||
538 | case 8: | ||
539 | intassign0 &= ~(INTASSIGN_MASK << 12); | ||
540 | intassign0 |= (uint16_t)assign << 12; | ||
541 | break; | ||
542 | case 9: | ||
543 | intassign1 &= ~INTASSIGN_MASK; | ||
544 | intassign1 |= (uint16_t)assign; | ||
545 | break; | ||
546 | case 11: | ||
547 | intassign1 &= ~(INTASSIGN_MASK << 6); | ||
548 | intassign1 |= (uint16_t)assign << 6; | ||
549 | break; | ||
550 | case 12: | ||
551 | intassign1 &= ~(INTASSIGN_MASK << 9); | ||
552 | intassign1 |= (uint16_t)assign << 9; | ||
553 | break; | ||
554 | default: | ||
555 | return -EINVAL; | ||
556 | } | ||
557 | |||
558 | sysint1_assign[pin] = assign; | ||
559 | write_icu1(intassign0, INTASSIGN0); | ||
560 | write_icu1(intassign1, INTASSIGN1); | ||
561 | |||
562 | spin_unlock_irq(&desc->lock); | ||
563 | |||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | static inline int set_sysint2_assign(unsigned int irq, unsigned char assign) | ||
568 | { | ||
569 | irq_desc_t *desc = irq_desc + irq; | ||
570 | uint16_t intassign2, intassign3; | ||
571 | unsigned int pin; | ||
572 | |||
573 | pin = SYSINT2_IRQ_TO_PIN(irq); | ||
574 | |||
575 | spin_lock_irq(&desc->lock); | ||
576 | |||
577 | intassign2 = read_icu1(INTASSIGN2); | ||
578 | intassign3 = read_icu1(INTASSIGN3); | ||
579 | |||
580 | switch (pin) { | ||
581 | case 0: | ||
582 | intassign2 &= ~INTASSIGN_MASK; | ||
583 | intassign2 |= (uint16_t)assign; | ||
584 | break; | ||
585 | case 1: | ||
586 | intassign2 &= ~(INTASSIGN_MASK << 3); | ||
587 | intassign2 |= (uint16_t)assign << 3; | ||
588 | break; | ||
589 | case 3: | ||
590 | intassign2 &= ~(INTASSIGN_MASK << 6); | ||
591 | intassign2 |= (uint16_t)assign << 6; | ||
592 | break; | ||
593 | case 4: | ||
594 | intassign2 &= ~(INTASSIGN_MASK << 9); | ||
595 | intassign2 |= (uint16_t)assign << 9; | ||
596 | break; | ||
597 | case 5: | ||
598 | intassign2 &= ~(INTASSIGN_MASK << 12); | ||
599 | intassign2 |= (uint16_t)assign << 12; | ||
600 | break; | ||
601 | case 6: | ||
602 | intassign3 &= ~INTASSIGN_MASK; | ||
603 | intassign3 |= (uint16_t)assign; | ||
604 | break; | ||
605 | case 7: | ||
606 | intassign3 &= ~(INTASSIGN_MASK << 3); | ||
607 | intassign3 |= (uint16_t)assign << 3; | ||
608 | break; | ||
609 | case 8: | ||
610 | intassign3 &= ~(INTASSIGN_MASK << 6); | ||
611 | intassign3 |= (uint16_t)assign << 6; | ||
612 | break; | ||
613 | case 9: | ||
614 | intassign3 &= ~(INTASSIGN_MASK << 9); | ||
615 | intassign3 |= (uint16_t)assign << 9; | ||
616 | break; | ||
617 | case 10: | ||
618 | intassign3 &= ~(INTASSIGN_MASK << 12); | ||
619 | intassign3 |= (uint16_t)assign << 12; | ||
620 | break; | ||
621 | default: | ||
622 | return -EINVAL; | ||
623 | } | ||
624 | |||
625 | sysint2_assign[pin] = assign; | ||
626 | write_icu1(intassign2, INTASSIGN2); | ||
627 | write_icu1(intassign3, INTASSIGN3); | ||
628 | |||
629 | spin_unlock_irq(&desc->lock); | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | int vr41xx_set_intassign(unsigned int irq, unsigned char intassign) | ||
635 | { | ||
636 | int retval = -EINVAL; | ||
637 | |||
638 | if (current_cpu_data.cputype != CPU_VR4133) | ||
639 | return -EINVAL; | ||
640 | |||
641 | if (intassign > INTASSIGN_MAX) | ||
642 | return -EINVAL; | ||
643 | |||
644 | if (irq >= SYSINT1_IRQ_BASE && irq <= SYSINT1_IRQ_LAST) | ||
645 | retval = set_sysint1_assign(irq, intassign); | ||
646 | else if (irq >= SYSINT2_IRQ_BASE && irq <= SYSINT2_IRQ_LAST) | ||
647 | retval = set_sysint2_assign(irq, intassign); | ||
648 | |||
649 | return retval; | ||
650 | } | ||
651 | |||
652 | EXPORT_SYMBOL(vr41xx_set_intassign); | ||
653 | |||
654 | /*=======================================================================*/ | ||
655 | |||
656 | asmlinkage void irq_dispatch(unsigned char intnum, struct pt_regs *regs) | ||
657 | { | ||
658 | uint16_t pend1, pend2; | ||
659 | uint16_t mask1, mask2; | ||
660 | int i; | ||
661 | |||
662 | pend1 = read_icu1(SYSINT1REG); | ||
663 | mask1 = read_icu1(MSYSINT1REG); | ||
664 | |||
665 | pend2 = read_icu2(SYSINT2REG); | ||
666 | mask2 = read_icu2(MSYSINT2REG); | ||
667 | |||
668 | mask1 &= pend1; | ||
669 | mask2 &= pend2; | ||
670 | |||
671 | if (mask1) { | ||
672 | for (i = 0; i < 16; i++) { | ||
673 | if (intnum == sysint1_assign[i] && | ||
674 | (mask1 & ((uint16_t)1 << i))) { | ||
675 | if (i == 8) | ||
676 | giuint_irq_dispatch(regs); | ||
677 | else | ||
678 | do_IRQ(SYSINT1_IRQ(i), regs); | ||
679 | return; | ||
680 | } | ||
681 | } | ||
682 | } | ||
683 | |||
684 | if (mask2) { | ||
685 | for (i = 0; i < 16; i++) { | ||
686 | if (intnum == sysint2_assign[i] && | ||
687 | (mask2 & ((uint16_t)1 << i))) { | ||
688 | do_IRQ(SYSINT2_IRQ(i), regs); | ||
689 | return; | ||
690 | } | ||
691 | } | ||
692 | } | ||
693 | |||
694 | printk(KERN_ERR "spurious ICU interrupt: %04x,%04x\n", pend1, pend2); | ||
695 | |||
696 | atomic_inc(&irq_err_count); | ||
697 | } | ||
698 | |||
699 | /*=======================================================================*/ | ||
700 | |||
701 | static int __init vr41xx_icu_init(void) | ||
702 | { | ||
703 | switch (current_cpu_data.cputype) { | ||
704 | case CPU_VR4111: | ||
705 | case CPU_VR4121: | ||
706 | icu1_base = SYSINT1REG_TYPE1; | ||
707 | icu2_base = SYSINT2REG_TYPE1; | ||
708 | break; | ||
709 | case CPU_VR4122: | ||
710 | case CPU_VR4131: | ||
711 | case CPU_VR4133: | ||
712 | icu1_base = SYSINT1REG_TYPE2; | ||
713 | icu2_base = SYSINT2REG_TYPE2; | ||
714 | break; | ||
715 | default: | ||
716 | printk(KERN_ERR "ICU: Unexpected CPU of NEC VR4100 series\n"); | ||
717 | return -EINVAL; | ||
718 | } | ||
719 | |||
720 | write_icu1(0, MSYSINT1REG); | ||
721 | write_icu1(0xffff, MGIUINTLREG); | ||
722 | |||
723 | write_icu2(0, MSYSINT2REG); | ||
724 | write_icu2(0xffff, MGIUINTHREG); | ||
725 | |||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | early_initcall(vr41xx_icu_init); | ||
730 | |||
731 | /*=======================================================================*/ | ||
732 | |||
733 | static inline void init_vr41xx_icu_irq(void) | ||
734 | { | ||
735 | int i; | ||
736 | |||
737 | for (i = SYSINT1_IRQ_BASE; i <= SYSINT1_IRQ_LAST; i++) | ||
738 | irq_desc[i].handler = &sysint1_irq_type; | ||
739 | |||
740 | for (i = SYSINT2_IRQ_BASE; i <= SYSINT2_IRQ_LAST; i++) | ||
741 | irq_desc[i].handler = &sysint2_irq_type; | ||
742 | |||
743 | setup_irq(INT0_CASCADE_IRQ, &icu_cascade); | ||
744 | setup_irq(INT1_CASCADE_IRQ, &icu_cascade); | ||
745 | setup_irq(INT2_CASCADE_IRQ, &icu_cascade); | ||
746 | setup_irq(INT3_CASCADE_IRQ, &icu_cascade); | ||
747 | setup_irq(INT4_CASCADE_IRQ, &icu_cascade); | ||
748 | } | ||
749 | |||
750 | void __init arch_init_irq(void) | ||
751 | { | ||
752 | mips_cpu_irq_init(MIPS_CPU_IRQ_BASE); | ||
753 | init_vr41xx_icu_irq(); | ||
754 | init_vr41xx_giuint_irq(); | ||
755 | |||
756 | set_except_vector(0, vr41xx_handle_interrupt); | ||
757 | } | ||
diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c new file mode 100644 index 000000000000..e03be896cbc4 --- /dev/null +++ b/arch/mips/vr41xx/common/init.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * init.c, Common initialization routines for NEC VR4100 series. | ||
3 | * | ||
4 | * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
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; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/irq.h> | ||
23 | #include <linux/string.h> | ||
24 | |||
25 | #include <asm/bootinfo.h> | ||
26 | #include <asm/time.h> | ||
27 | #include <asm/vr41xx/vr41xx.h> | ||
28 | |||
29 | #define IO_MEM_RESOURCE_START 0UL | ||
30 | #define IO_MEM_RESOURCE_END 0x1fffffffUL | ||
31 | |||
32 | static void __init iomem_resource_init(void) | ||
33 | { | ||
34 | iomem_resource.start = IO_MEM_RESOURCE_START; | ||
35 | iomem_resource.end = IO_MEM_RESOURCE_END; | ||
36 | } | ||
37 | |||
38 | static void __init setup_timer_frequency(void) | ||
39 | { | ||
40 | unsigned long tclock; | ||
41 | |||
42 | tclock = vr41xx_get_tclock_frequency(); | ||
43 | if (current_cpu_data.processor_id == PRID_VR4131_REV2_0 || | ||
44 | current_cpu_data.processor_id == PRID_VR4131_REV2_1) | ||
45 | mips_hpt_frequency = tclock / 2; | ||
46 | else | ||
47 | mips_hpt_frequency = tclock / 4; | ||
48 | } | ||
49 | |||
50 | static void __init setup_timer_irq(struct irqaction *irq) | ||
51 | { | ||
52 | setup_irq(TIMER_IRQ, irq); | ||
53 | } | ||
54 | |||
55 | static void __init timer_init(void) | ||
56 | { | ||
57 | board_time_init = setup_timer_frequency; | ||
58 | board_timer_setup = setup_timer_irq; | ||
59 | } | ||
60 | |||
61 | void __init prom_init(void) | ||
62 | { | ||
63 | int argc, i; | ||
64 | char **argv; | ||
65 | |||
66 | argc = fw_arg0; | ||
67 | argv = (char **)fw_arg1; | ||
68 | |||
69 | for (i = 1; i < argc; i++) { | ||
70 | strcat(arcs_cmdline, argv[i]); | ||
71 | if (i < (argc - 1)) | ||
72 | strcat(arcs_cmdline, " "); | ||
73 | } | ||
74 | |||
75 | vr41xx_calculate_clock_frequency(); | ||
76 | |||
77 | timer_init(); | ||
78 | |||
79 | iomem_resource_init(); | ||
80 | } | ||
81 | |||
82 | unsigned long __init prom_free_prom_memory (void) | ||
83 | { | ||
84 | return 0UL; | ||
85 | } | ||
diff --git a/arch/mips/vr41xx/common/int-handler.S b/arch/mips/vr41xx/common/int-handler.S new file mode 100644 index 000000000000..38ff89b505f2 --- /dev/null +++ b/arch/mips/vr41xx/common/int-handler.S | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * FILE NAME | ||
3 | * arch/mips/vr41xx/common/int-handler.S | ||
4 | * | ||
5 | * BRIEF MODULE DESCRIPTION | ||
6 | * Interrupt dispatcher for the NEC VR4100 series. | ||
7 | * | ||
8 | * Author: Yoichi Yuasa | ||
9 | * yyuasa@mvista.com or source@mvista.com | ||
10 | * | ||
11 | * Copyright 2001 MontaVista Software Inc. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | * | ||
18 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
19 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
20 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
23 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
24 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | ||
26 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | ||
27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
28 | * | ||
29 | * You should have received a copy of the GNU General Public License along | ||
30 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
31 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
32 | */ | ||
33 | /* | ||
34 | * Changes: | ||
35 | * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com> | ||
36 | * - New creation, NEC VR4100 series are supported. | ||
37 | * | ||
38 | * Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
39 | * - Coped with INTASSIGN of NEC VR4133. | ||
40 | */ | ||
41 | #include <asm/asm.h> | ||
42 | #include <asm/regdef.h> | ||
43 | #include <asm/mipsregs.h> | ||
44 | #include <asm/stackframe.h> | ||
45 | |||
46 | .text | ||
47 | .set noreorder | ||
48 | |||
49 | .align 5 | ||
50 | NESTED(vr41xx_handle_interrupt, PT_SIZE, ra) | ||
51 | .set noat | ||
52 | SAVE_ALL | ||
53 | CLI | ||
54 | .set at | ||
55 | .set noreorder | ||
56 | |||
57 | /* | ||
58 | * Get the pending interrupts | ||
59 | */ | ||
60 | mfc0 t0, CP0_CAUSE | ||
61 | mfc0 t1, CP0_STATUS | ||
62 | andi t0, 0xff00 | ||
63 | and t0, t0, t1 | ||
64 | |||
65 | andi t1, t0, CAUSEF_IP7 # MIPS timer interrupt | ||
66 | bnez t1, handle_irq | ||
67 | li a0, 7 | ||
68 | |||
69 | andi t1, t0, 0x7800 # check for Int1-4 | ||
70 | beqz t1, 1f | ||
71 | |||
72 | andi t1, t0, CAUSEF_IP3 # check for Int1 | ||
73 | bnez t1, handle_int | ||
74 | li a0, 1 | ||
75 | |||
76 | andi t1, t0, CAUSEF_IP4 # check for Int2 | ||
77 | bnez t1, handle_int | ||
78 | li a0, 2 | ||
79 | |||
80 | andi t1, t0, CAUSEF_IP5 # check for Int3 | ||
81 | bnez t1, handle_int | ||
82 | li a0, 3 | ||
83 | |||
84 | andi t1, t0, CAUSEF_IP6 # check for Int4 | ||
85 | bnez t1, handle_int | ||
86 | li a0, 4 | ||
87 | |||
88 | 1: | ||
89 | andi t1, t0, CAUSEF_IP2 # check for Int0 | ||
90 | bnez t1, handle_int | ||
91 | li a0, 0 | ||
92 | |||
93 | andi t1, t0, CAUSEF_IP0 # check for IP0 | ||
94 | bnez t1, handle_irq | ||
95 | li a0, 0 | ||
96 | |||
97 | andi t1, t0, CAUSEF_IP1 # check for IP1 | ||
98 | bnez t1, handle_irq | ||
99 | li a0, 1 | ||
100 | |||
101 | j spurious_interrupt | ||
102 | nop | ||
103 | |||
104 | handle_int: | ||
105 | jal irq_dispatch | ||
106 | move a1, sp | ||
107 | j ret_from_irq | ||
108 | nop | ||
109 | |||
110 | handle_irq: | ||
111 | jal do_IRQ | ||
112 | move a1, sp | ||
113 | j ret_from_irq | ||
114 | END(vr41xx_handle_interrupt) | ||
diff --git a/arch/mips/vr41xx/common/pmu.c b/arch/mips/vr41xx/common/pmu.c new file mode 100644 index 000000000000..c5f1043de938 --- /dev/null +++ b/arch/mips/vr41xx/common/pmu.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * pmu.c, Power Management Unit routines for NEC VR4100 series. | ||
3 | * | ||
4 | * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
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; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/smp.h> | ||
23 | #include <linux/types.h> | ||
24 | |||
25 | #include <asm/cpu.h> | ||
26 | #include <asm/io.h> | ||
27 | #include <asm/reboot.h> | ||
28 | #include <asm/system.h> | ||
29 | |||
30 | #define PMUCNT2REG KSEG1ADDR(0x0f0000c6) | ||
31 | #define SOFTRST 0x0010 | ||
32 | |||
33 | static inline void software_reset(void) | ||
34 | { | ||
35 | uint16_t val; | ||
36 | |||
37 | switch (current_cpu_data.cputype) { | ||
38 | case CPU_VR4122: | ||
39 | case CPU_VR4131: | ||
40 | case CPU_VR4133: | ||
41 | val = readw(PMUCNT2REG); | ||
42 | val |= SOFTRST; | ||
43 | writew(val, PMUCNT2REG); | ||
44 | break; | ||
45 | default: | ||
46 | break; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | static void vr41xx_restart(char *command) | ||
51 | { | ||
52 | local_irq_disable(); | ||
53 | software_reset(); | ||
54 | printk(KERN_NOTICE "\nYou can reset your system\n"); | ||
55 | while (1) ; | ||
56 | } | ||
57 | |||
58 | static void vr41xx_halt(void) | ||
59 | { | ||
60 | local_irq_disable(); | ||
61 | printk(KERN_NOTICE "\nYou can turn off the power supply\n"); | ||
62 | while (1) ; | ||
63 | } | ||
64 | |||
65 | static void vr41xx_power_off(void) | ||
66 | { | ||
67 | local_irq_disable(); | ||
68 | printk(KERN_NOTICE "\nYou can turn off the power supply\n"); | ||
69 | while (1) ; | ||
70 | } | ||
71 | |||
72 | static int __init vr41xx_pmu_init(void) | ||
73 | { | ||
74 | _machine_restart = vr41xx_restart; | ||
75 | _machine_halt = vr41xx_halt; | ||
76 | _machine_power_off = vr41xx_power_off; | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | early_initcall(vr41xx_pmu_init); | ||
diff --git a/arch/mips/vr41xx/common/vrc4173.c b/arch/mips/vr41xx/common/vrc4173.c new file mode 100644 index 000000000000..5475dd72e264 --- /dev/null +++ b/arch/mips/vr41xx/common/vrc4173.c | |||
@@ -0,0 +1,581 @@ | |||
1 | /* | ||
2 | * vrc4173.c, NEC VRC4173 base driver for NEC VR4122/VR4131. | ||
3 | * | ||
4 | * Copyright (C) 2001-2003 MontaVista Software Inc. | ||
5 | * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com> | ||
6 | * Copyright (C) 2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
7 | * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/irq.h> | ||
27 | #include <linux/pci.h> | ||
28 | #include <linux/spinlock.h> | ||
29 | #include <linux/types.h> | ||
30 | |||
31 | #include <asm/vr41xx/vr41xx.h> | ||
32 | #include <asm/vr41xx/vrc4173.h> | ||
33 | |||
34 | MODULE_DESCRIPTION("NEC VRC4173 base driver for NEC VR4122/4131"); | ||
35 | MODULE_AUTHOR("Yoichi Yuasa <yyuasa@mvista.com>"); | ||
36 | MODULE_LICENSE("GPL"); | ||
37 | |||
38 | #define VRC4173_CMUCLKMSK 0x040 | ||
39 | #define MSKPIU 0x0001 | ||
40 | #define MSKKIU 0x0002 | ||
41 | #define MSKAIU 0x0004 | ||
42 | #define MSKPS2CH1 0x0008 | ||
43 | #define MSKPS2CH2 0x0010 | ||
44 | #define MSKUSB 0x0020 | ||
45 | #define MSKCARD1 0x0040 | ||
46 | #define MSKCARD2 0x0080 | ||
47 | #define MSKAC97 0x0100 | ||
48 | #define MSK48MUSB 0x0400 | ||
49 | #define MSK48MPIN 0x0800 | ||
50 | #define MSK48MOSC 0x1000 | ||
51 | #define VRC4173_CMUSRST 0x042 | ||
52 | #define USBRST 0x0001 | ||
53 | #define CARD1RST 0x0002 | ||
54 | #define CARD2RST 0x0004 | ||
55 | #define AC97RST 0x0008 | ||
56 | |||
57 | #define VRC4173_SYSINT1REG 0x060 | ||
58 | #define VRC4173_MSYSINT1REG 0x06c | ||
59 | #define VRC4173_MPIUINTREG 0x06e | ||
60 | #define VRC4173_MAIUINTREG 0x070 | ||
61 | #define VRC4173_MKIUINTREG 0x072 | ||
62 | |||
63 | #define VRC4173_SELECTREG 0x09e | ||
64 | #define SEL3 0x0008 | ||
65 | #define SEL2 0x0004 | ||
66 | #define SEL1 0x0002 | ||
67 | #define SEL0 0x0001 | ||
68 | |||
69 | static struct pci_device_id vrc4173_id_table[] __devinitdata = { | ||
70 | { .vendor = PCI_VENDOR_ID_NEC, | ||
71 | .device = PCI_DEVICE_ID_NEC_VRC4173, | ||
72 | .subvendor = PCI_ANY_ID, | ||
73 | .subdevice = PCI_ANY_ID, }, | ||
74 | { .vendor = 0, }, | ||
75 | }; | ||
76 | |||
77 | unsigned long vrc4173_io_offset = 0; | ||
78 | |||
79 | EXPORT_SYMBOL(vrc4173_io_offset); | ||
80 | |||
81 | static int vrc4173_initialized; | ||
82 | static uint16_t vrc4173_cmuclkmsk; | ||
83 | static uint16_t vrc4173_selectreg; | ||
84 | static spinlock_t vrc4173_cmu_lock; | ||
85 | static spinlock_t vrc4173_giu_lock; | ||
86 | |||
87 | static inline void set_cmusrst(uint16_t val) | ||
88 | { | ||
89 | uint16_t cmusrst; | ||
90 | |||
91 | cmusrst = vrc4173_inw(VRC4173_CMUSRST); | ||
92 | cmusrst |= val; | ||
93 | vrc4173_outw(cmusrst, VRC4173_CMUSRST); | ||
94 | } | ||
95 | |||
96 | static inline void clear_cmusrst(uint16_t val) | ||
97 | { | ||
98 | uint16_t cmusrst; | ||
99 | |||
100 | cmusrst = vrc4173_inw(VRC4173_CMUSRST); | ||
101 | cmusrst &= ~val; | ||
102 | vrc4173_outw(cmusrst, VRC4173_CMUSRST); | ||
103 | } | ||
104 | |||
105 | void vrc4173_supply_clock(vrc4173_clock_t clock) | ||
106 | { | ||
107 | if (vrc4173_initialized) { | ||
108 | spin_lock_irq(&vrc4173_cmu_lock); | ||
109 | |||
110 | switch (clock) { | ||
111 | case VRC4173_PIU_CLOCK: | ||
112 | vrc4173_cmuclkmsk |= MSKPIU; | ||
113 | break; | ||
114 | case VRC4173_KIU_CLOCK: | ||
115 | vrc4173_cmuclkmsk |= MSKKIU; | ||
116 | break; | ||
117 | case VRC4173_AIU_CLOCK: | ||
118 | vrc4173_cmuclkmsk |= MSKAIU; | ||
119 | break; | ||
120 | case VRC4173_PS2_CH1_CLOCK: | ||
121 | vrc4173_cmuclkmsk |= MSKPS2CH1; | ||
122 | break; | ||
123 | case VRC4173_PS2_CH2_CLOCK: | ||
124 | vrc4173_cmuclkmsk |= MSKPS2CH2; | ||
125 | break; | ||
126 | case VRC4173_USBU_PCI_CLOCK: | ||
127 | set_cmusrst(USBRST); | ||
128 | vrc4173_cmuclkmsk |= MSKUSB; | ||
129 | break; | ||
130 | case VRC4173_CARDU1_PCI_CLOCK: | ||
131 | set_cmusrst(CARD1RST); | ||
132 | vrc4173_cmuclkmsk |= MSKCARD1; | ||
133 | break; | ||
134 | case VRC4173_CARDU2_PCI_CLOCK: | ||
135 | set_cmusrst(CARD2RST); | ||
136 | vrc4173_cmuclkmsk |= MSKCARD2; | ||
137 | break; | ||
138 | case VRC4173_AC97U_PCI_CLOCK: | ||
139 | set_cmusrst(AC97RST); | ||
140 | vrc4173_cmuclkmsk |= MSKAC97; | ||
141 | break; | ||
142 | case VRC4173_USBU_48MHz_CLOCK: | ||
143 | set_cmusrst(USBRST); | ||
144 | vrc4173_cmuclkmsk |= MSK48MUSB; | ||
145 | break; | ||
146 | case VRC4173_EXT_48MHz_CLOCK: | ||
147 | if (vrc4173_cmuclkmsk & MSK48MOSC) | ||
148 | vrc4173_cmuclkmsk |= MSK48MPIN; | ||
149 | else | ||
150 | printk(KERN_WARNING | ||
151 | "vrc4173_supply_clock: " | ||
152 | "Please supply VRC4173_48MHz_CLOCK first " | ||
153 | "rather than VRC4173_EXT_48MHz_CLOCK.\n"); | ||
154 | break; | ||
155 | case VRC4173_48MHz_CLOCK: | ||
156 | vrc4173_cmuclkmsk |= MSK48MOSC; | ||
157 | break; | ||
158 | default: | ||
159 | printk(KERN_WARNING | ||
160 | "vrc4173_supply_clock: Invalid CLOCK value %u\n", clock); | ||
161 | break; | ||
162 | } | ||
163 | |||
164 | vrc4173_outw(vrc4173_cmuclkmsk, VRC4173_CMUCLKMSK); | ||
165 | |||
166 | switch (clock) { | ||
167 | case VRC4173_USBU_PCI_CLOCK: | ||
168 | case VRC4173_USBU_48MHz_CLOCK: | ||
169 | clear_cmusrst(USBRST); | ||
170 | break; | ||
171 | case VRC4173_CARDU1_PCI_CLOCK: | ||
172 | clear_cmusrst(CARD1RST); | ||
173 | break; | ||
174 | case VRC4173_CARDU2_PCI_CLOCK: | ||
175 | clear_cmusrst(CARD2RST); | ||
176 | break; | ||
177 | case VRC4173_AC97U_PCI_CLOCK: | ||
178 | clear_cmusrst(AC97RST); | ||
179 | break; | ||
180 | default: | ||
181 | break; | ||
182 | } | ||
183 | |||
184 | spin_unlock_irq(&vrc4173_cmu_lock); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | EXPORT_SYMBOL(vrc4173_supply_clock); | ||
189 | |||
190 | void vrc4173_mask_clock(vrc4173_clock_t clock) | ||
191 | { | ||
192 | if (vrc4173_initialized) { | ||
193 | spin_lock_irq(&vrc4173_cmu_lock); | ||
194 | |||
195 | switch (clock) { | ||
196 | case VRC4173_PIU_CLOCK: | ||
197 | vrc4173_cmuclkmsk &= ~MSKPIU; | ||
198 | break; | ||
199 | case VRC4173_KIU_CLOCK: | ||
200 | vrc4173_cmuclkmsk &= ~MSKKIU; | ||
201 | break; | ||
202 | case VRC4173_AIU_CLOCK: | ||
203 | vrc4173_cmuclkmsk &= ~MSKAIU; | ||
204 | break; | ||
205 | case VRC4173_PS2_CH1_CLOCK: | ||
206 | vrc4173_cmuclkmsk &= ~MSKPS2CH1; | ||
207 | break; | ||
208 | case VRC4173_PS2_CH2_CLOCK: | ||
209 | vrc4173_cmuclkmsk &= ~MSKPS2CH2; | ||
210 | break; | ||
211 | case VRC4173_USBU_PCI_CLOCK: | ||
212 | set_cmusrst(USBRST); | ||
213 | vrc4173_cmuclkmsk &= ~MSKUSB; | ||
214 | break; | ||
215 | case VRC4173_CARDU1_PCI_CLOCK: | ||
216 | set_cmusrst(CARD1RST); | ||
217 | vrc4173_cmuclkmsk &= ~MSKCARD1; | ||
218 | break; | ||
219 | case VRC4173_CARDU2_PCI_CLOCK: | ||
220 | set_cmusrst(CARD2RST); | ||
221 | vrc4173_cmuclkmsk &= ~MSKCARD2; | ||
222 | break; | ||
223 | case VRC4173_AC97U_PCI_CLOCK: | ||
224 | set_cmusrst(AC97RST); | ||
225 | vrc4173_cmuclkmsk &= ~MSKAC97; | ||
226 | break; | ||
227 | case VRC4173_USBU_48MHz_CLOCK: | ||
228 | set_cmusrst(USBRST); | ||
229 | vrc4173_cmuclkmsk &= ~MSK48MUSB; | ||
230 | break; | ||
231 | case VRC4173_EXT_48MHz_CLOCK: | ||
232 | vrc4173_cmuclkmsk &= ~MSK48MPIN; | ||
233 | break; | ||
234 | case VRC4173_48MHz_CLOCK: | ||
235 | vrc4173_cmuclkmsk &= ~MSK48MOSC; | ||
236 | break; | ||
237 | default: | ||
238 | printk(KERN_WARNING "vrc4173_mask_clock: Invalid CLOCK value %u\n", clock); | ||
239 | break; | ||
240 | } | ||
241 | |||
242 | vrc4173_outw(vrc4173_cmuclkmsk, VRC4173_CMUCLKMSK); | ||
243 | |||
244 | switch (clock) { | ||
245 | case VRC4173_USBU_PCI_CLOCK: | ||
246 | case VRC4173_USBU_48MHz_CLOCK: | ||
247 | clear_cmusrst(USBRST); | ||
248 | break; | ||
249 | case VRC4173_CARDU1_PCI_CLOCK: | ||
250 | clear_cmusrst(CARD1RST); | ||
251 | break; | ||
252 | case VRC4173_CARDU2_PCI_CLOCK: | ||
253 | clear_cmusrst(CARD2RST); | ||
254 | break; | ||
255 | case VRC4173_AC97U_PCI_CLOCK: | ||
256 | clear_cmusrst(AC97RST); | ||
257 | break; | ||
258 | default: | ||
259 | break; | ||
260 | } | ||
261 | |||
262 | spin_unlock_irq(&vrc4173_cmu_lock); | ||
263 | } | ||
264 | } | ||
265 | |||
266 | EXPORT_SYMBOL(vrc4173_mask_clock); | ||
267 | |||
268 | static inline void vrc4173_cmu_init(void) | ||
269 | { | ||
270 | vrc4173_cmuclkmsk = vrc4173_inw(VRC4173_CMUCLKMSK); | ||
271 | |||
272 | spin_lock_init(&vrc4173_cmu_lock); | ||
273 | } | ||
274 | |||
275 | void vrc4173_select_function(vrc4173_function_t function) | ||
276 | { | ||
277 | if (vrc4173_initialized) { | ||
278 | spin_lock_irq(&vrc4173_giu_lock); | ||
279 | |||
280 | switch(function) { | ||
281 | case PS2_CHANNEL1: | ||
282 | vrc4173_selectreg |= SEL2; | ||
283 | break; | ||
284 | case PS2_CHANNEL2: | ||
285 | vrc4173_selectreg |= SEL1; | ||
286 | break; | ||
287 | case TOUCHPANEL: | ||
288 | vrc4173_selectreg &= SEL2 | SEL1 | SEL0; | ||
289 | break; | ||
290 | case KEYBOARD_8SCANLINES: | ||
291 | vrc4173_selectreg &= SEL3 | SEL2 | SEL1; | ||
292 | break; | ||
293 | case KEYBOARD_10SCANLINES: | ||
294 | vrc4173_selectreg &= SEL3 | SEL2; | ||
295 | break; | ||
296 | case KEYBOARD_12SCANLINES: | ||
297 | vrc4173_selectreg &= SEL3; | ||
298 | break; | ||
299 | case GPIO_0_15PINS: | ||
300 | vrc4173_selectreg |= SEL0; | ||
301 | break; | ||
302 | case GPIO_16_20PINS: | ||
303 | vrc4173_selectreg |= SEL3; | ||
304 | break; | ||
305 | } | ||
306 | |||
307 | vrc4173_outw(vrc4173_selectreg, VRC4173_SELECTREG); | ||
308 | |||
309 | spin_unlock_irq(&vrc4173_giu_lock); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | EXPORT_SYMBOL(vrc4173_select_function); | ||
314 | |||
315 | static inline void vrc4173_giu_init(void) | ||
316 | { | ||
317 | vrc4173_selectreg = vrc4173_inw(VRC4173_SELECTREG); | ||
318 | |||
319 | spin_lock_init(&vrc4173_giu_lock); | ||
320 | } | ||
321 | |||
322 | void vrc4173_enable_piuint(uint16_t mask) | ||
323 | { | ||
324 | irq_desc_t *desc = irq_desc + VRC4173_PIU_IRQ; | ||
325 | unsigned long flags; | ||
326 | uint16_t val; | ||
327 | |||
328 | spin_lock_irqsave(&desc->lock, flags); | ||
329 | val = vrc4173_inw(VRC4173_MPIUINTREG); | ||
330 | val |= mask; | ||
331 | vrc4173_outw(val, VRC4173_MPIUINTREG); | ||
332 | spin_unlock_irqrestore(&desc->lock, flags); | ||
333 | } | ||
334 | |||
335 | EXPORT_SYMBOL(vrc4173_enable_piuint); | ||
336 | |||
337 | void vrc4173_disable_piuint(uint16_t mask) | ||
338 | { | ||
339 | irq_desc_t *desc = irq_desc + VRC4173_PIU_IRQ; | ||
340 | unsigned long flags; | ||
341 | uint16_t val; | ||
342 | |||
343 | spin_lock_irqsave(&desc->lock, flags); | ||
344 | val = vrc4173_inw(VRC4173_MPIUINTREG); | ||
345 | val &= ~mask; | ||
346 | vrc4173_outw(val, VRC4173_MPIUINTREG); | ||
347 | spin_unlock_irqrestore(&desc->lock, flags); | ||
348 | } | ||
349 | |||
350 | EXPORT_SYMBOL(vrc4173_disable_piuint); | ||
351 | |||
352 | void vrc4173_enable_aiuint(uint16_t mask) | ||
353 | { | ||
354 | irq_desc_t *desc = irq_desc + VRC4173_AIU_IRQ; | ||
355 | unsigned long flags; | ||
356 | uint16_t val; | ||
357 | |||
358 | spin_lock_irqsave(&desc->lock, flags); | ||
359 | val = vrc4173_inw(VRC4173_MAIUINTREG); | ||
360 | val |= mask; | ||
361 | vrc4173_outw(val, VRC4173_MAIUINTREG); | ||
362 | spin_unlock_irqrestore(&desc->lock, flags); | ||
363 | } | ||
364 | |||
365 | EXPORT_SYMBOL(vrc4173_enable_aiuint); | ||
366 | |||
367 | void vrc4173_disable_aiuint(uint16_t mask) | ||
368 | { | ||
369 | irq_desc_t *desc = irq_desc + VRC4173_AIU_IRQ; | ||
370 | unsigned long flags; | ||
371 | uint16_t val; | ||
372 | |||
373 | spin_lock_irqsave(&desc->lock, flags); | ||
374 | val = vrc4173_inw(VRC4173_MAIUINTREG); | ||
375 | val &= ~mask; | ||
376 | vrc4173_outw(val, VRC4173_MAIUINTREG); | ||
377 | spin_unlock_irqrestore(&desc->lock, flags); | ||
378 | } | ||
379 | |||
380 | EXPORT_SYMBOL(vrc4173_disable_aiuint); | ||
381 | |||
382 | void vrc4173_enable_kiuint(uint16_t mask) | ||
383 | { | ||
384 | irq_desc_t *desc = irq_desc + VRC4173_KIU_IRQ; | ||
385 | unsigned long flags; | ||
386 | uint16_t val; | ||
387 | |||
388 | spin_lock_irqsave(&desc->lock, flags); | ||
389 | val = vrc4173_inw(VRC4173_MKIUINTREG); | ||
390 | val |= mask; | ||
391 | vrc4173_outw(val, VRC4173_MKIUINTREG); | ||
392 | spin_unlock_irqrestore(&desc->lock, flags); | ||
393 | } | ||
394 | |||
395 | EXPORT_SYMBOL(vrc4173_enable_kiuint); | ||
396 | |||
397 | void vrc4173_disable_kiuint(uint16_t mask) | ||
398 | { | ||
399 | irq_desc_t *desc = irq_desc + VRC4173_KIU_IRQ; | ||
400 | unsigned long flags; | ||
401 | uint16_t val; | ||
402 | |||
403 | spin_lock_irqsave(&desc->lock, flags); | ||
404 | val = vrc4173_inw(VRC4173_MKIUINTREG); | ||
405 | val &= ~mask; | ||
406 | vrc4173_outw(val, VRC4173_MKIUINTREG); | ||
407 | spin_unlock_irqrestore(&desc->lock, flags); | ||
408 | } | ||
409 | |||
410 | EXPORT_SYMBOL(vrc4173_disable_kiuint); | ||
411 | |||
412 | static void enable_vrc4173_irq(unsigned int irq) | ||
413 | { | ||
414 | uint16_t val; | ||
415 | |||
416 | val = vrc4173_inw(VRC4173_MSYSINT1REG); | ||
417 | val |= (uint16_t)1 << (irq - VRC4173_IRQ_BASE); | ||
418 | vrc4173_outw(val, VRC4173_MSYSINT1REG); | ||
419 | } | ||
420 | |||
421 | static void disable_vrc4173_irq(unsigned int irq) | ||
422 | { | ||
423 | uint16_t val; | ||
424 | |||
425 | val = vrc4173_inw(VRC4173_MSYSINT1REG); | ||
426 | val &= ~((uint16_t)1 << (irq - VRC4173_IRQ_BASE)); | ||
427 | vrc4173_outw(val, VRC4173_MSYSINT1REG); | ||
428 | } | ||
429 | |||
430 | static unsigned int startup_vrc4173_irq(unsigned int irq) | ||
431 | { | ||
432 | enable_vrc4173_irq(irq); | ||
433 | return 0; /* never anything pending */ | ||
434 | } | ||
435 | |||
436 | #define shutdown_vrc4173_irq disable_vrc4173_irq | ||
437 | #define ack_vrc4173_irq disable_vrc4173_irq | ||
438 | |||
439 | static void end_vrc4173_irq(unsigned int irq) | ||
440 | { | ||
441 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
442 | enable_vrc4173_irq(irq); | ||
443 | } | ||
444 | |||
445 | static struct hw_interrupt_type vrc4173_irq_type = { | ||
446 | .typename = "VRC4173", | ||
447 | .startup = startup_vrc4173_irq, | ||
448 | .shutdown = shutdown_vrc4173_irq, | ||
449 | .enable = enable_vrc4173_irq, | ||
450 | .disable = disable_vrc4173_irq, | ||
451 | .ack = ack_vrc4173_irq, | ||
452 | .end = end_vrc4173_irq, | ||
453 | }; | ||
454 | |||
455 | static int vrc4173_get_irq_number(int irq) | ||
456 | { | ||
457 | uint16_t status, mask; | ||
458 | int i; | ||
459 | |||
460 | status = vrc4173_inw(VRC4173_SYSINT1REG); | ||
461 | mask = vrc4173_inw(VRC4173_MSYSINT1REG); | ||
462 | |||
463 | status &= mask; | ||
464 | if (status) { | ||
465 | for (i = 0; i < 16; i++) | ||
466 | if (status & (0x0001 << i)) | ||
467 | return VRC4173_IRQ(i); | ||
468 | } | ||
469 | |||
470 | return -EINVAL; | ||
471 | } | ||
472 | |||
473 | static inline int vrc4173_icu_init(int cascade_irq) | ||
474 | { | ||
475 | int i; | ||
476 | |||
477 | if (cascade_irq < GIU_IRQ(0) || cascade_irq > GIU_IRQ(15)) | ||
478 | return -EINVAL; | ||
479 | |||
480 | vrc4173_outw(0, VRC4173_MSYSINT1REG); | ||
481 | |||
482 | vr41xx_set_irq_trigger(GIU_IRQ_TO_PIN(cascade_irq), TRIGGER_LEVEL, SIGNAL_THROUGH); | ||
483 | vr41xx_set_irq_level(GIU_IRQ_TO_PIN(cascade_irq), LEVEL_LOW); | ||
484 | |||
485 | for (i = VRC4173_IRQ_BASE; i <= VRC4173_IRQ_LAST; i++) | ||
486 | irq_desc[i].handler = &vrc4173_irq_type; | ||
487 | |||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static int __devinit vrc4173_probe(struct pci_dev *dev, | ||
492 | const struct pci_device_id *id) | ||
493 | { | ||
494 | unsigned long start, flags; | ||
495 | int err; | ||
496 | |||
497 | err = pci_enable_device(dev); | ||
498 | if (err < 0) { | ||
499 | printk(KERN_ERR "vrc4173: Failed to enable PCI device, aborting\n"); | ||
500 | return err; | ||
501 | } | ||
502 | |||
503 | pci_set_master(dev); | ||
504 | |||
505 | start = pci_resource_start(dev, 0); | ||
506 | if (start == 0) { | ||
507 | printk(KERN_ERR "vrc4173:No such PCI I/O resource, aborting\n"); | ||
508 | return -ENXIO; | ||
509 | } | ||
510 | |||
511 | flags = pci_resource_flags(dev, 0); | ||
512 | if ((flags & IORESOURCE_IO) == 0) { | ||
513 | printk(KERN_ERR "vrc4173: No such PCI I/O resource, aborting\n"); | ||
514 | return -ENXIO; | ||
515 | } | ||
516 | |||
517 | err = pci_request_regions(dev, "NEC VRC4173"); | ||
518 | if (err < 0) { | ||
519 | printk(KERN_ERR "vrc4173: PCI resources are busy, aborting\n"); | ||
520 | return err; | ||
521 | } | ||
522 | |||
523 | set_vrc4173_io_offset(start); | ||
524 | |||
525 | vrc4173_cmu_init(); | ||
526 | vrc4173_giu_init(); | ||
527 | |||
528 | err = vrc4173_icu_init(dev->irq); | ||
529 | if (err < 0) { | ||
530 | printk(KERN_ERR "vrc4173: Invalid IRQ %d, aborting\n", dev->irq); | ||
531 | return err; | ||
532 | } | ||
533 | |||
534 | err = vr41xx_cascade_irq(dev->irq, vrc4173_get_irq_number); | ||
535 | if (err < 0) { | ||
536 | printk(KERN_ERR "vrc4173: IRQ resource %d is busy, aborting\n", dev->irq); | ||
537 | return err; | ||
538 | } | ||
539 | |||
540 | printk(KERN_INFO | ||
541 | "NEC VRC4173 at 0x%#08lx, IRQ is cascaded to %d\n", start, dev->irq); | ||
542 | |||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | static void vrc4173_remove(struct pci_dev *dev) | ||
547 | { | ||
548 | free_irq(dev->irq, NULL); | ||
549 | |||
550 | pci_release_regions(dev); | ||
551 | } | ||
552 | |||
553 | static struct pci_driver vrc4173_driver = { | ||
554 | .name = "NEC VRC4173", | ||
555 | .probe = vrc4173_probe, | ||
556 | .remove = vrc4173_remove, | ||
557 | .id_table = vrc4173_id_table, | ||
558 | }; | ||
559 | |||
560 | static int __devinit vrc4173_init(void) | ||
561 | { | ||
562 | int err; | ||
563 | |||
564 | err = pci_module_init(&vrc4173_driver); | ||
565 | if (err < 0) | ||
566 | return err; | ||
567 | |||
568 | vrc4173_initialized = 1; | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static void __devexit vrc4173_exit(void) | ||
574 | { | ||
575 | vrc4173_initialized = 0; | ||
576 | |||
577 | pci_unregister_driver(&vrc4173_driver); | ||
578 | } | ||
579 | |||
580 | module_init(vrc4173_init); | ||
581 | module_exit(vrc4173_exit); | ||
diff --git a/arch/mips/vr41xx/ibm-workpad/Makefile b/arch/mips/vr41xx/ibm-workpad/Makefile new file mode 100644 index 000000000000..5ffaff0f0f89 --- /dev/null +++ b/arch/mips/vr41xx/ibm-workpad/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for the IBM WorkPad z50 specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y += setup.o | ||
diff --git a/arch/mips/vr41xx/ibm-workpad/setup.c b/arch/mips/vr41xx/ibm-workpad/setup.c new file mode 100644 index 000000000000..cff44602d3d4 --- /dev/null +++ b/arch/mips/vr41xx/ibm-workpad/setup.c | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * setup.c, Setup for the IBM WorkPad z50. | ||
3 | * | ||
4 | * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
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; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/ioport.h> | ||
22 | |||
23 | #include <asm/io.h> | ||
24 | #include <asm/vr41xx/workpad.h> | ||
25 | |||
26 | const char *get_system_type(void) | ||
27 | { | ||
28 | return "IBM WorkPad z50"; | ||
29 | } | ||
30 | |||
31 | static int __init ibm_workpad_setup(void) | ||
32 | { | ||
33 | set_io_port_base(IO_PORT_BASE); | ||
34 | ioport_resource.start = IO_PORT_RESOURCE_START; | ||
35 | ioport_resource.end = IO_PORT_RESOURCE_END; | ||
36 | |||
37 | return 0; | ||
38 | } | ||
39 | |||
40 | arch_initcall(ibm_workpad_setup); | ||
diff --git a/arch/mips/vr41xx/nec-cmbvr4133/Makefile b/arch/mips/vr41xx/nec-cmbvr4133/Makefile new file mode 100644 index 000000000000..5835cae54aca --- /dev/null +++ b/arch/mips/vr41xx/nec-cmbvr4133/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for the NEC-CMBVR4133 | ||
3 | # | ||
4 | |||
5 | obj-y := init.o setup.o | ||
6 | |||
7 | obj-$(CONFIG_PCI) += m1535plus.o | ||
8 | obj-$(CONFIG_ROCKHOPPER) += irq.o | ||
diff --git a/arch/mips/vr41xx/nec-cmbvr4133/init.c b/arch/mips/vr41xx/nec-cmbvr4133/init.c new file mode 100644 index 000000000000..87f06b3f5a9c --- /dev/null +++ b/arch/mips/vr41xx/nec-cmbvr4133/init.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * arch/mips/vr41xx/nec-cmbvr4133/init.c | ||
3 | * | ||
4 | * PROM library initialisation code for NEC CMB-VR4133 board. | ||
5 | * | ||
6 | * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com> and | ||
7 | * Jun Sun <jsun@mvista.com, or source@mvista.com> and | ||
8 | * Alex Sapkov <asapkov@ru.mvista.com> | ||
9 | * | ||
10 | * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under | ||
11 | * the terms of the GNU General Public License version 2. This program | ||
12 | * is licensed "as is" without any warranty of any kind, whether express | ||
13 | * or implied. | ||
14 | * | ||
15 | * Support for NEC-CMBVR4133 in 2.6 | ||
16 | * Manish Lachwani (mlachwani@mvista.com) | ||
17 | */ | ||
18 | #include <linux/config.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/string.h> | ||
22 | |||
23 | #include <asm/bootinfo.h> | ||
24 | |||
25 | #ifdef CONFIG_ROCKHOPPER | ||
26 | #include <asm/io.h> | ||
27 | #include <linux/pci.h> | ||
28 | |||
29 | #define PCICONFDREG 0xaf000c14 | ||
30 | #define PCICONFAREG 0xaf000c18 | ||
31 | #endif | ||
32 | |||
33 | const char *get_system_type(void) | ||
34 | { | ||
35 | return "NEC CMB-VR4133"; | ||
36 | } | ||
37 | |||
38 | #ifdef CONFIG_ROCKHOPPER | ||
39 | void disable_pcnet(void) | ||
40 | { | ||
41 | u32 data; | ||
42 | |||
43 | /* | ||
44 | * Workaround for the bug in PMON on VR4133. PMON leaves | ||
45 | * AMD PCNet controller (on Rockhopper) initialized and running in | ||
46 | * bus master mode. We have do disable it before doing any | ||
47 | * further initialization. Or we get problems with PCI bus 2 | ||
48 | * and random lockups and crashes. | ||
49 | */ | ||
50 | |||
51 | writel((2 << 16) | | ||
52 | (PCI_DEVFN(1,0) << 8) | | ||
53 | (0 & 0xfc) | | ||
54 | 1UL, | ||
55 | PCICONFAREG); | ||
56 | |||
57 | data = readl(PCICONFDREG); | ||
58 | |||
59 | writel((2 << 16) | | ||
60 | (PCI_DEVFN(1,0) << 8) | | ||
61 | (4 & 0xfc) | | ||
62 | 1UL, | ||
63 | PCICONFAREG); | ||
64 | |||
65 | data = readl(PCICONFDREG); | ||
66 | |||
67 | writel((2 << 16) | | ||
68 | (PCI_DEVFN(1,0) << 8) | | ||
69 | (4 & 0xfc) | | ||
70 | 1UL, | ||
71 | PCICONFAREG); | ||
72 | |||
73 | data &= ~4; | ||
74 | |||
75 | writel(data, PCICONFDREG); | ||
76 | } | ||
77 | #endif | ||
78 | |||
diff --git a/arch/mips/vr41xx/nec-cmbvr4133/irq.c b/arch/mips/vr41xx/nec-cmbvr4133/irq.c new file mode 100644 index 000000000000..31db6b61a39e --- /dev/null +++ b/arch/mips/vr41xx/nec-cmbvr4133/irq.c | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * arch/mips/vr41xx/nec-cmbvr4133/irq.c | ||
3 | * | ||
4 | * Interrupt routines for the NEC CMB-VR4133 board. | ||
5 | * | ||
6 | * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com> and | ||
7 | * Alex Sapkov <asapkov@ru.mvista.com> | ||
8 | * | ||
9 | * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under | ||
10 | * the terms of the GNU General Public License version 2. This program | ||
11 | * is licensed "as is" without any warranty of any kind, whether express | ||
12 | * or implied. | ||
13 | * | ||
14 | * Support for NEC-CMBVR4133 in 2.6 | ||
15 | * Manish Lachwani (mlachwani@mvista.com) | ||
16 | */ | ||
17 | #include <linux/bitops.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/ioport.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | |||
23 | #include <asm/io.h> | ||
24 | #include <asm/vr41xx/cmbvr4133.h> | ||
25 | |||
26 | extern void enable_8259A_irq(unsigned int irq); | ||
27 | extern void disable_8259A_irq(unsigned int irq); | ||
28 | extern void mask_and_ack_8259A(unsigned int irq); | ||
29 | extern void init_8259A(int hoge); | ||
30 | |||
31 | extern int vr4133_rockhopper; | ||
32 | |||
33 | static unsigned int startup_i8259_irq(unsigned int irq) | ||
34 | { | ||
35 | enable_8259A_irq(irq - I8259_IRQ_BASE); | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static void shutdown_i8259_irq(unsigned int irq) | ||
40 | { | ||
41 | disable_8259A_irq(irq - I8259_IRQ_BASE); | ||
42 | } | ||
43 | |||
44 | static void enable_i8259_irq(unsigned int irq) | ||
45 | { | ||
46 | enable_8259A_irq(irq - I8259_IRQ_BASE); | ||
47 | } | ||
48 | |||
49 | static void disable_i8259_irq(unsigned int irq) | ||
50 | { | ||
51 | disable_8259A_irq(irq - I8259_IRQ_BASE); | ||
52 | } | ||
53 | |||
54 | static void ack_i8259_irq(unsigned int irq) | ||
55 | { | ||
56 | mask_and_ack_8259A(irq - I8259_IRQ_BASE); | ||
57 | } | ||
58 | |||
59 | static void end_i8259_irq(unsigned int irq) | ||
60 | { | ||
61 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
62 | enable_8259A_irq(irq - I8259_IRQ_BASE); | ||
63 | } | ||
64 | |||
65 | static struct hw_interrupt_type i8259_irq_type = { | ||
66 | .typename = "XT-PIC", | ||
67 | .startup = startup_i8259_irq, | ||
68 | .shutdown = shutdown_i8259_irq, | ||
69 | .enable = enable_i8259_irq, | ||
70 | .disable = disable_i8259_irq, | ||
71 | .ack = ack_i8259_irq, | ||
72 | .end = end_i8259_irq, | ||
73 | }; | ||
74 | |||
75 | static int i8259_get_irq_number(int irq) | ||
76 | { | ||
77 | unsigned long isr; | ||
78 | |||
79 | isr = inb(0x20); | ||
80 | irq = ffz(~isr); | ||
81 | if (irq == 2) { | ||
82 | isr = inb(0xa0); | ||
83 | irq = 8 + ffz(~isr); | ||
84 | } | ||
85 | |||
86 | if (irq < 0 || irq > 15) | ||
87 | return -EINVAL; | ||
88 | |||
89 | return I8259_IRQ_BASE + irq; | ||
90 | } | ||
91 | |||
92 | static struct irqaction i8259_slave_cascade = { | ||
93 | .handler = &no_action, | ||
94 | .name = "cascade", | ||
95 | }; | ||
96 | |||
97 | void __init rockhopper_init_irq(void) | ||
98 | { | ||
99 | int i; | ||
100 | |||
101 | if(!vr4133_rockhopper) { | ||
102 | printk(KERN_ERR "Not a Rockhopper Board \n"); | ||
103 | return; | ||
104 | } | ||
105 | |||
106 | for (i = I8259_IRQ_BASE; i <= I8259_IRQ_LAST; i++) | ||
107 | irq_desc[i].handler = &i8259_irq_type; | ||
108 | |||
109 | setup_irq(I8259_SLAVE_IRQ, &i8259_slave_cascade); | ||
110 | |||
111 | vr41xx_set_irq_trigger(CMBVR41XX_INTC_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH); | ||
112 | vr41xx_set_irq_level(CMBVR41XX_INTC_PIN, LEVEL_HIGH); | ||
113 | vr41xx_cascade_irq(CMBVR41XX_INTC_IRQ, i8259_get_irq_number); | ||
114 | } | ||
diff --git a/arch/mips/vr41xx/nec-cmbvr4133/m1535plus.c b/arch/mips/vr41xx/nec-cmbvr4133/m1535plus.c new file mode 100644 index 000000000000..1f6b24ef8695 --- /dev/null +++ b/arch/mips/vr41xx/nec-cmbvr4133/m1535plus.c | |||
@@ -0,0 +1,250 @@ | |||
1 | /* | ||
2 | * arch/mips/vr41xx/nec-cmbvr4133/m1535plus.c | ||
3 | * | ||
4 | * Initialize for ALi M1535+(included M5229 and M5237). | ||
5 | * | ||
6 | * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com> and | ||
7 | * Alex Sapkov <asapkov@ru.mvista.com> | ||
8 | * | ||
9 | * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under | ||
10 | * the terms of the GNU General Public License version 2. This program | ||
11 | * is licensed "as is" without any warranty of any kind, whether express | ||
12 | * or implied. | ||
13 | * | ||
14 | * Support for NEC-CMBVR4133 in 2.6 | ||
15 | * Author: Manish Lachwani (mlachwani@mvista.com) | ||
16 | */ | ||
17 | #include <linux/config.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/serial.h> | ||
21 | |||
22 | #include <asm/vr41xx/cmbvr4133.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <asm/io.h> | ||
25 | |||
26 | #define CONFIG_PORT(port) ((port) ? 0x3f0 : 0x370) | ||
27 | #define DATA_PORT(port) ((port) ? 0x3f1 : 0x371) | ||
28 | #define INDEX_PORT(port) CONFIG_PORT(port) | ||
29 | |||
30 | #define ENTER_CONFIG_MODE(port) \ | ||
31 | do { \ | ||
32 | outb_p(0x51, CONFIG_PORT(port)); \ | ||
33 | outb_p(0x23, CONFIG_PORT(port)); \ | ||
34 | } while(0) | ||
35 | |||
36 | #define SELECT_LOGICAL_DEVICE(port, dev_no) \ | ||
37 | do { \ | ||
38 | outb_p(0x07, INDEX_PORT(port)); \ | ||
39 | outb_p((dev_no), DATA_PORT(port)); \ | ||
40 | } while(0) | ||
41 | |||
42 | #define WRITE_CONFIG_DATA(port,index,data) \ | ||
43 | do { \ | ||
44 | outb_p((index), INDEX_PORT(port)); \ | ||
45 | outb_p((data), DATA_PORT(port)); \ | ||
46 | } while(0) | ||
47 | |||
48 | #define EXIT_CONFIG_MODE(port) outb(0xbb, CONFIG_PORT(port)) | ||
49 | |||
50 | #define PCI_CONFIG_ADDR KSEG1ADDR(0x0f000c18) | ||
51 | #define PCI_CONFIG_DATA KSEG1ADDR(0x0f000c14) | ||
52 | |||
53 | #ifdef CONFIG_BLK_DEV_FD | ||
54 | |||
55 | void __devinit ali_m1535plus_fdc_init(int port) | ||
56 | { | ||
57 | ENTER_CONFIG_MODE(port); | ||
58 | SELECT_LOGICAL_DEVICE(port, 0); /* FDC */ | ||
59 | WRITE_CONFIG_DATA(port, 0x30, 0x01); /* FDC: enable */ | ||
60 | WRITE_CONFIG_DATA(port, 0x60, 0x03); /* I/O port base: 0x3f0 */ | ||
61 | WRITE_CONFIG_DATA(port, 0x61, 0xf0); | ||
62 | WRITE_CONFIG_DATA(port, 0x70, 0x06); /* IRQ: 6 */ | ||
63 | WRITE_CONFIG_DATA(port, 0x74, 0x02); /* DMA: channel 2 */ | ||
64 | WRITE_CONFIG_DATA(port, 0xf0, 0x08); | ||
65 | WRITE_CONFIG_DATA(port, 0xf1, 0x00); | ||
66 | WRITE_CONFIG_DATA(port, 0xf2, 0xff); | ||
67 | WRITE_CONFIG_DATA(port, 0xf4, 0x00); | ||
68 | EXIT_CONFIG_MODE(port); | ||
69 | } | ||
70 | |||
71 | #endif | ||
72 | |||
73 | void __devinit ali_m1535plus_parport_init(int port) | ||
74 | { | ||
75 | ENTER_CONFIG_MODE(port); | ||
76 | SELECT_LOGICAL_DEVICE(port, 3); /* Parallel Port */ | ||
77 | WRITE_CONFIG_DATA(port, 0x30, 0x01); | ||
78 | WRITE_CONFIG_DATA(port, 0x60, 0x03); /* I/O port base: 0x378 */ | ||
79 | WRITE_CONFIG_DATA(port, 0x61, 0x78); | ||
80 | WRITE_CONFIG_DATA(port, 0x70, 0x07); /* IRQ: 7 */ | ||
81 | WRITE_CONFIG_DATA(port, 0x74, 0x04); /* DMA: None */ | ||
82 | WRITE_CONFIG_DATA(port, 0xf0, 0x8c); /* IRQ polarity: Active Low */ | ||
83 | WRITE_CONFIG_DATA(port, 0xf1, 0xc5); | ||
84 | EXIT_CONFIG_MODE(port); | ||
85 | } | ||
86 | |||
87 | void __devinit ali_m1535plus_keyboard_init(int port) | ||
88 | { | ||
89 | ENTER_CONFIG_MODE(port); | ||
90 | SELECT_LOGICAL_DEVICE(port, 7); /* KEYBOARD */ | ||
91 | WRITE_CONFIG_DATA(port, 0x30, 0x01); /* KEYBOARD: eable */ | ||
92 | WRITE_CONFIG_DATA(port, 0x70, 0x01); /* IRQ: 1 */ | ||
93 | WRITE_CONFIG_DATA(port, 0x72, 0x0c); /* PS/2 Mouse IRQ: 12 */ | ||
94 | WRITE_CONFIG_DATA(port, 0xf0, 0x00); | ||
95 | EXIT_CONFIG_MODE(port); | ||
96 | } | ||
97 | |||
98 | void __devinit ali_m1535plus_hotkey_init(int port) | ||
99 | { | ||
100 | ENTER_CONFIG_MODE(port); | ||
101 | SELECT_LOGICAL_DEVICE(port, 0xc); /* HOTKEY */ | ||
102 | WRITE_CONFIG_DATA(port, 0x30, 0x00); | ||
103 | WRITE_CONFIG_DATA(port, 0xf0, 0x35); | ||
104 | WRITE_CONFIG_DATA(port, 0xf1, 0x14); | ||
105 | WRITE_CONFIG_DATA(port, 0xf2, 0x11); | ||
106 | WRITE_CONFIG_DATA(port, 0xf3, 0x71); | ||
107 | WRITE_CONFIG_DATA(port, 0xf5, 0x05); | ||
108 | EXIT_CONFIG_MODE(port); | ||
109 | } | ||
110 | |||
111 | void ali_m1535plus_init(struct pci_dev *dev) | ||
112 | { | ||
113 | pci_write_config_byte(dev, 0x40, 0x18); /* PCI Interface Control */ | ||
114 | pci_write_config_byte(dev, 0x41, 0xc0); /* PS2 keyb & mouse enable */ | ||
115 | pci_write_config_byte(dev, 0x42, 0x41); /* ISA bus cycle control */ | ||
116 | pci_write_config_byte(dev, 0x43, 0x00); /* ISA bus cycle control 2 */ | ||
117 | pci_write_config_byte(dev, 0x44, 0x5d); /* IDE enable & IRQ 14 */ | ||
118 | pci_write_config_byte(dev, 0x45, 0x0b); /* PCI int polling mode */ | ||
119 | pci_write_config_byte(dev, 0x47, 0x00); /* BIOS chip select control */ | ||
120 | |||
121 | /* IRQ routing */ | ||
122 | pci_write_config_byte(dev, 0x48, 0x03); /* INTA IRQ10, INTB disable */ | ||
123 | pci_write_config_byte(dev, 0x49, 0x00); /* INTC and INTD disable */ | ||
124 | pci_write_config_byte(dev, 0x4a, 0x00); /* INTE and INTF disable */ | ||
125 | pci_write_config_byte(dev, 0x4b, 0x90); /* Audio IRQ11, Modem disable */ | ||
126 | |||
127 | pci_write_config_word(dev, 0x50, 0x4000); /* Parity check IDE enable */ | ||
128 | pci_write_config_word(dev, 0x52, 0x0000); /* USB & RTC disable */ | ||
129 | pci_write_config_word(dev, 0x54, 0x0002); /* ??? no info */ | ||
130 | pci_write_config_word(dev, 0x56, 0x0002); /* PCS1J signal disable */ | ||
131 | |||
132 | pci_write_config_byte(dev, 0x59, 0x00); /* PCSDS */ | ||
133 | pci_write_config_byte(dev, 0x5a, 0x00); | ||
134 | pci_write_config_byte(dev, 0x5b, 0x00); | ||
135 | pci_write_config_word(dev, 0x5c, 0x0000); | ||
136 | pci_write_config_byte(dev, 0x5e, 0x00); | ||
137 | pci_write_config_byte(dev, 0x5f, 0x00); | ||
138 | pci_write_config_word(dev, 0x60, 0x0000); | ||
139 | |||
140 | pci_write_config_byte(dev, 0x6c, 0x00); | ||
141 | pci_write_config_byte(dev, 0x6d, 0x48); /* ROM address mapping */ | ||
142 | pci_write_config_byte(dev, 0x6e, 0x00); /* ??? what for? */ | ||
143 | |||
144 | pci_write_config_byte(dev, 0x70, 0x12); /* Serial IRQ control */ | ||
145 | pci_write_config_byte(dev, 0x71, 0xEF); /* DMA channel select */ | ||
146 | pci_write_config_byte(dev, 0x72, 0x03); /* USB IDSEL */ | ||
147 | pci_write_config_byte(dev, 0x73, 0x00); /* ??? no info */ | ||
148 | |||
149 | /* | ||
150 | * IRQ setup ALi M5237 USB Host Controller | ||
151 | * IRQ: 9 | ||
152 | */ | ||
153 | pci_write_config_byte(dev, 0x74, 0x01); /* USB IRQ9 */ | ||
154 | |||
155 | pci_write_config_byte(dev, 0x75, 0x1f); /* IDE2 IRQ 15 */ | ||
156 | pci_write_config_byte(dev, 0x76, 0x80); /* ACPI disable */ | ||
157 | pci_write_config_byte(dev, 0x77, 0x40); /* Modem disable */ | ||
158 | pci_write_config_dword(dev, 0x78, 0x20000000); /* Pin select 2 */ | ||
159 | pci_write_config_byte(dev, 0x7c, 0x00); /* Pin select 3 */ | ||
160 | pci_write_config_byte(dev, 0x81, 0x00); /* ID read/write control */ | ||
161 | pci_write_config_byte(dev, 0x90, 0x00); /* PCI PM block control */ | ||
162 | pci_write_config_word(dev, 0xa4, 0x0000); /* PMSCR */ | ||
163 | |||
164 | #ifdef CONFIG_BLK_DEV_FD | ||
165 | ali_m1535plus_fdc_init(1); | ||
166 | #endif | ||
167 | |||
168 | ali_m1535plus_keyboard_init(1); | ||
169 | ali_m1535plus_hotkey_init(1); | ||
170 | } | ||
171 | |||
172 | static inline void ali_config_writeb(u8 reg, u8 val, int devfn) | ||
173 | { | ||
174 | u32 data; | ||
175 | int shift; | ||
176 | |||
177 | writel((1 << 16) | (devfn << 8) | (reg & 0xfc) | 1UL, PCI_CONFIG_ADDR); | ||
178 | data = readl(PCI_CONFIG_DATA); | ||
179 | |||
180 | shift = (reg & 3) << 3; | ||
181 | data &= ~(0xff << shift); | ||
182 | data |= (((u32)val) << shift); | ||
183 | |||
184 | writel(data, PCI_CONFIG_DATA); | ||
185 | } | ||
186 | |||
187 | static inline u8 ali_config_readb(u8 reg, int devfn) | ||
188 | { | ||
189 | u32 data; | ||
190 | |||
191 | writel((1 << 16) | (devfn << 8) | (reg & 0xfc) | 1UL, PCI_CONFIG_ADDR); | ||
192 | data = readl(PCI_CONFIG_DATA); | ||
193 | |||
194 | return (u8)(data >> ((reg & 3) << 3)); | ||
195 | } | ||
196 | |||
197 | static inline u16 ali_config_readw(u8 reg, int devfn) | ||
198 | { | ||
199 | u32 data; | ||
200 | |||
201 | writel((1 << 16) | (devfn << 8) | (reg & 0xfc) | 1UL, PCI_CONFIG_ADDR); | ||
202 | data = readl(PCI_CONFIG_DATA); | ||
203 | |||
204 | return (u16)(data >> ((reg & 2) << 3)); | ||
205 | } | ||
206 | |||
207 | int vr4133_rockhopper = 0; | ||
208 | void __init ali_m5229_preinit(void) | ||
209 | { | ||
210 | if (ali_config_readw(PCI_VENDOR_ID,16) == PCI_VENDOR_ID_AL && | ||
211 | ali_config_readw(PCI_DEVICE_ID,16) == PCI_DEVICE_ID_AL_M1533) { | ||
212 | printk(KERN_INFO "Found an NEC Rockhopper \n"); | ||
213 | vr4133_rockhopper = 1; | ||
214 | /* | ||
215 | * Enable ALi M5229 IDE Controller (both channels) | ||
216 | * IDSEL: A27 | ||
217 | */ | ||
218 | ali_config_writeb(0x58, 0x4c, 16); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | void __init ali_m5229_init(struct pci_dev *dev) | ||
223 | { | ||
224 | /* | ||
225 | * Enable Primary/Secondary Channel Cable Detect 40-Pin | ||
226 | */ | ||
227 | pci_write_config_word(dev, 0x4a, 0xc023); | ||
228 | |||
229 | /* | ||
230 | * Set only the 3rd byteis for the master IDE's cycle and | ||
231 | * enable Internal IDE Function | ||
232 | */ | ||
233 | pci_write_config_byte(dev, 0x50, 0x23); /* Class code attr register */ | ||
234 | |||
235 | pci_write_config_byte(dev, 0x09, 0xff); /* Set native mode & stuff */ | ||
236 | pci_write_config_byte(dev, 0x52, 0x00); /* use timing registers */ | ||
237 | pci_write_config_byte(dev, 0x58, 0x02); /* Primary addr setup timing */ | ||
238 | pci_write_config_byte(dev, 0x59, 0x22); /* Primary cmd block timing */ | ||
239 | pci_write_config_byte(dev, 0x5a, 0x22); /* Pr drv 0 R/W timing */ | ||
240 | pci_write_config_byte(dev, 0x5b, 0x22); /* Pr drv 1 R/W timing */ | ||
241 | pci_write_config_byte(dev, 0x5c, 0x02); /* Sec addr setup timing */ | ||
242 | pci_write_config_byte(dev, 0x5d, 0x22); /* Sec cmd block timing */ | ||
243 | pci_write_config_byte(dev, 0x5e, 0x22); /* Sec drv 0 R/W timing */ | ||
244 | pci_write_config_byte(dev, 0x5f, 0x22); /* Sec drv 1 R/W timing */ | ||
245 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); | ||
246 | pci_write_config_word(dev, PCI_COMMAND, | ||
247 | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | | ||
248 | PCI_COMMAND_IO); | ||
249 | } | ||
250 | |||
diff --git a/arch/mips/vr41xx/nec-cmbvr4133/setup.c b/arch/mips/vr41xx/nec-cmbvr4133/setup.c new file mode 100644 index 000000000000..db686ce42e85 --- /dev/null +++ b/arch/mips/vr41xx/nec-cmbvr4133/setup.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * arch/mips/vr41xx/nec-cmbvr4133/setup.c | ||
3 | * | ||
4 | * Setup for the NEC CMB-VR4133. | ||
5 | * | ||
6 | * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com> and | ||
7 | * Alex Sapkov <asapkov@ru.mvista.com> | ||
8 | * | ||
9 | * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under | ||
10 | * the terms of the GNU General Public License version 2. This program | ||
11 | * is licensed "as is" without any warranty of any kind, whether express | ||
12 | * or implied. | ||
13 | * | ||
14 | * Support for CMBVR4133 board in 2.6 | ||
15 | * Author: Manish Lachwani (mlachwani@mvista.com) | ||
16 | */ | ||
17 | #include <linux/config.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/ide.h> | ||
20 | #include <linux/ioport.h> | ||
21 | |||
22 | #include <asm/reboot.h> | ||
23 | #include <asm/time.h> | ||
24 | #include <asm/vr41xx/cmbvr4133.h> | ||
25 | #include <asm/bootinfo.h> | ||
26 | |||
27 | #ifdef CONFIG_MTD | ||
28 | #include <linux/mtd/physmap.h> | ||
29 | #include <linux/mtd/partitions.h> | ||
30 | #include <linux/mtd/mtd.h> | ||
31 | #include <linux/mtd/map.h> | ||
32 | |||
33 | static struct mtd_partition cmbvr4133_mtd_parts[] = { | ||
34 | { | ||
35 | .name = "User FS", | ||
36 | .size = 0x1be0000, | ||
37 | .offset = 0, | ||
38 | .mask_flags = 0, | ||
39 | }, | ||
40 | { | ||
41 | .name = "PMON", | ||
42 | .size = 0x140000, | ||
43 | .offset = MTDPART_OFS_APPEND, | ||
44 | .mask_flags = MTD_WRITEABLE, /* force read-only */ | ||
45 | }, | ||
46 | { | ||
47 | .name = "User FS2", | ||
48 | .size = MTDPART_SIZ_FULL, | ||
49 | .offset = MTDPART_OFS_APPEND, | ||
50 | .mask_flags = 0, | ||
51 | } | ||
52 | }; | ||
53 | |||
54 | #define number_partitions (sizeof(cmbvr4133_mtd_parts)/sizeof(struct mtd_partition)) | ||
55 | #endif | ||
56 | |||
57 | extern void i8259_init(void); | ||
58 | |||
59 | static int __init nec_cmbvr4133_setup(void) | ||
60 | { | ||
61 | #ifdef CONFIG_ROCKHOPPER | ||
62 | extern void disable_pcnet(void); | ||
63 | |||
64 | disable_pcnet(); | ||
65 | #endif | ||
66 | set_io_port_base(KSEG1ADDR(0x16000000)); | ||
67 | |||
68 | mips_machgroup = MACH_GROUP_NEC_VR41XX; | ||
69 | mips_machtype = MACH_NEC_CMBVR4133; | ||
70 | |||
71 | #ifdef CONFIG_PCI | ||
72 | #ifdef CONFIG_ROCKHOPPER | ||
73 | ali_m5229_preinit(); | ||
74 | #endif | ||
75 | #endif | ||
76 | |||
77 | #ifdef CONFIG_ROCKHOPPER | ||
78 | rockhopper_init_irq(); | ||
79 | #endif | ||
80 | |||
81 | #ifdef CONFIG_MTD | ||
82 | /* we use generic physmap mapping driver and we use partitions */ | ||
83 | physmap_configure(0x1C000000, 0x02000000, 4, NULL); | ||
84 | physmap_set_partitions(cmbvr4133_mtd_parts, number_partitions); | ||
85 | #endif | ||
86 | |||
87 | /* 128 MB memory support */ | ||
88 | add_memory_region(0, 0x08000000, BOOT_MEM_RAM); | ||
89 | |||
90 | #ifdef CONFIG_ROCKHOPPER | ||
91 | i8259_init(); | ||
92 | #endif | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | early_initcall(nec_cmbvr4133_setup); | ||
diff --git a/arch/mips/vr41xx/tanbac-tb0226/Makefile b/arch/mips/vr41xx/tanbac-tb0226/Makefile new file mode 100644 index 000000000000..372f953d240b --- /dev/null +++ b/arch/mips/vr41xx/tanbac-tb0226/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for the TANBAC TB0226 specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y += setup.o | ||
diff --git a/arch/mips/vr41xx/tanbac-tb0226/setup.c b/arch/mips/vr41xx/tanbac-tb0226/setup.c new file mode 100644 index 000000000000..60027e5dea25 --- /dev/null +++ b/arch/mips/vr41xx/tanbac-tb0226/setup.c | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * setup.c, Setup for the TANBAC TB0226. | ||
3 | * | ||
4 | * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
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; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | const char *get_system_type(void) | ||
22 | { | ||
23 | return "TANBAC TB0226"; | ||
24 | } | ||
diff --git a/arch/mips/vr41xx/tanbac-tb0229/Makefile b/arch/mips/vr41xx/tanbac-tb0229/Makefile new file mode 100644 index 000000000000..9c6b864ef2ef --- /dev/null +++ b/arch/mips/vr41xx/tanbac-tb0229/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for the TANBAC TB0229(VR4131DIMM) specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := setup.o | ||
diff --git a/arch/mips/vr41xx/tanbac-tb0229/setup.c b/arch/mips/vr41xx/tanbac-tb0229/setup.c new file mode 100644 index 000000000000..5c1b757bfb0c --- /dev/null +++ b/arch/mips/vr41xx/tanbac-tb0229/setup.c | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * setup.c, Setup for the TANBAC TB0229 (VR4131DIMM) | ||
3 | * | ||
4 | * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
5 | * | ||
6 | * Modified for TANBAC TB0229: | ||
7 | * Copyright (C) 2003 Megasolution Inc. <matsu@megasolution.jp> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | const char *get_system_type(void) | ||
25 | { | ||
26 | return "TANBAC TB0229"; | ||
27 | } | ||
diff --git a/arch/mips/vr41xx/victor-mpc30x/Makefile b/arch/mips/vr41xx/victor-mpc30x/Makefile new file mode 100644 index 000000000000..a2e8086a31a6 --- /dev/null +++ b/arch/mips/vr41xx/victor-mpc30x/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for the Victor MP-C303/304 specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y += setup.o | ||
diff --git a/arch/mips/vr41xx/victor-mpc30x/setup.c b/arch/mips/vr41xx/victor-mpc30x/setup.c new file mode 100644 index 000000000000..f591e36726e6 --- /dev/null +++ b/arch/mips/vr41xx/victor-mpc30x/setup.c | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * setup.c, Setup for the Victor MP-C303/304. | ||
3 | * | ||
4 | * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
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; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | const char *get_system_type(void) | ||
22 | { | ||
23 | return "Victor MP-C303/304"; | ||
24 | } | ||
diff --git a/arch/mips/vr41xx/zao-capcella/Makefile b/arch/mips/vr41xx/zao-capcella/Makefile new file mode 100644 index 000000000000..cf420197cd23 --- /dev/null +++ b/arch/mips/vr41xx/zao-capcella/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for the ZAO Networks Capcella specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y += setup.o | ||
diff --git a/arch/mips/vr41xx/zao-capcella/setup.c b/arch/mips/vr41xx/zao-capcella/setup.c new file mode 100644 index 000000000000..17bade241fe2 --- /dev/null +++ b/arch/mips/vr41xx/zao-capcella/setup.c | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * setup.c, Setup for the ZAO Networks Capcella. | ||
3 | * | ||
4 | * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
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; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | const char *get_system_type(void) | ||
22 | { | ||
23 | return "ZAO Networks Capcella"; | ||
24 | } | ||