aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/mti-malta
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/mti-malta')
-rw-r--r--arch/mips/mti-malta/Makefile21
-rw-r--r--arch/mips/mti-malta/malta-amon.c80
-rw-r--r--arch/mips/mti-malta/malta-cmdline.c59
-rw-r--r--arch/mips/mti-malta/malta-console.c47
-rw-r--r--arch/mips/mti-malta/malta-display.c64
-rw-r--r--arch/mips/mti-malta/malta-init.c424
-rw-r--r--arch/mips/mti-malta/malta-int.c712
-rw-r--r--arch/mips/mti-malta/malta-kgdb.c133
-rw-r--r--arch/mips/mti-malta/malta-memory.c177
-rw-r--r--arch/mips/mti-malta/malta-mtd.c63
-rw-r--r--arch/mips/mti-malta/malta-pci.c243
-rw-r--r--arch/mips/mti-malta/malta-platform.c65
-rw-r--r--arch/mips/mti-malta/malta-reset.c56
-rw-r--r--arch/mips/mti-malta/malta-setup.c229
-rw-r--r--arch/mips/mti-malta/malta-smtc.c154
-rw-r--r--arch/mips/mti-malta/malta-time.c163
16 files changed, 2690 insertions, 0 deletions
diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile
new file mode 100644
index 000000000000..f8064446e812
--- /dev/null
+++ b/arch/mips/mti-malta/Makefile
@@ -0,0 +1,21 @@
1#
2# Carsten Langgaard, carstenl@mips.com
3# Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
4#
5# Copyright (C) 2008 Wind River Systems, Inc.
6# written by Ralf Baechle <ralf@linux-mips.org>
7#
8obj-y := malta-amon.o malta-cmdline.o \
9 malta-display.o malta-init.o malta-int.o \
10 malta-memory.o malta-mtd.o \
11 malta-platform.o malta-reset.o \
12 malta-setup.o malta-time.o
13
14obj-$(CONFIG_EARLY_PRINTK) += malta-console.o
15obj-$(CONFIG_PCI) += malta-pci.o
16obj-$(CONFIG_KGDB) += malta-kgdb.o
17
18# FIXME FIXME FIXME
19obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o
20
21EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/mti-malta/malta-amon.c b/arch/mips/mti-malta/malta-amon.c
new file mode 100644
index 000000000000..96236bf33838
--- /dev/null
+++ b/arch/mips/mti-malta/malta-amon.c
@@ -0,0 +1,80 @@
1/*
2 * Copyright (C) 2007 MIPS Technologies, Inc.
3 * All rights reserved.
4
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * Arbitrary Monitor interface
19 */
20
21#include <linux/kernel.h>
22#include <linux/init.h>
23#include <linux/smp.h>
24
25#include <asm-mips/addrspace.h>
26#include <asm-mips/mips-boards/launch.h>
27#include <asm-mips/mipsmtregs.h>
28
29int amon_cpu_avail(int cpu)
30{
31 struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH);
32
33 if (cpu < 0 || cpu >= NCPULAUNCH) {
34 pr_debug("avail: cpu%d is out of range\n", cpu);
35 return 0;
36 }
37
38 launch += cpu;
39 if (!(launch->flags & LAUNCH_FREADY)) {
40 pr_debug("avail: cpu%d is not ready\n", cpu);
41 return 0;
42 }
43 if (launch->flags & (LAUNCH_FGO|LAUNCH_FGONE)) {
44 pr_debug("avail: too late.. cpu%d is already gone\n", cpu);
45 return 0;
46 }
47
48 return 1;
49}
50
51void amon_cpu_start(int cpu,
52 unsigned long pc, unsigned long sp,
53 unsigned long gp, unsigned long a0)
54{
55 volatile struct cpulaunch *launch =
56 (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH);
57
58 if (!amon_cpu_avail(cpu))
59 return;
60 if (cpu == smp_processor_id()) {
61 pr_debug("launch: I am cpu%d!\n", cpu);
62 return;
63 }
64 launch += cpu;
65
66 pr_debug("launch: starting cpu%d\n", cpu);
67
68 launch->pc = pc;
69 launch->gp = gp;
70 launch->sp = sp;
71 launch->a0 = a0;
72
73 /* Make sure target sees parameters before the go bit */
74 smp_mb();
75
76 launch->flags |= LAUNCH_FGO;
77 while ((launch->flags & LAUNCH_FGONE) == 0)
78 ;
79 pr_debug("launch: cpu%d gone!\n", cpu);
80}
diff --git a/arch/mips/mti-malta/malta-cmdline.c b/arch/mips/mti-malta/malta-cmdline.c
new file mode 100644
index 000000000000..1871c30ed2eb
--- /dev/null
+++ b/arch/mips/mti-malta/malta-cmdline.c
@@ -0,0 +1,59 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * Kernel command line creation using the prom monitor (YAMON) argc/argv.
19 */
20#include <linux/init.h>
21#include <linux/string.h>
22
23#include <asm/bootinfo.h>
24
25extern int prom_argc;
26extern int *_prom_argv;
27
28/*
29 * YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer.
30 * This macro take care of sign extension.
31 */
32#define prom_argv(index) ((char *)(long)_prom_argv[(index)])
33
34char * __init prom_getcmdline(void)
35{
36 return &(arcs_cmdline[0]);
37}
38
39
40void __init prom_init_cmdline(void)
41{
42 char *cp;
43 int actr;
44
45 actr = 1; /* Always ignore argv[0] */
46
47 cp = &(arcs_cmdline[0]);
48 while(actr < prom_argc) {
49 strcpy(cp, prom_argv(actr));
50 cp += strlen(prom_argv(actr));
51 *cp++ = ' ';
52 actr++;
53 }
54 if (cp != &(arcs_cmdline[0])) {
55 /* get rid of trailing space */
56 --cp;
57 *cp = '\0';
58 }
59}
diff --git a/arch/mips/mti-malta/malta-console.c b/arch/mips/mti-malta/malta-console.c
new file mode 100644
index 000000000000..43bcfb4f8167
--- /dev/null
+++ b/arch/mips/mti-malta/malta-console.c
@@ -0,0 +1,47 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * Putting things on the screen/serial line using YAMONs facilities.
19 */
20#include <linux/console.h>
21#include <linux/init.h>
22#include <linux/serial_reg.h>
23#include <asm/io.h>
24
25
26#define PORT(offset) (0x3f8 + (offset))
27
28
29static inline unsigned int serial_in(int offset)
30{
31 return inb(PORT(offset));
32}
33
34static inline void serial_out(int offset, int value)
35{
36 outb(value, PORT(offset));
37}
38
39int prom_putchar(char c)
40{
41 while ((serial_in(UART_LSR) & UART_LSR_THRE) == 0)
42 ;
43
44 serial_out(UART_TX, c);
45
46 return 1;
47}
diff --git a/arch/mips/mti-malta/malta-display.c b/arch/mips/mti-malta/malta-display.c
new file mode 100644
index 000000000000..7c8828fcb0ad
--- /dev/null
+++ b/arch/mips/mti-malta/malta-display.c
@@ -0,0 +1,64 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * Display routines for display messages in MIPS boards ascii display.
19 */
20
21#include <linux/compiler.h>
22#include <linux/timer.h>
23#include <asm/io.h>
24#include <asm/mips-boards/generic.h>
25#include <asm/mips-boards/prom.h>
26
27extern const char display_string[];
28static unsigned int display_count;
29static unsigned int max_display_count;
30
31void mips_display_message(const char *str)
32{
33 static unsigned int __iomem *display = NULL;
34 int i;
35
36 if (unlikely(display == NULL))
37 display = ioremap(ASCII_DISPLAY_POS_BASE, 16*sizeof(int));
38
39 for (i = 0; i <= 14; i=i+2) {
40 if (*str)
41 __raw_writel(*str++, display + i);
42 else
43 __raw_writel(' ', display + i);
44 }
45}
46
47static void scroll_display_message(unsigned long data);
48static DEFINE_TIMER(mips_scroll_timer, scroll_display_message, HZ, 0);
49
50static void scroll_display_message(unsigned long data)
51{
52 mips_display_message(&display_string[display_count++]);
53 if (display_count == max_display_count)
54 display_count = 0;
55
56 mod_timer(&mips_scroll_timer, jiffies + HZ);
57}
58
59void mips_scroll_message(void)
60{
61 del_timer_sync(&mips_scroll_timer);
62 max_display_count = strlen(display_string) + 1 - 8;
63 mod_timer(&mips_scroll_timer, jiffies + 1);
64}
diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c
new file mode 100644
index 000000000000..c0653021a171
--- /dev/null
+++ b/arch/mips/mti-malta/malta-init.c
@@ -0,0 +1,424 @@
1/*
2 * Copyright (C) 1999, 2000, 2004, 2005 MIPS Technologies, Inc.
3 * All rights reserved.
4 * Authors: Carsten Langgaard <carstenl@mips.com>
5 * Maciej W. Rozycki <macro@mips.com>
6 *
7 * This program is free software; you can distribute it and/or modify it
8 * under the terms of the GNU General Public License (Version 2) as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
19 *
20 * PROM library initialisation code.
21 */
22#include <linux/init.h>
23#include <linux/string.h>
24#include <linux/kernel.h>
25
26#include <asm/bootinfo.h>
27#include <asm/gt64120.h>
28#include <asm/io.h>
29#include <asm/system.h>
30#include <asm/cacheflush.h>
31#include <asm/traps.h>
32
33#include <asm/mips-boards/prom.h>
34#include <asm/mips-boards/generic.h>
35#include <asm/mips-boards/bonito64.h>
36#include <asm/mips-boards/msc01_pci.h>
37
38#include <asm/mips-boards/malta.h>
39
40#ifdef CONFIG_KGDB
41extern int rs_kgdb_hook(int, int);
42extern int rs_putDebugChar(char);
43extern char rs_getDebugChar(void);
44extern int saa9730_kgdb_hook(int);
45extern int saa9730_putDebugChar(char);
46extern char saa9730_getDebugChar(void);
47#endif
48
49int prom_argc;
50int *_prom_argv, *_prom_envp;
51
52/*
53 * YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer.
54 * This macro take care of sign extension, if running in 64-bit mode.
55 */
56#define prom_envp(index) ((char *)(long)_prom_envp[(index)])
57
58int init_debug = 0;
59
60int mips_revision_corid;
61int mips_revision_sconid;
62
63/* Bonito64 system controller register base. */
64unsigned long _pcictrl_bonito;
65unsigned long _pcictrl_bonito_pcicfg;
66
67/* GT64120 system controller register base */
68unsigned long _pcictrl_gt64120;
69
70/* MIPS System controller register base */
71unsigned long _pcictrl_msc;
72
73char *prom_getenv(char *envname)
74{
75 /*
76 * Return a pointer to the given environment variable.
77 * In 64-bit mode: we're using 64-bit pointers, but all pointers
78 * in the PROM structures are only 32-bit, so we need some
79 * workarounds, if we are running in 64-bit mode.
80 */
81 int i, index=0;
82
83 i = strlen(envname);
84
85 while (prom_envp(index)) {
86 if(strncmp(envname, prom_envp(index), i) == 0) {
87 return(prom_envp(index+1));
88 }
89 index += 2;
90 }
91
92 return NULL;
93}
94
95static inline unsigned char str2hexnum(unsigned char c)
96{
97 if (c >= '0' && c <= '9')
98 return c - '0';
99 if (c >= 'a' && c <= 'f')
100 return c - 'a' + 10;
101 return 0; /* foo */
102}
103
104static inline void str2eaddr(unsigned char *ea, unsigned char *str)
105{
106 int i;
107
108 for (i = 0; i < 6; i++) {
109 unsigned char num;
110
111 if((*str == '.') || (*str == ':'))
112 str++;
113 num = str2hexnum(*str++) << 4;
114 num |= (str2hexnum(*str++));
115 ea[i] = num;
116 }
117}
118
119int get_ethernet_addr(char *ethernet_addr)
120{
121 char *ethaddr_str;
122
123 ethaddr_str = prom_getenv("ethaddr");
124 if (!ethaddr_str) {
125 printk("ethaddr not set in boot prom\n");
126 return -1;
127 }
128 str2eaddr(ethernet_addr, ethaddr_str);
129
130 if (init_debug > 1) {
131 int i;
132 printk("get_ethernet_addr: ");
133 for (i=0; i<5; i++)
134 printk("%02x:", (unsigned char)*(ethernet_addr+i));
135 printk("%02x\n", *(ethernet_addr+i));
136 }
137
138 return 0;
139}
140
141#ifdef CONFIG_SERIAL_8250_CONSOLE
142static void __init console_config(void)
143{
144 char console_string[40];
145 int baud = 0;
146 char parity = '\0', bits = '\0', flow = '\0';
147 char *s;
148
149 if ((strstr(prom_getcmdline(), "console=")) == NULL) {
150 s = prom_getenv("modetty0");
151 if (s) {
152 while (*s >= '0' && *s <= '9')
153 baud = baud*10 + *s++ - '0';
154 if (*s == ',') s++;
155 if (*s) parity = *s++;
156 if (*s == ',') s++;
157 if (*s) bits = *s++;
158 if (*s == ',') s++;
159 if (*s == 'h') flow = 'r';
160 }
161 if (baud == 0)
162 baud = 38400;
163 if (parity != 'n' && parity != 'o' && parity != 'e')
164 parity = 'n';
165 if (bits != '7' && bits != '8')
166 bits = '8';
167 if (flow == '\0')
168 flow = 'r';
169 sprintf(console_string, " console=ttyS0,%d%c%c%c", baud, parity, bits, flow);
170 strcat(prom_getcmdline(), console_string);
171 pr_info("Config serial console:%s\n", console_string);
172 }
173}
174#endif
175
176#ifdef CONFIG_KGDB
177void __init kgdb_config(void)
178{
179 extern int (*generic_putDebugChar)(char);
180 extern char (*generic_getDebugChar)(void);
181 char *argptr;
182 int line, speed;
183
184 argptr = prom_getcmdline();
185 if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) {
186 argptr += strlen("kgdb=ttyS");
187 if (*argptr != '0' && *argptr != '1')
188 printk("KGDB: Unknown serial line /dev/ttyS%c, "
189 "falling back to /dev/ttyS1\n", *argptr);
190 line = *argptr == '0' ? 0 : 1;
191 printk("KGDB: Using serial line /dev/ttyS%d for session\n", line);
192
193 speed = 0;
194 if (*++argptr == ',')
195 {
196 int c;
197 while ((c = *++argptr) && ('0' <= c && c <= '9'))
198 speed = speed * 10 + c - '0';
199 }
200 {
201 speed = rs_kgdb_hook(line, speed);
202 generic_putDebugChar = rs_putDebugChar;
203 generic_getDebugChar = rs_getDebugChar;
204 }
205
206 pr_info("KGDB: Using serial line /dev/ttyS%d at %d for "
207 "session, please connect your debugger\n",
208 line ? 1 : 0, speed);
209
210 {
211 char *s;
212 for (s = "Please connect GDB to this port\r\n"; *s; )
213 generic_putDebugChar(*s++);
214 }
215
216 /* Breakpoint is invoked after interrupts are initialised */
217 }
218}
219#endif
220
221static void __init mips_nmi_setup(void)
222{
223 void *base;
224 extern char except_vec_nmi;
225
226 base = cpu_has_veic ?
227 (void *)(CAC_BASE + 0xa80) :
228 (void *)(CAC_BASE + 0x380);
229 memcpy(base, &except_vec_nmi, 0x80);
230 flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
231}
232
233static void __init mips_ejtag_setup(void)
234{
235 void *base;
236 extern char except_vec_ejtag_debug;
237
238 base = cpu_has_veic ?
239 (void *)(CAC_BASE + 0xa00) :
240 (void *)(CAC_BASE + 0x300);
241 memcpy(base, &except_vec_ejtag_debug, 0x80);
242 flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
243}
244
245extern struct plat_smp_ops msmtc_smp_ops;
246
247void __init prom_init(void)
248{
249 prom_argc = fw_arg0;
250 _prom_argv = (int *) fw_arg1;
251 _prom_envp = (int *) fw_arg2;
252
253 mips_display_message("LINUX");
254
255 /*
256 * early setup of _pcictrl_bonito so that we can determine
257 * the system controller on a CORE_EMUL board
258 */
259 _pcictrl_bonito = (unsigned long)ioremap(BONITO_REG_BASE, BONITO_REG_SIZE);
260
261 mips_revision_corid = MIPS_REVISION_CORID;
262
263 if (mips_revision_corid == MIPS_REVISION_CORID_CORE_EMUL) {
264 if (BONITO_PCIDID == 0x0001df53 ||
265 BONITO_PCIDID == 0x0003df53)
266 mips_revision_corid = MIPS_REVISION_CORID_CORE_EMUL_BON;
267 else
268 mips_revision_corid = MIPS_REVISION_CORID_CORE_EMUL_MSC;
269 }
270
271 mips_revision_sconid = MIPS_REVISION_SCONID;
272 if (mips_revision_sconid == MIPS_REVISION_SCON_OTHER) {
273 switch (mips_revision_corid) {
274 case MIPS_REVISION_CORID_QED_RM5261:
275 case MIPS_REVISION_CORID_CORE_LV:
276 case MIPS_REVISION_CORID_CORE_FPGA:
277 case MIPS_REVISION_CORID_CORE_FPGAR2:
278 mips_revision_sconid = MIPS_REVISION_SCON_GT64120;
279 break;
280 case MIPS_REVISION_CORID_CORE_EMUL_BON:
281 case MIPS_REVISION_CORID_BONITO64:
282 case MIPS_REVISION_CORID_CORE_20K:
283 mips_revision_sconid = MIPS_REVISION_SCON_BONITO;
284 break;
285 case MIPS_REVISION_CORID_CORE_MSC:
286 case MIPS_REVISION_CORID_CORE_FPGA2:
287 case MIPS_REVISION_CORID_CORE_24K:
288 /*
289 * SOCit/ROCit support is essentially identical
290 * but make an attempt to distinguish them
291 */
292 mips_revision_sconid = MIPS_REVISION_SCON_SOCIT;
293 break;
294 case MIPS_REVISION_CORID_CORE_FPGA3:
295 case MIPS_REVISION_CORID_CORE_FPGA4:
296 case MIPS_REVISION_CORID_CORE_FPGA5:
297 case MIPS_REVISION_CORID_CORE_EMUL_MSC:
298 default:
299 /* See above */
300 mips_revision_sconid = MIPS_REVISION_SCON_ROCIT;
301 break;
302 }
303 }
304
305 switch (mips_revision_sconid) {
306 u32 start, map, mask, data;
307
308 case MIPS_REVISION_SCON_GT64120:
309 /*
310 * Setup the North bridge to do Master byte-lane swapping
311 * when running in bigendian.
312 */
313 _pcictrl_gt64120 = (unsigned long)ioremap(MIPS_GT_BASE, 0x2000);
314
315#ifdef CONFIG_CPU_LITTLE_ENDIAN
316 GT_WRITE(GT_PCI0_CMD_OFS, GT_PCI0_CMD_MBYTESWAP_BIT |
317 GT_PCI0_CMD_SBYTESWAP_BIT);
318#else
319 GT_WRITE(GT_PCI0_CMD_OFS, 0);
320#endif
321 /* Fix up PCI I/O mapping if necessary (for Atlas). */
322 start = GT_READ(GT_PCI0IOLD_OFS);
323 map = GT_READ(GT_PCI0IOREMAP_OFS);
324 if ((start & map) != 0) {
325 map &= ~start;
326 GT_WRITE(GT_PCI0IOREMAP_OFS, map);
327 }
328
329 set_io_port_base(MALTA_GT_PORT_BASE);
330 break;
331
332 case MIPS_REVISION_SCON_BONITO:
333 _pcictrl_bonito_pcicfg = (unsigned long)ioremap(BONITO_PCICFG_BASE, BONITO_PCICFG_SIZE);
334
335 /*
336 * Disable Bonito IOBC.
337 */
338 BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG &
339 ~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
340 BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
341
342 /*
343 * Setup the North bridge to do Master byte-lane swapping
344 * when running in bigendian.
345 */
346#ifdef CONFIG_CPU_LITTLE_ENDIAN
347 BONITO_BONGENCFG = BONITO_BONGENCFG &
348 ~(BONITO_BONGENCFG_MSTRBYTESWAP |
349 BONITO_BONGENCFG_BYTESWAP);
350#else
351 BONITO_BONGENCFG = BONITO_BONGENCFG |
352 BONITO_BONGENCFG_MSTRBYTESWAP |
353 BONITO_BONGENCFG_BYTESWAP;
354#endif
355
356 set_io_port_base(MALTA_BONITO_PORT_BASE);
357 break;
358
359 case MIPS_REVISION_SCON_SOCIT:
360 case MIPS_REVISION_SCON_ROCIT:
361 _pcictrl_msc = (unsigned long)ioremap(MIPS_MSC01_PCI_REG_BASE, 0x2000);
362 mips_pci_controller:
363 mb();
364 MSC_READ(MSC01_PCI_CFG, data);
365 MSC_WRITE(MSC01_PCI_CFG, data & ~MSC01_PCI_CFG_EN_BIT);
366 wmb();
367
368 /* Fix up lane swapping. */
369#ifdef CONFIG_CPU_LITTLE_ENDIAN
370 MSC_WRITE(MSC01_PCI_SWAP, MSC01_PCI_SWAP_NOSWAP);
371#else
372 MSC_WRITE(MSC01_PCI_SWAP,
373 MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_IO_SHF |
374 MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_MEM_SHF |
375 MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_BAR0_SHF);
376#endif
377 /* Fix up target memory mapping. */
378 MSC_READ(MSC01_PCI_BAR0, mask);
379 MSC_WRITE(MSC01_PCI_P2SCMSKL, mask & MSC01_PCI_BAR0_SIZE_MSK);
380
381 /* Don't handle target retries indefinitely. */
382 if ((data & MSC01_PCI_CFG_MAXRTRY_MSK) ==
383 MSC01_PCI_CFG_MAXRTRY_MSK)
384 data = (data & ~(MSC01_PCI_CFG_MAXRTRY_MSK <<
385 MSC01_PCI_CFG_MAXRTRY_SHF)) |
386 ((MSC01_PCI_CFG_MAXRTRY_MSK - 1) <<
387 MSC01_PCI_CFG_MAXRTRY_SHF);
388
389 wmb();
390 MSC_WRITE(MSC01_PCI_CFG, data);
391 mb();
392
393 set_io_port_base(MALTA_MSC_PORT_BASE);
394 break;
395
396 case MIPS_REVISION_SCON_SOCITSC:
397 case MIPS_REVISION_SCON_SOCITSCP:
398 _pcictrl_msc = (unsigned long)ioremap(MIPS_SOCITSC_PCI_REG_BASE, 0x2000);
399 goto mips_pci_controller;
400
401 default:
402 /* Unknown system controller */
403 mips_display_message("SC Error");
404 while (1); /* We die here... */
405 }
406 board_nmi_handler_setup = mips_nmi_setup;
407 board_ejtag_handler_setup = mips_ejtag_setup;
408
409 pr_info("\nLINUX started...\n");
410 prom_init_cmdline();
411 prom_meminit();
412#ifdef CONFIG_SERIAL_8250_CONSOLE
413 console_config();
414#endif
415#ifdef CONFIG_MIPS_CMP
416 register_smp_ops(&cmp_smp_ops);
417#endif
418#ifdef CONFIG_MIPS_MT_SMP
419 register_smp_ops(&vsmp_smp_ops);
420#endif
421#ifdef CONFIG_MIPS_MT_SMTC
422 register_smp_ops(&msmtc_smp_ops);
423#endif
424}
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
new file mode 100644
index 000000000000..ea176113fea9
--- /dev/null
+++ b/arch/mips/mti-malta/malta-int.c
@@ -0,0 +1,712 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc.
4 * Copyright (C) 2001 Ralf Baechle
5 *
6 * This program is free software; you can distribute it and/or modify it
7 * under the terms of the GNU General Public License (Version 2) as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
18 *
19 * Routines for generic manipulation of the interrupts found on the MIPS
20 * Malta board.
21 * The interrupt controller is located in the South Bridge a PIIX4 device
22 * with two internal 82C95 interrupt controllers.
23 */
24#include <linux/init.h>
25#include <linux/irq.h>
26#include <linux/sched.h>
27#include <linux/slab.h>
28#include <linux/interrupt.h>
29#include <linux/io.h>
30#include <linux/kernel_stat.h>
31#include <linux/kernel.h>
32#include <linux/random.h>
33
34#include <asm/traps.h>
35#include <asm/i8259.h>
36#include <asm/irq_cpu.h>
37#include <asm/irq_regs.h>
38#include <asm/mips-boards/malta.h>
39#include <asm/mips-boards/maltaint.h>
40#include <asm/mips-boards/piix4.h>
41#include <asm/gt64120.h>
42#include <asm/mips-boards/generic.h>
43#include <asm/mips-boards/msc01_pci.h>
44#include <asm/msc01_ic.h>
45#include <asm/gic.h>
46#include <asm/gcmpregs.h>
47
48int gcmp_present = -1;
49int gic_present;
50static unsigned long _msc01_biu_base;
51static unsigned long _gcmp_base;
52static unsigned int ipi_map[NR_CPUS];
53
54static DEFINE_SPINLOCK(mips_irq_lock);
55
56static inline int mips_pcibios_iack(void)
57{
58 int irq;
59 u32 dummy;
60
61 /*
62 * Determine highest priority pending interrupt by performing
63 * a PCI Interrupt Acknowledge cycle.
64 */
65 switch (mips_revision_sconid) {
66 case MIPS_REVISION_SCON_SOCIT:
67 case MIPS_REVISION_SCON_ROCIT:
68 case MIPS_REVISION_SCON_SOCITSC:
69 case MIPS_REVISION_SCON_SOCITSCP:
70 MSC_READ(MSC01_PCI_IACK, irq);
71 irq &= 0xff;
72 break;
73 case MIPS_REVISION_SCON_GT64120:
74 irq = GT_READ(GT_PCI0_IACK_OFS);
75 irq &= 0xff;
76 break;
77 case MIPS_REVISION_SCON_BONITO:
78 /* The following will generate a PCI IACK cycle on the
79 * Bonito controller. It's a little bit kludgy, but it
80 * was the easiest way to implement it in hardware at
81 * the given time.
82 */
83 BONITO_PCIMAP_CFG = 0x20000;
84
85 /* Flush Bonito register block */
86 dummy = BONITO_PCIMAP_CFG;
87 iob(); /* sync */
88
89 irq = readl((u32 *)_pcictrl_bonito_pcicfg);
90 iob(); /* sync */
91 irq &= 0xff;
92 BONITO_PCIMAP_CFG = 0;
93 break;
94 default:
95 printk(KERN_WARNING "Unknown system controller.\n");
96 return -1;
97 }
98 return irq;
99}
100
101static inline int get_int(void)
102{
103 unsigned long flags;
104 int irq;
105 spin_lock_irqsave(&mips_irq_lock, flags);
106
107 irq = mips_pcibios_iack();
108
109 /*
110 * The only way we can decide if an interrupt is spurious
111 * is by checking the 8259 registers. This needs a spinlock
112 * on an SMP system, so leave it up to the generic code...
113 */
114
115 spin_unlock_irqrestore(&mips_irq_lock, flags);
116
117 return irq;
118}
119
120static void malta_hw0_irqdispatch(void)
121{
122 int irq;
123
124 irq = get_int();
125 if (irq < 0) {
126 /* interrupt has already been cleared */
127 return;
128 }
129
130 do_IRQ(MALTA_INT_BASE + irq);
131}
132
133static void malta_ipi_irqdispatch(void)
134{
135 int irq;
136
137 irq = gic_get_int();
138 if (irq < 0)
139 return; /* interrupt has already been cleared */
140
141 do_IRQ(MIPS_GIC_IRQ_BASE + irq);
142}
143
144static void corehi_irqdispatch(void)
145{
146 unsigned int intedge, intsteer, pcicmd, pcibadaddr;
147 unsigned int pcimstat, intisr, inten, intpol;
148 unsigned int intrcause, datalo, datahi;
149 struct pt_regs *regs = get_irq_regs();
150
151 printk(KERN_EMERG "CoreHI interrupt, shouldn't happen, we die here!\n");
152 printk(KERN_EMERG "epc : %08lx\nStatus: %08lx\n"
153 "Cause : %08lx\nbadVaddr : %08lx\n",
154 regs->cp0_epc, regs->cp0_status,
155 regs->cp0_cause, regs->cp0_badvaddr);
156
157 /* Read all the registers and then print them as there is a
158 problem with interspersed printk's upsetting the Bonito controller.
159 Do it for the others too.
160 */
161
162 switch (mips_revision_sconid) {
163 case MIPS_REVISION_SCON_SOCIT:
164 case MIPS_REVISION_SCON_ROCIT:
165 case MIPS_REVISION_SCON_SOCITSC:
166 case MIPS_REVISION_SCON_SOCITSCP:
167 ll_msc_irq();
168 break;
169 case MIPS_REVISION_SCON_GT64120:
170 intrcause = GT_READ(GT_INTRCAUSE_OFS);
171 datalo = GT_READ(GT_CPUERR_ADDRLO_OFS);
172 datahi = GT_READ(GT_CPUERR_ADDRHI_OFS);
173 printk(KERN_EMERG "GT_INTRCAUSE = %08x\n", intrcause);
174 printk(KERN_EMERG "GT_CPUERR_ADDR = %02x%08x\n",
175 datahi, datalo);
176 break;
177 case MIPS_REVISION_SCON_BONITO:
178 pcibadaddr = BONITO_PCIBADADDR;
179 pcimstat = BONITO_PCIMSTAT;
180 intisr = BONITO_INTISR;
181 inten = BONITO_INTEN;
182 intpol = BONITO_INTPOL;
183 intedge = BONITO_INTEDGE;
184 intsteer = BONITO_INTSTEER;
185 pcicmd = BONITO_PCICMD;
186 printk(KERN_EMERG "BONITO_INTISR = %08x\n", intisr);
187 printk(KERN_EMERG "BONITO_INTEN = %08x\n", inten);
188 printk(KERN_EMERG "BONITO_INTPOL = %08x\n", intpol);
189 printk(KERN_EMERG "BONITO_INTEDGE = %08x\n", intedge);
190 printk(KERN_EMERG "BONITO_INTSTEER = %08x\n", intsteer);
191 printk(KERN_EMERG "BONITO_PCICMD = %08x\n", pcicmd);
192 printk(KERN_EMERG "BONITO_PCIBADADDR = %08x\n", pcibadaddr);
193 printk(KERN_EMERG "BONITO_PCIMSTAT = %08x\n", pcimstat);
194 break;
195 }
196
197 die("CoreHi interrupt", regs);
198}
199
200static inline int clz(unsigned long x)
201{
202 __asm__(
203 " .set push \n"
204 " .set mips32 \n"
205 " clz %0, %1 \n"
206 " .set pop \n"
207 : "=r" (x)
208 : "r" (x));
209
210 return x;
211}
212
213/*
214 * Version of ffs that only looks at bits 12..15.
215 */
216static inline unsigned int irq_ffs(unsigned int pending)
217{
218#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
219 return -clz(pending) + 31 - CAUSEB_IP;
220#else
221 unsigned int a0 = 7;
222 unsigned int t0;
223
224 t0 = pending & 0xf000;
225 t0 = t0 < 1;
226 t0 = t0 << 2;
227 a0 = a0 - t0;
228 pending = pending << t0;
229
230 t0 = pending & 0xc000;
231 t0 = t0 < 1;
232 t0 = t0 << 1;
233 a0 = a0 - t0;
234 pending = pending << t0;
235
236 t0 = pending & 0x8000;
237 t0 = t0 < 1;
238 /* t0 = t0 << 2; */
239 a0 = a0 - t0;
240 /* pending = pending << t0; */
241
242 return a0;
243#endif
244}
245
246/*
247 * IRQs on the Malta board look basically (barring software IRQs which we
248 * don't use at all and all external interrupt sources are combined together
249 * on hardware interrupt 0 (MIPS IRQ 2)) like:
250 *
251 * MIPS IRQ Source
252 * -------- ------
253 * 0 Software (ignored)
254 * 1 Software (ignored)
255 * 2 Combined hardware interrupt (hw0)
256 * 3 Hardware (ignored)
257 * 4 Hardware (ignored)
258 * 5 Hardware (ignored)
259 * 6 Hardware (ignored)
260 * 7 R4k timer (what we use)
261 *
262 * We handle the IRQ according to _our_ priority which is:
263 *
264 * Highest ---- R4k Timer
265 * Lowest ---- Combined hardware interrupt
266 *
267 * then we just return, if multiple IRQs are pending then we will just take
268 * another exception, big deal.
269 */
270
271asmlinkage void plat_irq_dispatch(void)
272{
273 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
274 int irq;
275
276 irq = irq_ffs(pending);
277
278 if (irq == MIPSCPU_INT_I8259A)
279 malta_hw0_irqdispatch();
280 else if (gic_present && ((1 << irq) & ipi_map[smp_processor_id()]))
281 malta_ipi_irqdispatch();
282 else if (irq >= 0)
283 do_IRQ(MIPS_CPU_IRQ_BASE + irq);
284 else
285 spurious_interrupt();
286}
287
288#ifdef CONFIG_MIPS_MT_SMP
289
290
291#define GIC_MIPS_CPU_IPI_RESCHED_IRQ 3
292#define GIC_MIPS_CPU_IPI_CALL_IRQ 4
293
294#define MIPS_CPU_IPI_RESCHED_IRQ 0 /* SW int 0 for resched */
295#define C_RESCHED C_SW0
296#define MIPS_CPU_IPI_CALL_IRQ 1 /* SW int 1 for resched */
297#define C_CALL C_SW1
298static int cpu_ipi_resched_irq, cpu_ipi_call_irq;
299
300static void ipi_resched_dispatch(void)
301{
302 do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
303}
304
305static void ipi_call_dispatch(void)
306{
307 do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
308}
309
310static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
311{
312 return IRQ_HANDLED;
313}
314
315static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
316{
317 smp_call_function_interrupt();
318
319 return IRQ_HANDLED;
320}
321
322static struct irqaction irq_resched = {
323 .handler = ipi_resched_interrupt,
324 .flags = IRQF_DISABLED|IRQF_PERCPU,
325 .name = "IPI_resched"
326};
327
328static struct irqaction irq_call = {
329 .handler = ipi_call_interrupt,
330 .flags = IRQF_DISABLED|IRQF_PERCPU,
331 .name = "IPI_call"
332};
333#endif /* CONFIG_MIPS_MT_SMP */
334
335static struct irqaction i8259irq = {
336 .handler = no_action,
337 .name = "XT-PIC cascade"
338};
339
340static struct irqaction corehi_irqaction = {
341 .handler = no_action,
342 .name = "CoreHi"
343};
344
345static msc_irqmap_t __initdata msc_irqmap[] = {
346 {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0},
347 {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0},
348};
349static int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap);
350
351static msc_irqmap_t __initdata msc_eicirqmap[] = {
352 {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0},
353 {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0},
354 {MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0},
355 {MSC01E_INT_SMI, MSC01_IRQ_LEVEL, 0},
356 {MSC01E_INT_COREHI, MSC01_IRQ_LEVEL, 0},
357 {MSC01E_INT_CORELO, MSC01_IRQ_LEVEL, 0},
358 {MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0},
359 {MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0},
360 {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0},
361 {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0}
362};
363
364static int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
365
366#if defined(CONFIG_MIPS_MT_SMP)
367/*
368 * This GIC specific tabular array defines the association between External
369 * Interrupts and CPUs/Core Interrupts. The nature of the External
370 * Interrupts is also defined here - polarity/trigger.
371 */
372static struct gic_intr_map gic_intr_map[] = {
373 { GIC_EXT_INTR(0), X, X, X, X, 0 },
374 { GIC_EXT_INTR(1), X, X, X, X, 0 },
375 { GIC_EXT_INTR(2), X, X, X, X, 0 },
376 { GIC_EXT_INTR(3), 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
377 { GIC_EXT_INTR(4), 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
378 { GIC_EXT_INTR(5), 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
379 { GIC_EXT_INTR(6), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
380 { GIC_EXT_INTR(7), 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
381 { GIC_EXT_INTR(8), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
382 { GIC_EXT_INTR(9), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
383 { GIC_EXT_INTR(10), X, X, X, X, 0 },
384 { GIC_EXT_INTR(11), X, X, X, X, 0 },
385 { GIC_EXT_INTR(12), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
386 { GIC_EXT_INTR(13), 0, GIC_MAP_TO_NMI_MSK, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
387 { GIC_EXT_INTR(14), 0, GIC_MAP_TO_NMI_MSK, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
388 { GIC_EXT_INTR(15), X, X, X, X, 0 },
389 { GIC_EXT_INTR(16), 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
390 { GIC_EXT_INTR(17), 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
391 { GIC_EXT_INTR(18), 1, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
392 { GIC_EXT_INTR(19), 1, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
393 { GIC_EXT_INTR(20), 2, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
394 { GIC_EXT_INTR(21), 2, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
395 { GIC_EXT_INTR(22), 3, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
396 { GIC_EXT_INTR(23), 3, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
397};
398#endif
399
400/*
401 * GCMP needs to be detected before any SMP initialisation
402 */
403static int __init gcmp_probe(unsigned long addr, unsigned long size)
404{
405 if (gcmp_present >= 0)
406 return gcmp_present;
407
408 _gcmp_base = (unsigned long) ioremap_nocache(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ);
409 _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ);
410 gcmp_present = (GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) == GCMP_BASE_ADDR;
411
412 if (gcmp_present)
413 printk(KERN_DEBUG "GCMP present\n");
414 return gcmp_present;
415}
416
417#if defined(CONFIG_MIPS_MT_SMP)
418static void __init fill_ipi_map(void)
419{
420 int i;
421
422 for (i = 0; i < ARRAY_SIZE(gic_intr_map); i++) {
423 if (gic_intr_map[i].ipiflag && (gic_intr_map[i].cpunum != X))
424 ipi_map[gic_intr_map[i].cpunum] |=
425 (1 << (gic_intr_map[i].pin + 2));
426 }
427}
428#endif
429
430void __init arch_init_irq(void)
431{
432 int gic_present, gcmp_present;
433
434 init_i8259_irqs();
435
436 if (!cpu_has_veic)
437 mips_cpu_irq_init();
438
439 gcmp_present = gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ);
440 if (gcmp_present) {
441 GCMPGCB(GICBA) = GIC_BASE_ADDR | GCMP_GCB_GICBA_EN_MSK;
442 gic_present = 1;
443 } else {
444 _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ);
445 gic_present = (REG(_msc01_biu_base, MSC01_SC_CFG) &
446 MSC01_SC_CFG_GICPRES_MSK) >> MSC01_SC_CFG_GICPRES_SHF;
447 }
448 if (gic_present)
449 printk(KERN_DEBUG "GIC present\n");
450
451 switch (mips_revision_sconid) {
452 case MIPS_REVISION_SCON_SOCIT:
453 case MIPS_REVISION_SCON_ROCIT:
454 if (cpu_has_veic)
455 init_msc_irqs(MIPS_MSC01_IC_REG_BASE,
456 MSC01E_INT_BASE, msc_eicirqmap,
457 msc_nr_eicirqs);
458 else
459 init_msc_irqs(MIPS_MSC01_IC_REG_BASE,
460 MSC01C_INT_BASE, msc_irqmap,
461 msc_nr_irqs);
462 break;
463
464 case MIPS_REVISION_SCON_SOCITSC:
465 case MIPS_REVISION_SCON_SOCITSCP:
466 if (cpu_has_veic)
467 init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE,
468 MSC01E_INT_BASE, msc_eicirqmap,
469 msc_nr_eicirqs);
470 else
471 init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE,
472 MSC01C_INT_BASE, msc_irqmap,
473 msc_nr_irqs);
474 }
475
476 if (cpu_has_veic) {
477 set_vi_handler(MSC01E_INT_I8259A, malta_hw0_irqdispatch);
478 set_vi_handler(MSC01E_INT_COREHI, corehi_irqdispatch);
479 setup_irq(MSC01E_INT_BASE+MSC01E_INT_I8259A, &i8259irq);
480 setup_irq(MSC01E_INT_BASE+MSC01E_INT_COREHI, &corehi_irqaction);
481 } else if (cpu_has_vint) {
482 set_vi_handler(MIPSCPU_INT_I8259A, malta_hw0_irqdispatch);
483 set_vi_handler(MIPSCPU_INT_COREHI, corehi_irqdispatch);
484#ifdef CONFIG_MIPS_MT_SMTC
485 setup_irq_smtc(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq,
486 (0x100 << MIPSCPU_INT_I8259A));
487 setup_irq_smtc(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI,
488 &corehi_irqaction, (0x100 << MIPSCPU_INT_COREHI));
489 /*
490 * Temporary hack to ensure that the subsidiary device
491 * interrupts coing in via the i8259A, but associated
492 * with low IRQ numbers, will restore the Status.IM
493 * value associated with the i8259A.
494 */
495 {
496 int i;
497
498 for (i = 0; i < 16; i++)
499 irq_hwmask[i] = (0x100 << MIPSCPU_INT_I8259A);
500 }
501#else /* Not SMTC */
502 setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq);
503 setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI,
504 &corehi_irqaction);
505#endif /* CONFIG_MIPS_MT_SMTC */
506 } else {
507 setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq);
508 setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI,
509 &corehi_irqaction);
510 }
511
512#if defined(CONFIG_MIPS_MT_SMP)
513 if (gic_present) {
514 /* FIXME */
515 int i;
516 struct {
517 unsigned int resched;
518 unsigned int call;
519 } ipiirq[] = {
520 {
521 .resched = GIC_IPI_EXT_INTR_RESCHED_VPE0,
522 .call = GIC_IPI_EXT_INTR_CALLFNC_VPE0},
523 {
524 .resched = GIC_IPI_EXT_INTR_RESCHED_VPE1,
525 .call = GIC_IPI_EXT_INTR_CALLFNC_VPE1
526 }, {
527 .resched = GIC_IPI_EXT_INTR_RESCHED_VPE2,
528 .call = GIC_IPI_EXT_INTR_CALLFNC_VPE2
529 }, {
530 .resched = GIC_IPI_EXT_INTR_RESCHED_VPE3,
531 .call = GIC_IPI_EXT_INTR_CALLFNC_VPE3
532 }
533 };
534 fill_ipi_map();
535 gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
536 if (!gcmp_present) {
537 /* Enable the GIC */
538 i = REG(_msc01_biu_base, MSC01_SC_CFG);
539 REG(_msc01_biu_base, MSC01_SC_CFG) =
540 (i | (0x1 << MSC01_SC_CFG_GICENA_SHF));
541 pr_debug("GIC Enabled\n");
542 }
543
544 /* set up ipi interrupts */
545 if (cpu_has_vint) {
546 set_vi_handler(MIPSCPU_INT_IPI0, malta_ipi_irqdispatch);
547 set_vi_handler(MIPSCPU_INT_IPI1, malta_ipi_irqdispatch);
548 }
549 /* Argh.. this really needs sorting out.. */
550 printk("CPU%d: status register was %08x\n", smp_processor_id(), read_c0_status());
551 write_c0_status(read_c0_status() | STATUSF_IP3 | STATUSF_IP4);
552 printk("CPU%d: status register now %08x\n", smp_processor_id(), read_c0_status());
553 write_c0_status(0x1100dc00);
554 printk("CPU%d: status register frc %08x\n", smp_processor_id(), read_c0_status());
555 for (i = 0; i < ARRAY_SIZE(ipiirq); i++) {
556 setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, &irq_resched);
557 setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].call, &irq_call);
558
559 set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, handle_percpu_irq);
560 set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].call, handle_percpu_irq);
561 }
562 } else {
563 /* set up ipi interrupts */
564 if (cpu_has_veic) {
565 set_vi_handler (MSC01E_INT_SW0, ipi_resched_dispatch);
566 set_vi_handler (MSC01E_INT_SW1, ipi_call_dispatch);
567 cpu_ipi_resched_irq = MSC01E_INT_SW0;
568 cpu_ipi_call_irq = MSC01E_INT_SW1;
569 } else {
570 if (cpu_has_vint) {
571 set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
572 set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
573 }
574 cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
575 cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ;
576 }
577
578 setup_irq(cpu_ipi_resched_irq, &irq_resched);
579 setup_irq(cpu_ipi_call_irq, &irq_call);
580
581 set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq);
582 set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq);
583 }
584#endif
585}
586
587void malta_be_init(void)
588{
589 if (gcmp_present) {
590 /* Could change CM error mask register */
591 }
592}
593
594
595static char *tr[8] = {
596 "mem", "gcr", "gic", "mmio",
597 "0x04", "0x05", "0x06", "0x07"
598};
599
600static char *mcmd[32] = {
601 [0x00] = "0x00",
602 [0x01] = "Legacy Write",
603 [0x02] = "Legacy Read",
604 [0x03] = "0x03",
605 [0x04] = "0x04",
606 [0x05] = "0x05",
607 [0x06] = "0x06",
608 [0x07] = "0x07",
609 [0x08] = "Coherent Read Own",
610 [0x09] = "Coherent Read Share",
611 [0x0a] = "Coherent Read Discard",
612 [0x0b] = "Coherent Ready Share Always",
613 [0x0c] = "Coherent Upgrade",
614 [0x0d] = "Coherent Writeback",
615 [0x0e] = "0x0e",
616 [0x0f] = "0x0f",
617 [0x10] = "Coherent Copyback",
618 [0x11] = "Coherent Copyback Invalidate",
619 [0x12] = "Coherent Invalidate",
620 [0x13] = "Coherent Write Invalidate",
621 [0x14] = "Coherent Completion Sync",
622 [0x15] = "0x15",
623 [0x16] = "0x16",
624 [0x17] = "0x17",
625 [0x18] = "0x18",
626 [0x19] = "0x19",
627 [0x1a] = "0x1a",
628 [0x1b] = "0x1b",
629 [0x1c] = "0x1c",
630 [0x1d] = "0x1d",
631 [0x1e] = "0x1e",
632 [0x1f] = "0x1f"
633};
634
635static char *core[8] = {
636 "Invalid/OK", "Invalid/Data",
637 "Shared/OK", "Shared/Data",
638 "Modified/OK", "Modified/Data",
639 "Exclusive/OK", "Exclusive/Data"
640};
641
642static char *causes[32] = {
643 "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR",
644 "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07",
645 "0x08", "0x09", "0x0a", "0x0b",
646 "0x0c", "0x0d", "0x0e", "0x0f",
647 "0x10", "0x11", "0x12", "0x13",
648 "0x14", "0x15", "0x16", "INTVN_WR_ERR",
649 "INTVN_RD_ERR", "0x19", "0x1a", "0x1b",
650 "0x1c", "0x1d", "0x1e", "0x1f"
651};
652
653int malta_be_handler(struct pt_regs *regs, int is_fixup)
654{
655 /* This duplicates the handling in do_be which seems wrong */
656 int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
657
658 if (gcmp_present) {
659 unsigned long cm_error = GCMPGCB(GCMEC);
660 unsigned long cm_addr = GCMPGCB(GCMEA);
661 unsigned long cm_other = GCMPGCB(GCMEO);
662 unsigned long cause, ocause;
663 char buf[256];
664
665 cause = (cm_error & GCMP_GCB_GMEC_ERROR_TYPE_MSK);
666 if (cause != 0) {
667 cause >>= GCMP_GCB_GMEC_ERROR_TYPE_SHF;
668 if (cause < 16) {
669 unsigned long cca_bits = (cm_error >> 15) & 7;
670 unsigned long tr_bits = (cm_error >> 12) & 7;
671 unsigned long mcmd_bits = (cm_error >> 7) & 0x1f;
672 unsigned long stag_bits = (cm_error >> 3) & 15;
673 unsigned long sport_bits = (cm_error >> 0) & 7;
674
675 snprintf(buf, sizeof(buf),
676 "CCA=%lu TR=%s MCmd=%s STag=%lu "
677 "SPort=%lu\n",
678 cca_bits, tr[tr_bits], mcmd[mcmd_bits],
679 stag_bits, sport_bits);
680 } else {
681 /* glob state & sresp together */
682 unsigned long c3_bits = (cm_error >> 18) & 7;
683 unsigned long c2_bits = (cm_error >> 15) & 7;
684 unsigned long c1_bits = (cm_error >> 12) & 7;
685 unsigned long c0_bits = (cm_error >> 9) & 7;
686 unsigned long sc_bit = (cm_error >> 8) & 1;
687 unsigned long mcmd_bits = (cm_error >> 3) & 0x1f;
688 unsigned long sport_bits = (cm_error >> 0) & 7;
689 snprintf(buf, sizeof(buf),
690 "C3=%s C2=%s C1=%s C0=%s SC=%s "
691 "MCmd=%s SPort=%lu\n",
692 core[c3_bits], core[c2_bits],
693 core[c1_bits], core[c0_bits],
694 sc_bit ? "True" : "False",
695 mcmd[mcmd_bits], sport_bits);
696 }
697
698 ocause = (cm_other & GCMP_GCB_GMEO_ERROR_2ND_MSK) >>
699 GCMP_GCB_GMEO_ERROR_2ND_SHF;
700
701 printk("CM_ERROR=%08lx %s <%s>\n", cm_error,
702 causes[cause], buf);
703 printk("CM_ADDR =%08lx\n", cm_addr);
704 printk("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]);
705
706 /* reprime cause register */
707 GCMPGCB(GCMEC) = 0;
708 }
709 }
710
711 return retval;
712}
diff --git a/arch/mips/mti-malta/malta-kgdb.c b/arch/mips/mti-malta/malta-kgdb.c
new file mode 100644
index 000000000000..6a1854de4579
--- /dev/null
+++ b/arch/mips/mti-malta/malta-kgdb.c
@@ -0,0 +1,133 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * This is the interface to the remote debugger stub.
19 */
20#include <linux/types.h>
21#include <linux/serial.h>
22#include <linux/serialP.h>
23#include <linux/serial_reg.h>
24
25#include <asm/serial.h>
26#include <asm/io.h>
27
28static struct serial_state rs_table[] = {
29 SERIAL_PORT_DFNS /* Defined in serial.h */
30};
31
32static struct async_struct kdb_port_info = {0};
33
34int (*generic_putDebugChar)(char);
35char (*generic_getDebugChar)(void);
36
37static __inline__ unsigned int serial_in(struct async_struct *info, int offset)
38{
39 return inb(info->port + offset);
40}
41
42static __inline__ void serial_out(struct async_struct *info, int offset,
43 int value)
44{
45 outb(value, info->port+offset);
46}
47
48int rs_kgdb_hook(int tty_no, int speed) {
49 int t;
50 struct serial_state *ser = &rs_table[tty_no];
51
52 kdb_port_info.state = ser;
53 kdb_port_info.magic = SERIAL_MAGIC;
54 kdb_port_info.port = ser->port;
55 kdb_port_info.flags = ser->flags;
56
57 /*
58 * Clear all interrupts
59 */
60 serial_in(&kdb_port_info, UART_LSR);
61 serial_in(&kdb_port_info, UART_RX);
62 serial_in(&kdb_port_info, UART_IIR);
63 serial_in(&kdb_port_info, UART_MSR);
64
65 /*
66 * Now, initialize the UART
67 */
68 serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
69 if (kdb_port_info.flags & ASYNC_FOURPORT) {
70 kdb_port_info.MCR = UART_MCR_DTR | UART_MCR_RTS;
71 t = UART_MCR_DTR | UART_MCR_OUT1;
72 } else {
73 kdb_port_info.MCR
74 = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
75 t = UART_MCR_DTR | UART_MCR_RTS;
76 }
77
78 kdb_port_info.MCR = t; /* no interrupts, please */
79 serial_out(&kdb_port_info, UART_MCR, kdb_port_info.MCR);
80
81 /*
82 * and set the speed of the serial port
83 */
84 if (speed == 0)
85 speed = 9600;
86
87 t = kdb_port_info.state->baud_base / speed;
88 /* set DLAB */
89 serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
90 serial_out(&kdb_port_info, UART_DLL, t & 0xff);/* LS of divisor */
91 serial_out(&kdb_port_info, UART_DLM, t >> 8); /* MS of divisor */
92 /* reset DLAB */
93 serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8);
94
95 return speed;
96}
97
98int putDebugChar(char c)
99{
100 return generic_putDebugChar(c);
101}
102
103char getDebugChar(void)
104{
105 return generic_getDebugChar();
106}
107
108int rs_putDebugChar(char c)
109{
110
111 if (!kdb_port_info.state) { /* need to init device first */
112 return 0;
113 }
114
115 while ((serial_in(&kdb_port_info, UART_LSR) & UART_LSR_THRE) == 0)
116 ;
117
118 serial_out(&kdb_port_info, UART_TX, c);
119
120 return 1;
121}
122
123char rs_getDebugChar(void)
124{
125 if (!kdb_port_info.state) { /* need to init device first */
126 return 0;
127 }
128
129 while (!(serial_in(&kdb_port_info, UART_LSR) & 1))
130 ;
131
132 return serial_in(&kdb_port_info, UART_RX);
133}
diff --git a/arch/mips/mti-malta/malta-memory.c b/arch/mips/mti-malta/malta-memory.c
new file mode 100644
index 000000000000..61888ff72c87
--- /dev/null
+++ b/arch/mips/mti-malta/malta-memory.c
@@ -0,0 +1,177 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * PROM library functions for acquiring/using memory descriptors given to
19 * us from the YAMON.
20 */
21#include <linux/init.h>
22#include <linux/mm.h>
23#include <linux/bootmem.h>
24#include <linux/pfn.h>
25#include <linux/string.h>
26
27#include <asm/bootinfo.h>
28#include <asm/page.h>
29#include <asm/sections.h>
30
31#include <asm/mips-boards/prom.h>
32
33/*#define DEBUG*/
34
35enum yamon_memtypes {
36 yamon_dontuse,
37 yamon_prom,
38 yamon_free,
39};
40static struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
41
42#ifdef DEBUG
43static char *mtypes[3] = {
44 "Dont use memory",
45 "YAMON PROM memory",
46 "Free memmory",
47};
48#endif
49
50/* determined physical memory size, not overridden by command line args */
51unsigned long physical_memsize = 0L;
52
53static struct prom_pmemblock * __init prom_getmdesc(void)
54{
55 char *memsize_str;
56 unsigned int memsize;
57 char cmdline[CL_SIZE], *ptr;
58
59 /* otherwise look in the environment */
60 memsize_str = prom_getenv("memsize");
61 if (!memsize_str) {
62 printk(KERN_WARNING
63 "memsize not set in boot prom, set to default (32Mb)\n");
64 physical_memsize = 0x02000000;
65 } else {
66#ifdef DEBUG
67 pr_debug("prom_memsize = %s\n", memsize_str);
68#endif
69 physical_memsize = simple_strtol(memsize_str, NULL, 0);
70 }
71
72#ifdef CONFIG_CPU_BIG_ENDIAN
73 /* SOC-it swaps, or perhaps doesn't swap, when DMA'ing the last
74 word of physical memory */
75 physical_memsize -= PAGE_SIZE;
76#endif
77
78 /* Check the command line for a memsize directive that overrides
79 the physical/default amount */
80 strcpy(cmdline, arcs_cmdline);
81 ptr = strstr(cmdline, "memsize=");
82 if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' '))
83 ptr = strstr(ptr, " memsize=");
84
85 if (ptr)
86 memsize = memparse(ptr + 8, &ptr);
87 else
88 memsize = physical_memsize;
89
90 memset(mdesc, 0, sizeof(mdesc));
91
92 mdesc[0].type = yamon_dontuse;
93 mdesc[0].base = 0x00000000;
94 mdesc[0].size = 0x00001000;
95
96 mdesc[1].type = yamon_prom;
97 mdesc[1].base = 0x00001000;
98 mdesc[1].size = 0x000ef000;
99
100 /*
101 * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the
102 * south bridge and PCI access always forwarded to the ISA Bus and
103 * BIOSCS# is always generated.
104 * This mean that this area can't be used as DMA memory for PCI
105 * devices.
106 */
107 mdesc[2].type = yamon_dontuse;
108 mdesc[2].base = 0x000f0000;
109 mdesc[2].size = 0x00010000;
110
111 mdesc[3].type = yamon_dontuse;
112 mdesc[3].base = 0x00100000;
113 mdesc[3].size = CPHYSADDR(PFN_ALIGN((unsigned long)&_end)) - mdesc[3].base;
114
115 mdesc[4].type = yamon_free;
116 mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end));
117 mdesc[4].size = memsize - mdesc[4].base;
118
119 return &mdesc[0];
120}
121
122static int __init prom_memtype_classify(unsigned int type)
123{
124 switch (type) {
125 case yamon_free:
126 return BOOT_MEM_RAM;
127 case yamon_prom:
128 return BOOT_MEM_ROM_DATA;
129 default:
130 return BOOT_MEM_RESERVED;
131 }
132}
133
134void __init prom_meminit(void)
135{
136 struct prom_pmemblock *p;
137
138#ifdef DEBUG
139 pr_debug("YAMON MEMORY DESCRIPTOR dump:\n");
140 p = prom_getmdesc();
141 while (p->size) {
142 int i = 0;
143 pr_debug("[%d,%p]: base<%08lx> size<%08lx> type<%s>\n",
144 i, p, p->base, p->size, mtypes[p->type]);
145 p++;
146 i++;
147 }
148#endif
149 p = prom_getmdesc();
150
151 while (p->size) {
152 long type;
153 unsigned long base, size;
154
155 type = prom_memtype_classify(p->type);
156 base = p->base;
157 size = p->size;
158
159 add_memory_region(base, size, type);
160 p++;
161 }
162}
163
164void __init prom_free_prom_memory(void)
165{
166 unsigned long addr;
167 int i;
168
169 for (i = 0; i < boot_mem_map.nr_map; i++) {
170 if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
171 continue;
172
173 addr = boot_mem_map.map[i].addr;
174 free_init_pages("prom memory",
175 addr, addr + boot_mem_map.map[i].size);
176 }
177}
diff --git a/arch/mips/mti-malta/malta-mtd.c b/arch/mips/mti-malta/malta-mtd.c
new file mode 100644
index 000000000000..8ad9bdf25dce
--- /dev/null
+++ b/arch/mips/mti-malta/malta-mtd.c
@@ -0,0 +1,63 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2006 MIPS Technologies, Inc.
7 * written by Ralf Baechle <ralf@linux-mips.org>
8 */
9
10#include <linux/init.h>
11#include <linux/platform_device.h>
12#include <linux/mtd/partitions.h>
13#include <linux/mtd/physmap.h>
14#include <mtd/mtd-abi.h>
15
16static struct mtd_partition malta_mtd_partitions[] = {
17 {
18 .name = "YAMON",
19 .offset = 0x0,
20 .size = 0x100000,
21 .mask_flags = MTD_WRITEABLE
22 }, {
23 .name = "User FS",
24 .offset = 0x100000,
25 .size = 0x2e0000
26 }, {
27 .name = "Board Config",
28 .offset = 0x3e0000,
29 .size = 0x020000,
30 .mask_flags = MTD_WRITEABLE
31 }
32};
33
34static struct physmap_flash_data malta_flash_data = {
35 .width = 4,
36 .nr_parts = ARRAY_SIZE(malta_mtd_partitions),
37 .parts = malta_mtd_partitions
38};
39
40static struct resource malta_flash_resource = {
41 .start = 0x1e000000,
42 .end = 0x1e3fffff,
43 .flags = IORESOURCE_MEM
44};
45
46static struct platform_device malta_flash = {
47 .name = "physmap-flash",
48 .id = 0,
49 .dev = {
50 .platform_data = &malta_flash_data,
51 },
52 .num_resources = 1,
53 .resource = &malta_flash_resource,
54};
55
56static int __init malta_mtd_init(void)
57{
58 platform_device_register(&malta_flash);
59
60 return 0;
61}
62
63module_init(malta_mtd_init)
diff --git a/arch/mips/mti-malta/malta-pci.c b/arch/mips/mti-malta/malta-pci.c
new file mode 100644
index 000000000000..b9743190609a
--- /dev/null
+++ b/arch/mips/mti-malta/malta-pci.c
@@ -0,0 +1,243 @@
1/*
2 * Copyright (C) 1999, 2000, 2004, 2005 MIPS Technologies, Inc.
3 * All rights reserved.
4 * Authors: Carsten Langgaard <carstenl@mips.com>
5 * Maciej W. Rozycki <macro@mips.com>
6 *
7 * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
8 *
9 * This program is free software; you can distribute it and/or modify it
10 * under the terms of the GNU General Public License (Version 2) as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
21 *
22 * MIPS boards specific PCI support.
23 */
24#include <linux/types.h>
25#include <linux/pci.h>
26#include <linux/kernel.h>
27#include <linux/init.h>
28
29#include <asm/gt64120.h>
30
31#include <asm/mips-boards/generic.h>
32#include <asm/mips-boards/bonito64.h>
33#include <asm/mips-boards/msc01_pci.h>
34
35static struct resource bonito64_mem_resource = {
36 .name = "Bonito PCI MEM",
37 .flags = IORESOURCE_MEM,
38};
39
40static struct resource bonito64_io_resource = {
41 .name = "Bonito PCI I/O",
42 .start = 0x00000000UL,
43 .end = 0x000fffffUL,
44 .flags = IORESOURCE_IO,
45};
46
47static struct resource gt64120_mem_resource = {
48 .name = "GT-64120 PCI MEM",
49 .flags = IORESOURCE_MEM,
50};
51
52static struct resource gt64120_io_resource = {
53 .name = "GT-64120 PCI I/O",
54 .flags = IORESOURCE_IO,
55};
56
57static struct resource msc_mem_resource = {
58 .name = "MSC PCI MEM",
59 .flags = IORESOURCE_MEM,
60};
61
62static struct resource msc_io_resource = {
63 .name = "MSC PCI I/O",
64 .flags = IORESOURCE_IO,
65};
66
67extern struct pci_ops bonito64_pci_ops;
68extern struct pci_ops gt64xxx_pci0_ops;
69extern struct pci_ops msc_pci_ops;
70
71static struct pci_controller bonito64_controller = {
72 .pci_ops = &bonito64_pci_ops,
73 .io_resource = &bonito64_io_resource,
74 .mem_resource = &bonito64_mem_resource,
75 .io_offset = 0x00000000UL,
76};
77
78static struct pci_controller gt64120_controller = {
79 .pci_ops = &gt64xxx_pci0_ops,
80 .io_resource = &gt64120_io_resource,
81 .mem_resource = &gt64120_mem_resource,
82};
83
84static struct pci_controller msc_controller = {
85 .pci_ops = &msc_pci_ops,
86 .io_resource = &msc_io_resource,
87 .mem_resource = &msc_mem_resource,
88};
89
90void __init mips_pcibios_init(void)
91{
92 struct pci_controller *controller;
93 resource_size_t start, end, map, start1, end1, map1, map2, map3, mask;
94
95 switch (mips_revision_sconid) {
96 case MIPS_REVISION_SCON_GT64120:
97 /*
98 * Due to a bug in the Galileo system controller, we need
99 * to setup the PCI BAR for the Galileo internal registers.
100 * This should be done in the bios/bootprom and will be
101 * fixed in a later revision of YAMON (the MIPS boards
102 * boot prom).
103 */
104 GT_WRITE(GT_PCI0_CFGADDR_OFS,
105 (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */
106 (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */
107 (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/
108 ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/
109 GT_PCI0_CFGADDR_CONFIGEN_BIT);
110
111 /* Perform the write */
112 GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE));
113
114 /* Set up resource ranges from the controller's registers. */
115 start = GT_READ(GT_PCI0M0LD_OFS);
116 end = GT_READ(GT_PCI0M0HD_OFS);
117 map = GT_READ(GT_PCI0M0REMAP_OFS);
118 end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
119 start1 = GT_READ(GT_PCI0M1LD_OFS);
120 end1 = GT_READ(GT_PCI0M1HD_OFS);
121 map1 = GT_READ(GT_PCI0M1REMAP_OFS);
122 end1 = (end1 & GT_PCI_HD_MSK) | (start1 & ~GT_PCI_HD_MSK);
123 /* Cannot support multiple windows, use the wider. */
124 if (end1 - start1 > end - start) {
125 start = start1;
126 end = end1;
127 map = map1;
128 }
129 mask = ~(start ^ end);
130 /* We don't support remapping with a discontiguous mask. */
131 BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
132 mask != ~((mask & -mask) - 1));
133 gt64120_mem_resource.start = start;
134 gt64120_mem_resource.end = end;
135 gt64120_controller.mem_offset = (start & mask) - (map & mask);
136 /* Addresses are 36-bit, so do shifts in the destinations. */
137 gt64120_mem_resource.start <<= GT_PCI_DCRM_SHF;
138 gt64120_mem_resource.end <<= GT_PCI_DCRM_SHF;
139 gt64120_mem_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
140 gt64120_controller.mem_offset <<= GT_PCI_DCRM_SHF;
141
142 start = GT_READ(GT_PCI0IOLD_OFS);
143 end = GT_READ(GT_PCI0IOHD_OFS);
144 map = GT_READ(GT_PCI0IOREMAP_OFS);
145 end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
146 mask = ~(start ^ end);
147 /* We don't support remapping with a discontiguous mask. */
148 BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
149 mask != ~((mask & -mask) - 1));
150 gt64120_io_resource.start = map & mask;
151 gt64120_io_resource.end = (map & mask) | ~mask;
152 gt64120_controller.io_offset = 0;
153 /* Addresses are 36-bit, so do shifts in the destinations. */
154 gt64120_io_resource.start <<= GT_PCI_DCRM_SHF;
155 gt64120_io_resource.end <<= GT_PCI_DCRM_SHF;
156 gt64120_io_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
157
158 controller = &gt64120_controller;
159 break;
160
161 case MIPS_REVISION_SCON_BONITO:
162 /* Set up resource ranges from the controller's registers. */
163 map = BONITO_PCIMAP;
164 map1 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO0) >>
165 BONITO_PCIMAP_PCIMAP_LO0_SHIFT;
166 map2 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO1) >>
167 BONITO_PCIMAP_PCIMAP_LO1_SHIFT;
168 map3 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO2) >>
169 BONITO_PCIMAP_PCIMAP_LO2_SHIFT;
170 /* Combine as many adjacent windows as possible. */
171 map = map1;
172 start = BONITO_PCILO0_BASE;
173 end = 1;
174 if (map3 == map2 + 1) {
175 map = map2;
176 start = BONITO_PCILO1_BASE;
177 end++;
178 }
179 if (map2 == map1 + 1) {
180 map = map1;
181 start = BONITO_PCILO0_BASE;
182 end++;
183 }
184 bonito64_mem_resource.start = start;
185 bonito64_mem_resource.end = start +
186 BONITO_PCIMAP_WINBASE(end) - 1;
187 bonito64_controller.mem_offset = start -
188 BONITO_PCIMAP_WINBASE(map);
189
190 controller = &bonito64_controller;
191 break;
192
193 case MIPS_REVISION_SCON_SOCIT:
194 case MIPS_REVISION_SCON_ROCIT:
195 case MIPS_REVISION_SCON_SOCITSC:
196 case MIPS_REVISION_SCON_SOCITSCP:
197 /* Set up resource ranges from the controller's registers. */
198 MSC_READ(MSC01_PCI_SC2PMBASL, start);
199 MSC_READ(MSC01_PCI_SC2PMMSKL, mask);
200 MSC_READ(MSC01_PCI_SC2PMMAPL, map);
201 msc_mem_resource.start = start & mask;
202 msc_mem_resource.end = (start & mask) | ~mask;
203 msc_controller.mem_offset = (start & mask) - (map & mask);
204
205 MSC_READ(MSC01_PCI_SC2PIOBASL, start);
206 MSC_READ(MSC01_PCI_SC2PIOMSKL, mask);
207 MSC_READ(MSC01_PCI_SC2PIOMAPL, map);
208 msc_io_resource.start = map & mask;
209 msc_io_resource.end = (map & mask) | ~mask;
210 msc_controller.io_offset = 0;
211 ioport_resource.end = ~mask;
212
213 /* If ranges overlap I/O takes precedence. */
214 start = start & mask;
215 end = start | ~mask;
216 if ((start >= msc_mem_resource.start &&
217 start <= msc_mem_resource.end) ||
218 (end >= msc_mem_resource.start &&
219 end <= msc_mem_resource.end)) {
220 /* Use the larger space. */
221 start = max(start, msc_mem_resource.start);
222 end = min(end, msc_mem_resource.end);
223 if (start - msc_mem_resource.start >=
224 msc_mem_resource.end - end)
225 msc_mem_resource.end = start - 1;
226 else
227 msc_mem_resource.start = end + 1;
228 }
229
230 controller = &msc_controller;
231 break;
232 default:
233 return;
234 }
235
236 if (controller->io_resource->start < 0x00001000UL) /* FIXME */
237 controller->io_resource->start = 0x00001000UL;
238
239 iomem_resource.end &= 0xfffffffffULL; /* 64 GB */
240 ioport_resource.end = controller->io_resource->end;
241
242 register_pci_controller(controller);
243}
diff --git a/arch/mips/mti-malta/malta-platform.c b/arch/mips/mti-malta/malta-platform.c
new file mode 100644
index 000000000000..83b9bab3cd3f
--- /dev/null
+++ b/arch/mips/mti-malta/malta-platform.c
@@ -0,0 +1,65 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2007 MIPS Technologies, Inc.
7 * written by Ralf Baechle (ralf@linux-mips.org)
8 *
9 * Probe driver for the Malta's UART ports:
10 *
11 * o 2 ports in the SMC SuperIO
12 * o 1 port in the CBUS UART, a discrete 16550 which normally is only used
13 * for bringups.
14 *
15 * We don't use 8250_platform.c on Malta as it would result in the CBUS
16 * UART becoming ttyS0.
17 */
18#include <linux/module.h>
19#include <linux/init.h>
20#include <linux/serial_8250.h>
21
22#define SMC_PORT(base, int) \
23{ \
24 .iobase = base, \
25 .irq = int, \
26 .uartclk = 1843200, \
27 .iotype = UPIO_PORT, \
28 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
29 .regshift = 0, \
30}
31
32#define CBUS_UART_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP)
33
34static struct plat_serial8250_port uart8250_data[] = {
35 SMC_PORT(0x3F8, 4),
36 SMC_PORT(0x2F8, 3),
37 {
38 .mapbase = 0x1f000900, /* The CBUS UART */
39 .irq = MIPS_CPU_IRQ_BASE + 2,
40 .uartclk = 3686400, /* Twice the usual clk! */
41 .iotype = UPIO_MEM32,
42 .flags = CBUS_UART_FLAGS,
43 .regshift = 3,
44 },
45 { },
46};
47
48static struct platform_device uart8250_device = {
49 .name = "serial8250",
50 .id = PLAT8250_DEV_PLATFORM2,
51 .dev = {
52 .platform_data = uart8250_data,
53 },
54};
55
56static int __init uart8250_init(void)
57{
58 return platform_device_register(&uart8250_device);
59}
60
61module_init(uart8250_init);
62
63MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
64MODULE_LICENSE("GPL");
65MODULE_DESCRIPTION("8250 UART probe driver for the Malta CBUS UART");
diff --git a/arch/mips/mti-malta/malta-reset.c b/arch/mips/mti-malta/malta-reset.c
new file mode 100644
index 000000000000..42dee4da37ba
--- /dev/null
+++ b/arch/mips/mti-malta/malta-reset.c
@@ -0,0 +1,56 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * ########################################################################
6 *
7 * This program is free software; you can distribute it and/or modify it
8 * under the terms of the GNU General Public License (Version 2) as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
19 *
20 * ########################################################################
21 *
22 * Reset the MIPS boards.
23 *
24 */
25#include <linux/pm.h>
26
27#include <asm/io.h>
28#include <asm/reboot.h>
29#include <asm/mips-boards/generic.h>
30
31static void mips_machine_restart(char *command);
32static void mips_machine_halt(void);
33
34static void mips_machine_restart(char *command)
35{
36 unsigned int __iomem *softres_reg =
37 ioremap(SOFTRES_REG, sizeof(unsigned int));
38
39 __raw_writel(GORESET, softres_reg);
40}
41
42static void mips_machine_halt(void)
43{
44 unsigned int __iomem *softres_reg =
45 ioremap(SOFTRES_REG, sizeof(unsigned int));
46
47 __raw_writel(GORESET, softres_reg);
48}
49
50
51void mips_reboot_setup(void)
52{
53 _machine_restart = mips_machine_restart;
54 _machine_halt = mips_machine_halt;
55 pm_power_off = mips_machine_halt;
56}
diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c
new file mode 100644
index 000000000000..e7cad54936ca
--- /dev/null
+++ b/arch/mips/mti-malta/malta-setup.c
@@ -0,0 +1,229 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
4 * Copyright (C) 2008 Dmitri Vorobiev
5 *
6 * This program is free software; you can distribute it and/or modify it
7 * under the terms of the GNU General Public License (Version 2) as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
18 */
19#include <linux/cpu.h>
20#include <linux/init.h>
21#include <linux/sched.h>
22#include <linux/ioport.h>
23#include <linux/irq.h>
24#include <linux/pci.h>
25#include <linux/screen_info.h>
26#include <linux/time.h>
27
28#include <asm/bootinfo.h>
29#include <asm/mips-boards/generic.h>
30#include <asm/mips-boards/prom.h>
31#include <asm/mips-boards/malta.h>
32#include <asm/mips-boards/maltaint.h>
33#include <asm/dma.h>
34#include <asm/traps.h>
35#ifdef CONFIG_VT
36#include <linux/console.h>
37#endif
38
39extern void malta_be_init(void);
40extern int malta_be_handler(struct pt_regs *regs, int is_fixup);
41
42static struct resource standard_io_resources[] = {
43 {
44 .name = "dma1",
45 .start = 0x00,
46 .end = 0x1f,
47 .flags = IORESOURCE_BUSY
48 },
49 {
50 .name = "timer",
51 .start = 0x40,
52 .end = 0x5f,
53 .flags = IORESOURCE_BUSY
54 },
55 {
56 .name = "keyboard",
57 .start = 0x60,
58 .end = 0x6f,
59 .flags = IORESOURCE_BUSY
60 },
61 {
62 .name = "dma page reg",
63 .start = 0x80,
64 .end = 0x8f,
65 .flags = IORESOURCE_BUSY
66 },
67 {
68 .name = "dma2",
69 .start = 0xc0,
70 .end = 0xdf,
71 .flags = IORESOURCE_BUSY
72 },
73};
74
75const char *get_system_type(void)
76{
77 return "MIPS Malta";
78}
79
80#if defined(CONFIG_MIPS_MT_SMTC)
81const char display_string[] = " SMTC LINUX ON MALTA ";
82#else
83const char display_string[] = " LINUX ON MALTA ";
84#endif /* CONFIG_MIPS_MT_SMTC */
85
86#ifdef CONFIG_BLK_DEV_FD
87static void __init fd_activate(void)
88{
89 /*
90 * Activate Floppy Controller in the SMSC FDC37M817 Super I/O
91 * Controller.
92 * Done by YAMON 2.00 onwards
93 */
94 /* Entering config state. */
95 SMSC_WRITE(SMSC_CONFIG_ENTER, SMSC_CONFIG_REG);
96
97 /* Activate floppy controller. */
98 SMSC_WRITE(SMSC_CONFIG_DEVNUM, SMSC_CONFIG_REG);
99 SMSC_WRITE(SMSC_CONFIG_DEVNUM_FLOPPY, SMSC_DATA_REG);
100 SMSC_WRITE(SMSC_CONFIG_ACTIVATE, SMSC_CONFIG_REG);
101 SMSC_WRITE(SMSC_CONFIG_ACTIVATE_ENABLE, SMSC_DATA_REG);
102
103 /* Exit config state. */
104 SMSC_WRITE(SMSC_CONFIG_EXIT, SMSC_CONFIG_REG);
105}
106#endif
107
108#ifdef CONFIG_BLK_DEV_IDE
109static void __init pci_clock_check(void)
110{
111 unsigned int __iomem *jmpr_p =
112 (unsigned int *) ioremap(MALTA_JMPRS_REG, sizeof(unsigned int));
113 int jmpr = (__raw_readl(jmpr_p) >> 2) & 0x07;
114 static const int pciclocks[] __initdata = {
115 33, 20, 25, 30, 12, 16, 37, 10
116 };
117 int pciclock = pciclocks[jmpr];
118 char *argptr = prom_getcmdline();
119
120 if (pciclock != 33 && !strstr(argptr, "idebus=")) {
121 printk(KERN_WARNING "WARNING: PCI clock is %dMHz, "
122 "setting idebus\n", pciclock);
123 argptr += strlen(argptr);
124 sprintf(argptr, " idebus=%d", pciclock);
125 if (pciclock < 20 || pciclock > 66)
126 printk(KERN_WARNING "WARNING: IDE timing "
127 "calculations will be incorrect\n");
128 }
129}
130#endif
131
132#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
133static void __init screen_info_setup(void)
134{
135 screen_info = (struct screen_info) {
136 .orig_x = 0,
137 .orig_y = 25,
138 .ext_mem_k = 0,
139 .orig_video_page = 0,
140 .orig_video_mode = 0,
141 .orig_video_cols = 80,
142 .unused2 = 0,
143 .orig_video_ega_bx = 0,
144 .unused3 = 0,
145 .orig_video_lines = 25,
146 .orig_video_isVGA = VIDEO_TYPE_VGAC,
147 .orig_video_points = 16
148 };
149}
150#endif
151
152static void __init bonito_quirks_setup(void)
153{
154 char *argptr;
155
156 argptr = prom_getcmdline();
157 if (strstr(argptr, "debug")) {
158 BONITO_BONGENCFG |= BONITO_BONGENCFG_DEBUGMODE;
159 printk(KERN_INFO "Enabled Bonito debug mode\n");
160 } else
161 BONITO_BONGENCFG &= ~BONITO_BONGENCFG_DEBUGMODE;
162
163#ifdef CONFIG_DMA_COHERENT
164 if (BONITO_PCICACHECTRL & BONITO_PCICACHECTRL_CPUCOH_PRES) {
165 BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_CPUCOH_EN;
166 printk(KERN_INFO "Enabled Bonito CPU coherency\n");
167
168 argptr = prom_getcmdline();
169 if (strstr(argptr, "iobcuncached")) {
170 BONITO_PCICACHECTRL &= ~BONITO_PCICACHECTRL_IOBCCOH_EN;
171 BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG &
172 ~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
173 BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
174 printk(KERN_INFO "Disabled Bonito IOBC coherency\n");
175 } else {
176 BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_IOBCCOH_EN;
177 BONITO_PCIMEMBASECFG |=
178 (BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
179 BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
180 printk(KERN_INFO "Enabled Bonito IOBC coherency\n");
181 }
182 } else
183 panic("Hardware DMA cache coherency not supported");
184#endif
185}
186
187void __init plat_mem_setup(void)
188{
189 unsigned int i;
190
191 mips_pcibios_init();
192
193 /* Request I/O space for devices used on the Malta board. */
194 for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
195 request_resource(&ioport_resource, standard_io_resources+i);
196
197 /*
198 * Enable DMA channel 4 (cascade channel) in the PIIX4 south bridge.
199 */
200 enable_dma(4);
201
202#ifdef CONFIG_KGDB
203 kgdb_config();
204#endif
205
206#ifdef CONFIG_DMA_COHERENT
207 if (mips_revision_sconid != MIPS_REVISION_SCON_BONITO)
208 panic("Hardware DMA cache coherency not supported");
209#endif
210
211 if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO)
212 bonito_quirks_setup();
213
214#ifdef CONFIG_BLK_DEV_IDE
215 pci_clock_check();
216#endif
217
218#ifdef CONFIG_BLK_DEV_FD
219 fd_activate();
220#endif
221
222#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
223 screen_info_setup();
224#endif
225 mips_reboot_setup();
226
227 board_be_init = malta_be_init;
228 board_be_handler = malta_be_handler;
229}
diff --git a/arch/mips/mti-malta/malta-smtc.c b/arch/mips/mti-malta/malta-smtc.c
new file mode 100644
index 000000000000..5ea705e49454
--- /dev/null
+++ b/arch/mips/mti-malta/malta-smtc.c
@@ -0,0 +1,154 @@
1/*
2 * Malta Platform-specific hooks for SMP operation
3 */
4#include <linux/irq.h>
5#include <linux/init.h>
6
7#include <asm/mipsregs.h>
8#include <asm/mipsmtregs.h>
9#include <asm/smtc.h>
10#include <asm/smtc_ipi.h>
11
12/* VPE/SMP Prototype implements platform interfaces directly */
13
14/*
15 * Cause the specified action to be performed on a targeted "CPU"
16 */
17
18static void msmtc_send_ipi_single(int cpu, unsigned int action)
19{
20 /* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
21 smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
22}
23
24static void msmtc_send_ipi_mask(cpumask_t mask, unsigned int action)
25{
26 unsigned int i;
27
28 for_each_cpu_mask(i, mask)
29 msmtc_send_ipi_single(i, action);
30}
31
32/*
33 * Post-config but pre-boot cleanup entry point
34 */
35static void __cpuinit msmtc_init_secondary(void)
36{
37 void smtc_init_secondary(void);
38 int myvpe;
39
40 /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */
41 myvpe = read_c0_tcbind() & TCBIND_CURVPE;
42 if (myvpe != 0) {
43 /* Ideally, this should be done only once per VPE, but... */
44 clear_c0_status(ST0_IM);
45 set_c0_status((0x100 << cp0_compare_irq)
46 | (0x100 << MIPS_CPU_IPI_IRQ));
47 if (cp0_perfcount_irq >= 0)
48 set_c0_status(0x100 << cp0_perfcount_irq);
49 }
50
51 smtc_init_secondary();
52}
53
54/*
55 * Platform "CPU" startup hook
56 */
57static void __cpuinit msmtc_boot_secondary(int cpu, struct task_struct *idle)
58{
59 smtc_boot_secondary(cpu, idle);
60}
61
62/*
63 * SMP initialization finalization entry point
64 */
65static void __cpuinit msmtc_smp_finish(void)
66{
67 smtc_smp_finish();
68}
69
70/*
71 * Hook for after all CPUs are online
72 */
73
74static void msmtc_cpus_done(void)
75{
76}
77
78/*
79 * Platform SMP pre-initialization
80 *
81 * As noted above, we can assume a single CPU for now
82 * but it may be multithreaded.
83 */
84
85static void __init msmtc_smp_setup(void)
86{
87 mipsmt_build_cpu_map(0);
88}
89
90static void __init msmtc_prepare_cpus(unsigned int max_cpus)
91{
92 mipsmt_prepare_cpus();
93}
94
95struct plat_smp_ops msmtc_smp_ops = {
96 .send_ipi_single = msmtc_send_ipi_single,
97 .send_ipi_mask = msmtc_send_ipi_mask,
98 .init_secondary = msmtc_init_secondary,
99 .smp_finish = msmtc_smp_finish,
100 .cpus_done = msmtc_cpus_done,
101 .boot_secondary = msmtc_boot_secondary,
102 .smp_setup = msmtc_smp_setup,
103 .prepare_cpus = msmtc_prepare_cpus,
104};
105
106#ifdef CONFIG_MIPS_MT_SMTC_IRQAFF
107/*
108 * IRQ affinity hook
109 */
110
111
112void plat_set_irq_affinity(unsigned int irq, cpumask_t affinity)
113{
114 cpumask_t tmask = affinity;
115 int cpu = 0;
116 void smtc_set_irq_affinity(unsigned int irq, cpumask_t aff);
117
118 /*
119 * On the legacy Malta development board, all I/O interrupts
120 * are routed through the 8259 and combined in a single signal
121 * to the CPU daughterboard, and on the CoreFPGA2/3 34K models,
122 * that signal is brought to IP2 of both VPEs. To avoid racing
123 * concurrent interrupt service events, IP2 is enabled only on
124 * one VPE, by convention VPE0. So long as no bits are ever
125 * cleared in the affinity mask, there will never be any
126 * interrupt forwarding. But as soon as a program or operator
127 * sets affinity for one of the related IRQs, we need to make
128 * sure that we don't ever try to forward across the VPE boundry,
129 * at least not until we engineer a system where the interrupt
130 * _ack() or _end() function can somehow know that it corresponds
131 * to an interrupt taken on another VPE, and perform the appropriate
132 * restoration of Status.IM state using MFTR/MTTR instead of the
133 * normal local behavior. We also ensure that no attempt will
134 * be made to forward to an offline "CPU".
135 */
136
137 for_each_cpu_mask(cpu, affinity) {
138 if ((cpu_data[cpu].vpe_id != 0) || !cpu_online(cpu))
139 cpu_clear(cpu, tmask);
140 }
141 irq_desc[irq].affinity = tmask;
142
143 if (cpus_empty(tmask))
144 /*
145 * We could restore a default mask here, but the
146 * runtime code can anyway deal with the null set
147 */
148 printk(KERN_WARNING
149 "IRQ affinity leaves no legal CPU for IRQ %d\n", irq);
150
151 /* Do any generic SMTC IRQ affinity setup */
152 smtc_set_irq_affinity(irq, tmask);
153}
154#endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */
diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c
new file mode 100644
index 000000000000..0b97d47691fc
--- /dev/null
+++ b/arch/mips/mti-malta/malta-time.c
@@ -0,0 +1,163 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * Setting up the clock on the MIPS boards.
19 */
20
21#include <linux/types.h>
22#include <linux/init.h>
23#include <linux/kernel_stat.h>
24#include <linux/sched.h>
25#include <linux/spinlock.h>
26#include <linux/interrupt.h>
27#include <linux/time.h>
28#include <linux/timex.h>
29#include <linux/mc146818rtc.h>
30
31#include <asm/mipsregs.h>
32#include <asm/mipsmtregs.h>
33#include <asm/hardirq.h>
34#include <asm/i8253.h>
35#include <asm/irq.h>
36#include <asm/div64.h>
37#include <asm/cpu.h>
38#include <asm/time.h>
39#include <asm/mc146818-time.h>
40#include <asm/msc01_ic.h>
41
42#include <asm/mips-boards/generic.h>
43#include <asm/mips-boards/prom.h>
44
45#include <asm/mips-boards/maltaint.h>
46
47unsigned long cpu_khz;
48
49static int mips_cpu_timer_irq;
50static int mips_cpu_perf_irq;
51extern int cp0_perfcount_irq;
52
53static void mips_timer_dispatch(void)
54{
55 do_IRQ(mips_cpu_timer_irq);
56}
57
58static void mips_perf_dispatch(void)
59{
60 do_IRQ(mips_cpu_perf_irq);
61}
62
63/*
64 * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect
65 */
66static unsigned int __init estimate_cpu_frequency(void)
67{
68 unsigned int prid = read_c0_prid() & 0xffff00;
69 unsigned int count;
70
71 unsigned long flags;
72 unsigned int start;
73
74 local_irq_save(flags);
75
76 /* Start counter exactly on falling edge of update flag */
77 while (CMOS_READ(RTC_REG_A) & RTC_UIP);
78 while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
79
80 /* Start r4k counter. */
81 start = read_c0_count();
82
83 /* Read counter exactly on falling edge of update flag */
84 while (CMOS_READ(RTC_REG_A) & RTC_UIP);
85 while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
86
87 count = read_c0_count() - start;
88
89 /* restore interrupts */
90 local_irq_restore(flags);
91
92 mips_hpt_frequency = count;
93 if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) &&
94 (prid != (PRID_COMP_MIPS | PRID_IMP_25KF)))
95 count *= 2;
96
97 count += 5000; /* round */
98 count -= count%10000;
99
100 return count;
101}
102
103unsigned long read_persistent_clock(void)
104{
105 return mc146818_get_cmos_time();
106}
107
108static void __init plat_perf_setup(void)
109{
110#ifdef MSC01E_INT_BASE
111 if (cpu_has_veic) {
112 set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
113 mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
114 } else
115#endif
116 if (cp0_perfcount_irq >= 0) {
117 if (cpu_has_vint)
118 set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
119 mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
120#ifdef CONFIG_SMP
121 set_irq_handler(mips_cpu_perf_irq, handle_percpu_irq);
122#endif
123 }
124}
125
126unsigned int __cpuinit get_c0_compare_int(void)
127{
128#ifdef MSC01E_INT_BASE
129 if (cpu_has_veic) {
130 set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch);
131 mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
132 } else
133#endif
134 {
135 if (cpu_has_vint)
136 set_vi_handler(cp0_compare_irq, mips_timer_dispatch);
137 mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
138 }
139
140 return mips_cpu_timer_irq;
141}
142
143void __init plat_time_init(void)
144{
145 unsigned int est_freq;
146
147 /* Set Data mode - binary. */
148 CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);
149
150 est_freq = estimate_cpu_frequency();
151
152 printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
153 (est_freq%1000000)*100/1000000);
154
155 cpu_khz = est_freq / 1000;
156
157 mips_scroll_message();
158#ifdef CONFIG_I8253 /* Only Malta has a PIT */
159 setup_pit_timer();
160#endif
161
162 plat_perf_setup();
163}