diff options
Diffstat (limited to 'arch/mips/mti-malta')
-rw-r--r-- | arch/mips/mti-malta/Makefile | 21 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-amon.c | 80 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-cmdline.c | 59 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-console.c | 47 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-display.c | 64 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-init.c | 424 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-int.c | 712 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-kgdb.c | 133 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-memory.c | 177 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-mtd.c | 63 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-pci.c | 243 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-platform.c | 65 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-reset.c | 56 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-setup.c | 229 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-smtc.c | 154 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-time.c | 163 |
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 | # | ||
8 | obj-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 | |||
14 | obj-$(CONFIG_EARLY_PRINTK) += malta-console.o | ||
15 | obj-$(CONFIG_PCI) += malta-pci.o | ||
16 | obj-$(CONFIG_KGDB) += malta-kgdb.o | ||
17 | |||
18 | # FIXME FIXME FIXME | ||
19 | obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o | ||
20 | |||
21 | EXTRA_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 | |||
29 | int 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 | |||
51 | void 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 | |||
25 | extern int prom_argc; | ||
26 | extern 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 | |||
34 | char * __init prom_getcmdline(void) | ||
35 | { | ||
36 | return &(arcs_cmdline[0]); | ||
37 | } | ||
38 | |||
39 | |||
40 | void __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 | |||
29 | static inline unsigned int serial_in(int offset) | ||
30 | { | ||
31 | return inb(PORT(offset)); | ||
32 | } | ||
33 | |||
34 | static inline void serial_out(int offset, int value) | ||
35 | { | ||
36 | outb(value, PORT(offset)); | ||
37 | } | ||
38 | |||
39 | int 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 | |||
27 | extern const char display_string[]; | ||
28 | static unsigned int display_count; | ||
29 | static unsigned int max_display_count; | ||
30 | |||
31 | void 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 | |||
47 | static void scroll_display_message(unsigned long data); | ||
48 | static DEFINE_TIMER(mips_scroll_timer, scroll_display_message, HZ, 0); | ||
49 | |||
50 | static 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 | |||
59 | void 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 | ||
41 | extern int rs_kgdb_hook(int, int); | ||
42 | extern int rs_putDebugChar(char); | ||
43 | extern char rs_getDebugChar(void); | ||
44 | extern int saa9730_kgdb_hook(int); | ||
45 | extern int saa9730_putDebugChar(char); | ||
46 | extern char saa9730_getDebugChar(void); | ||
47 | #endif | ||
48 | |||
49 | int prom_argc; | ||
50 | int *_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 | |||
58 | int init_debug = 0; | ||
59 | |||
60 | int mips_revision_corid; | ||
61 | int mips_revision_sconid; | ||
62 | |||
63 | /* Bonito64 system controller register base. */ | ||
64 | unsigned long _pcictrl_bonito; | ||
65 | unsigned long _pcictrl_bonito_pcicfg; | ||
66 | |||
67 | /* GT64120 system controller register base */ | ||
68 | unsigned long _pcictrl_gt64120; | ||
69 | |||
70 | /* MIPS System controller register base */ | ||
71 | unsigned long _pcictrl_msc; | ||
72 | |||
73 | char *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 | |||
95 | static 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 | |||
104 | static 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 | |||
119 | int 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 | ||
142 | static 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 | ||
177 | void __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 | |||
221 | static 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 | |||
233 | static 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 | |||
245 | extern struct plat_smp_ops msmtc_smp_ops; | ||
246 | |||
247 | void __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 | |||
48 | int gcmp_present = -1; | ||
49 | int gic_present; | ||
50 | static unsigned long _msc01_biu_base; | ||
51 | static unsigned long _gcmp_base; | ||
52 | static unsigned int ipi_map[NR_CPUS]; | ||
53 | |||
54 | static DEFINE_SPINLOCK(mips_irq_lock); | ||
55 | |||
56 | static 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 | |||
101 | static 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 | |||
120 | static 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 | |||
133 | static 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 | |||
144 | static 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 | |||
200 | static 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 | */ | ||
216 | static 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 | |||
271 | asmlinkage 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 | ||
298 | static int cpu_ipi_resched_irq, cpu_ipi_call_irq; | ||
299 | |||
300 | static void ipi_resched_dispatch(void) | ||
301 | { | ||
302 | do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); | ||
303 | } | ||
304 | |||
305 | static void ipi_call_dispatch(void) | ||
306 | { | ||
307 | do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); | ||
308 | } | ||
309 | |||
310 | static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) | ||
311 | { | ||
312 | return IRQ_HANDLED; | ||
313 | } | ||
314 | |||
315 | static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) | ||
316 | { | ||
317 | smp_call_function_interrupt(); | ||
318 | |||
319 | return IRQ_HANDLED; | ||
320 | } | ||
321 | |||
322 | static struct irqaction irq_resched = { | ||
323 | .handler = ipi_resched_interrupt, | ||
324 | .flags = IRQF_DISABLED|IRQF_PERCPU, | ||
325 | .name = "IPI_resched" | ||
326 | }; | ||
327 | |||
328 | static 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 | |||
335 | static struct irqaction i8259irq = { | ||
336 | .handler = no_action, | ||
337 | .name = "XT-PIC cascade" | ||
338 | }; | ||
339 | |||
340 | static struct irqaction corehi_irqaction = { | ||
341 | .handler = no_action, | ||
342 | .name = "CoreHi" | ||
343 | }; | ||
344 | |||
345 | static msc_irqmap_t __initdata msc_irqmap[] = { | ||
346 | {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, | ||
347 | {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, | ||
348 | }; | ||
349 | static int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap); | ||
350 | |||
351 | static 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 | |||
364 | static 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 | */ | ||
372 | static 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 | */ | ||
403 | static 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) | ||
418 | static 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 | |||
430 | void __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 | |||
587 | void malta_be_init(void) | ||
588 | { | ||
589 | if (gcmp_present) { | ||
590 | /* Could change CM error mask register */ | ||
591 | } | ||
592 | } | ||
593 | |||
594 | |||
595 | static char *tr[8] = { | ||
596 | "mem", "gcr", "gic", "mmio", | ||
597 | "0x04", "0x05", "0x06", "0x07" | ||
598 | }; | ||
599 | |||
600 | static 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 | |||
635 | static 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 | |||
642 | static 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 | |||
653 | int 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 | |||
28 | static struct serial_state rs_table[] = { | ||
29 | SERIAL_PORT_DFNS /* Defined in serial.h */ | ||
30 | }; | ||
31 | |||
32 | static struct async_struct kdb_port_info = {0}; | ||
33 | |||
34 | int (*generic_putDebugChar)(char); | ||
35 | char (*generic_getDebugChar)(void); | ||
36 | |||
37 | static __inline__ unsigned int serial_in(struct async_struct *info, int offset) | ||
38 | { | ||
39 | return inb(info->port + offset); | ||
40 | } | ||
41 | |||
42 | static __inline__ void serial_out(struct async_struct *info, int offset, | ||
43 | int value) | ||
44 | { | ||
45 | outb(value, info->port+offset); | ||
46 | } | ||
47 | |||
48 | int 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 | |||
98 | int putDebugChar(char c) | ||
99 | { | ||
100 | return generic_putDebugChar(c); | ||
101 | } | ||
102 | |||
103 | char getDebugChar(void) | ||
104 | { | ||
105 | return generic_getDebugChar(); | ||
106 | } | ||
107 | |||
108 | int 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 | |||
123 | char 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 | |||
35 | enum yamon_memtypes { | ||
36 | yamon_dontuse, | ||
37 | yamon_prom, | ||
38 | yamon_free, | ||
39 | }; | ||
40 | static struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; | ||
41 | |||
42 | #ifdef DEBUG | ||
43 | static 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 */ | ||
51 | unsigned long physical_memsize = 0L; | ||
52 | |||
53 | static 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 | |||
122 | static 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 | |||
134 | void __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 | |||
164 | void __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 | |||
16 | static 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 | |||
34 | static 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 | |||
40 | static struct resource malta_flash_resource = { | ||
41 | .start = 0x1e000000, | ||
42 | .end = 0x1e3fffff, | ||
43 | .flags = IORESOURCE_MEM | ||
44 | }; | ||
45 | |||
46 | static 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 | |||
56 | static int __init malta_mtd_init(void) | ||
57 | { | ||
58 | platform_device_register(&malta_flash); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | module_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 | |||
35 | static struct resource bonito64_mem_resource = { | ||
36 | .name = "Bonito PCI MEM", | ||
37 | .flags = IORESOURCE_MEM, | ||
38 | }; | ||
39 | |||
40 | static struct resource bonito64_io_resource = { | ||
41 | .name = "Bonito PCI I/O", | ||
42 | .start = 0x00000000UL, | ||
43 | .end = 0x000fffffUL, | ||
44 | .flags = IORESOURCE_IO, | ||
45 | }; | ||
46 | |||
47 | static struct resource gt64120_mem_resource = { | ||
48 | .name = "GT-64120 PCI MEM", | ||
49 | .flags = IORESOURCE_MEM, | ||
50 | }; | ||
51 | |||
52 | static struct resource gt64120_io_resource = { | ||
53 | .name = "GT-64120 PCI I/O", | ||
54 | .flags = IORESOURCE_IO, | ||
55 | }; | ||
56 | |||
57 | static struct resource msc_mem_resource = { | ||
58 | .name = "MSC PCI MEM", | ||
59 | .flags = IORESOURCE_MEM, | ||
60 | }; | ||
61 | |||
62 | static struct resource msc_io_resource = { | ||
63 | .name = "MSC PCI I/O", | ||
64 | .flags = IORESOURCE_IO, | ||
65 | }; | ||
66 | |||
67 | extern struct pci_ops bonito64_pci_ops; | ||
68 | extern struct pci_ops gt64xxx_pci0_ops; | ||
69 | extern struct pci_ops msc_pci_ops; | ||
70 | |||
71 | static 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 | |||
78 | static struct pci_controller gt64120_controller = { | ||
79 | .pci_ops = >64xxx_pci0_ops, | ||
80 | .io_resource = >64120_io_resource, | ||
81 | .mem_resource = >64120_mem_resource, | ||
82 | }; | ||
83 | |||
84 | static 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 | |||
90 | void __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 = >64120_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 | |||
34 | static 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 | |||
48 | static struct platform_device uart8250_device = { | ||
49 | .name = "serial8250", | ||
50 | .id = PLAT8250_DEV_PLATFORM2, | ||
51 | .dev = { | ||
52 | .platform_data = uart8250_data, | ||
53 | }, | ||
54 | }; | ||
55 | |||
56 | static int __init uart8250_init(void) | ||
57 | { | ||
58 | return platform_device_register(&uart8250_device); | ||
59 | } | ||
60 | |||
61 | module_init(uart8250_init); | ||
62 | |||
63 | MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>"); | ||
64 | MODULE_LICENSE("GPL"); | ||
65 | MODULE_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 | |||
31 | static void mips_machine_restart(char *command); | ||
32 | static void mips_machine_halt(void); | ||
33 | |||
34 | static 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 | |||
42 | static 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 | |||
51 | void 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 | |||
39 | extern void malta_be_init(void); | ||
40 | extern int malta_be_handler(struct pt_regs *regs, int is_fixup); | ||
41 | |||
42 | static 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 | |||
75 | const char *get_system_type(void) | ||
76 | { | ||
77 | return "MIPS Malta"; | ||
78 | } | ||
79 | |||
80 | #if defined(CONFIG_MIPS_MT_SMTC) | ||
81 | const char display_string[] = " SMTC LINUX ON MALTA "; | ||
82 | #else | ||
83 | const char display_string[] = " LINUX ON MALTA "; | ||
84 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
85 | |||
86 | #ifdef CONFIG_BLK_DEV_FD | ||
87 | static 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 | ||
109 | static 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) | ||
133 | static 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 | |||
152 | static 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 | |||
187 | void __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 | |||
18 | static 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 | |||
24 | static 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 | */ | ||
35 | static 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 | */ | ||
57 | static 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 | */ | ||
65 | static void __cpuinit msmtc_smp_finish(void) | ||
66 | { | ||
67 | smtc_smp_finish(); | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * Hook for after all CPUs are online | ||
72 | */ | ||
73 | |||
74 | static 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 | |||
85 | static void __init msmtc_smp_setup(void) | ||
86 | { | ||
87 | mipsmt_build_cpu_map(0); | ||
88 | } | ||
89 | |||
90 | static void __init msmtc_prepare_cpus(unsigned int max_cpus) | ||
91 | { | ||
92 | mipsmt_prepare_cpus(); | ||
93 | } | ||
94 | |||
95 | struct 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 | |||
112 | void 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 | |||
47 | unsigned long cpu_khz; | ||
48 | |||
49 | static int mips_cpu_timer_irq; | ||
50 | static int mips_cpu_perf_irq; | ||
51 | extern int cp0_perfcount_irq; | ||
52 | |||
53 | static void mips_timer_dispatch(void) | ||
54 | { | ||
55 | do_IRQ(mips_cpu_timer_irq); | ||
56 | } | ||
57 | |||
58 | static 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 | */ | ||
66 | static 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 | |||
103 | unsigned long read_persistent_clock(void) | ||
104 | { | ||
105 | return mc146818_get_cmos_time(); | ||
106 | } | ||
107 | |||
108 | static 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 | |||
126 | unsigned 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 | |||
143 | void __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 | } | ||