diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/mips/dec/prom |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/mips/dec/prom')
-rw-r--r-- | arch/mips/dec/prom/Makefile | 11 | ||||
-rw-r--r-- | arch/mips/dec/prom/call_o32.S | 91 | ||||
-rw-r--r-- | arch/mips/dec/prom/cmdline.c | 39 | ||||
-rw-r--r-- | arch/mips/dec/prom/console.c | 55 | ||||
-rw-r--r-- | arch/mips/dec/prom/dectypes.h | 14 | ||||
-rw-r--r-- | arch/mips/dec/prom/identify.c | 177 | ||||
-rw-r--r-- | arch/mips/dec/prom/init.c | 134 | ||||
-rw-r--r-- | arch/mips/dec/prom/locore.S | 30 | ||||
-rw-r--r-- | arch/mips/dec/prom/memory.c | 130 |
9 files changed, 681 insertions, 0 deletions
diff --git a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile new file mode 100644 index 000000000000..373822ec2d8c --- /dev/null +++ b/arch/mips/dec/prom/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # | ||
2 | # Makefile for the DECstation prom monitor library routines | ||
3 | # under Linux. | ||
4 | # | ||
5 | |||
6 | lib-y += init.o memory.o cmdline.o identify.o console.o | ||
7 | |||
8 | lib-$(CONFIG_MIPS32) += locore.o | ||
9 | lib-$(CONFIG_MIPS64) += call_o32.o | ||
10 | |||
11 | EXTRA_AFLAGS := $(CFLAGS) | ||
diff --git a/arch/mips/dec/prom/call_o32.S b/arch/mips/dec/prom/call_o32.S new file mode 100644 index 000000000000..0dd56db9b3d0 --- /dev/null +++ b/arch/mips/dec/prom/call_o32.S | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * arch/mips/dec/call_o32.S | ||
3 | * | ||
4 | * O32 interface for the 64 (or N32) ABI. | ||
5 | * | ||
6 | * Copyright (C) 2002 Maciej W. Rozycki | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <asm/asm.h> | ||
15 | #include <asm/regdef.h> | ||
16 | |||
17 | /* Maximum number of arguments supported. Must be even! */ | ||
18 | #define O32_ARGC 32 | ||
19 | /* Number of static registers we save. */ | ||
20 | #define O32_STATC 11 | ||
21 | /* Frame size for both of the above. */ | ||
22 | #define O32_FRAMESZ (4 * O32_ARGC + SZREG * O32_STATC) | ||
23 | |||
24 | .text | ||
25 | |||
26 | /* | ||
27 | * O32 function call dispatcher, for interfacing 32-bit ROM routines. | ||
28 | * | ||
29 | * The standard 64 (N32) calling sequence is supported, with a0 | ||
30 | * holding a function pointer, a1-a7 -- its first seven arguments | ||
31 | * and the stack -- remaining ones (up to O32_ARGC, including a1-a7). | ||
32 | * Static registers, gp and fp are preserved, v0 holds a result. | ||
33 | * This code relies on the called o32 function for sp and ra | ||
34 | * restoration and thus both this dispatcher and the current stack | ||
35 | * have to be placed in a KSEGx (or KUSEG) address space. Any | ||
36 | * pointers passed have to point to addresses within one of these | ||
37 | * spaces as well. | ||
38 | */ | ||
39 | NESTED(call_o32, O32_FRAMESZ, ra) | ||
40 | REG_SUBU sp,O32_FRAMESZ | ||
41 | |||
42 | REG_S ra,O32_FRAMESZ-1*SZREG(sp) | ||
43 | REG_S fp,O32_FRAMESZ-2*SZREG(sp) | ||
44 | REG_S gp,O32_FRAMESZ-3*SZREG(sp) | ||
45 | REG_S s7,O32_FRAMESZ-4*SZREG(sp) | ||
46 | REG_S s6,O32_FRAMESZ-5*SZREG(sp) | ||
47 | REG_S s5,O32_FRAMESZ-6*SZREG(sp) | ||
48 | REG_S s4,O32_FRAMESZ-7*SZREG(sp) | ||
49 | REG_S s3,O32_FRAMESZ-8*SZREG(sp) | ||
50 | REG_S s2,O32_FRAMESZ-9*SZREG(sp) | ||
51 | REG_S s1,O32_FRAMESZ-10*SZREG(sp) | ||
52 | REG_S s0,O32_FRAMESZ-11*SZREG(sp) | ||
53 | |||
54 | move jp,a0 | ||
55 | |||
56 | sll a0,a1,zero | ||
57 | sll a1,a2,zero | ||
58 | sll a2,a3,zero | ||
59 | sll a3,a4,zero | ||
60 | sw a5,0x10(sp) | ||
61 | sw a6,0x14(sp) | ||
62 | sw a7,0x18(sp) | ||
63 | |||
64 | PTR_LA t0,O32_FRAMESZ(sp) | ||
65 | PTR_LA t1,0x1c(sp) | ||
66 | li t2,O32_ARGC-7 | ||
67 | 1: | ||
68 | lw t3,(t0) | ||
69 | REG_ADDU t0,SZREG | ||
70 | sw t3,(t1) | ||
71 | REG_SUBU t2,1 | ||
72 | REG_ADDU t1,4 | ||
73 | bnez t2,1b | ||
74 | |||
75 | jalr jp | ||
76 | |||
77 | REG_L s0,O32_FRAMESZ-11*SZREG(sp) | ||
78 | REG_L s1,O32_FRAMESZ-10*SZREG(sp) | ||
79 | REG_L s2,O32_FRAMESZ-9*SZREG(sp) | ||
80 | REG_L s3,O32_FRAMESZ-8*SZREG(sp) | ||
81 | REG_L s4,O32_FRAMESZ-7*SZREG(sp) | ||
82 | REG_L s5,O32_FRAMESZ-6*SZREG(sp) | ||
83 | REG_L s6,O32_FRAMESZ-5*SZREG(sp) | ||
84 | REG_L s7,O32_FRAMESZ-4*SZREG(sp) | ||
85 | REG_L gp,O32_FRAMESZ-3*SZREG(sp) | ||
86 | REG_L fp,O32_FRAMESZ-2*SZREG(sp) | ||
87 | REG_L ra,O32_FRAMESZ-1*SZREG(sp) | ||
88 | |||
89 | REG_ADDU sp,O32_FRAMESZ | ||
90 | jr ra | ||
91 | END(call_o32) | ||
diff --git a/arch/mips/dec/prom/cmdline.c b/arch/mips/dec/prom/cmdline.c new file mode 100644 index 000000000000..c3490bebbc5d --- /dev/null +++ b/arch/mips/dec/prom/cmdline.c | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * cmdline.c: read the command line passed to us by the PROM. | ||
3 | * | ||
4 | * Copyright (C) 1998 Harald Koerfgen | ||
5 | * Copyright (C) 2002, 2004 Maciej W. Rozycki | ||
6 | */ | ||
7 | #include <linux/init.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/string.h> | ||
10 | #include <linux/types.h> | ||
11 | |||
12 | #include <asm/bootinfo.h> | ||
13 | #include <asm/dec/prom.h> | ||
14 | |||
15 | #undef PROM_DEBUG | ||
16 | |||
17 | void __init prom_init_cmdline(s32 argc, s32 *argv, u32 magic) | ||
18 | { | ||
19 | char *arg; | ||
20 | int start_arg, i; | ||
21 | |||
22 | /* | ||
23 | * collect args and prepare cmd_line | ||
24 | */ | ||
25 | if (!prom_is_rex(magic)) | ||
26 | start_arg = 1; | ||
27 | else | ||
28 | start_arg = 2; | ||
29 | for (i = start_arg; i < argc; i++) { | ||
30 | arg = (void *)(long)(argv[i]); | ||
31 | strcat(arcs_cmdline, arg); | ||
32 | if (i < (argc - 1)) | ||
33 | strcat(arcs_cmdline, " "); | ||
34 | } | ||
35 | |||
36 | #ifdef PROM_DEBUG | ||
37 | printk("arcs_cmdline: %s\n", &(arcs_cmdline[0])); | ||
38 | #endif | ||
39 | } | ||
diff --git a/arch/mips/dec/prom/console.c b/arch/mips/dec/prom/console.c new file mode 100644 index 000000000000..cade16ec7e5a --- /dev/null +++ b/arch/mips/dec/prom/console.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * arch/mips/dec/prom/console.c | ||
3 | * | ||
4 | * DECstation PROM-based early console support. | ||
5 | * | ||
6 | * Copyright (C) 2004 Maciej W. Rozycki | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | */ | ||
13 | #include <linux/console.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/kernel.h> | ||
16 | |||
17 | #include <asm/dec/prom.h> | ||
18 | |||
19 | static void __init prom_console_write(struct console *con, const char *s, | ||
20 | unsigned int c) | ||
21 | { | ||
22 | static char sfmt[] __initdata = "%%%us"; | ||
23 | char fmt[13]; | ||
24 | |||
25 | snprintf(fmt, sizeof(fmt), sfmt, c); | ||
26 | prom_printf(fmt, s); | ||
27 | } | ||
28 | |||
29 | static struct console promcons __initdata = { | ||
30 | .name = "prom", | ||
31 | .write = prom_console_write, | ||
32 | .flags = CON_PRINTBUFFER, | ||
33 | .index = -1, | ||
34 | }; | ||
35 | |||
36 | static int promcons_output __initdata = 0; | ||
37 | |||
38 | void __init register_prom_console(void) | ||
39 | { | ||
40 | if (!promcons_output) { | ||
41 | promcons_output = 1; | ||
42 | register_console(&promcons); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | void __init unregister_prom_console(void) | ||
47 | { | ||
48 | if (promcons_output) { | ||
49 | unregister_console(&promcons); | ||
50 | promcons_output = 0; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | void disable_early_printk(void) | ||
55 | __attribute__((alias("unregister_prom_console"))); | ||
diff --git a/arch/mips/dec/prom/dectypes.h b/arch/mips/dec/prom/dectypes.h new file mode 100644 index 000000000000..707b6f1f5a9d --- /dev/null +++ b/arch/mips/dec/prom/dectypes.h | |||
@@ -0,0 +1,14 @@ | |||
1 | #ifndef DECTYPES | ||
2 | #define DECTYPES | ||
3 | |||
4 | #define DS2100_3100 1 /* DS2100/3100 Pmax */ | ||
5 | #define DS5000_200 2 /* DS5000/200 3max */ | ||
6 | #define DS5000_1XX 3 /* DS5000/1xx kmin */ | ||
7 | #define DS5000_2X0 4 /* DS5000/2x0 3max+ */ | ||
8 | #define DS5800 5 /* DS5800 Isis */ | ||
9 | #define DS5400 6 /* DS5400 MIPSfair */ | ||
10 | #define DS5000_XX 7 /* DS5000/xx maxine */ | ||
11 | #define DS5500 11 /* DS5500 MIPSfair-2 */ | ||
12 | #define DS5100 12 /* DS5100 MIPSmate */ | ||
13 | |||
14 | #endif | ||
diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c new file mode 100644 index 000000000000..9380588cb15c --- /dev/null +++ b/arch/mips/dec/prom/identify.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * identify.c: machine identification code. | ||
3 | * | ||
4 | * Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine | ||
5 | * Copyright (C) 2002, 2003, 2004 Maciej W. Rozycki | ||
6 | */ | ||
7 | #include <linux/init.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/mc146818rtc.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/string.h> | ||
12 | #include <linux/types.h> | ||
13 | |||
14 | #include <asm/bootinfo.h> | ||
15 | #include <asm/dec/ioasic.h> | ||
16 | #include <asm/dec/ioasic_addrs.h> | ||
17 | #include <asm/dec/kn01.h> | ||
18 | #include <asm/dec/kn02.h> | ||
19 | #include <asm/dec/kn02ba.h> | ||
20 | #include <asm/dec/kn02ca.h> | ||
21 | #include <asm/dec/kn03.h> | ||
22 | #include <asm/dec/kn230.h> | ||
23 | #include <asm/dec/prom.h> | ||
24 | |||
25 | #include "dectypes.h" | ||
26 | |||
27 | extern unsigned long mips_machgroup; | ||
28 | extern unsigned long mips_machtype; | ||
29 | |||
30 | static const char *dec_system_strings[] = { | ||
31 | [MACH_DSUNKNOWN] "unknown DECstation", | ||
32 | [MACH_DS23100] "DECstation 2100/3100", | ||
33 | [MACH_DS5100] "DECsystem 5100", | ||
34 | [MACH_DS5000_200] "DECstation 5000/200", | ||
35 | [MACH_DS5000_1XX] "DECstation 5000/1xx", | ||
36 | [MACH_DS5000_XX] "Personal DECstation 5000/xx", | ||
37 | [MACH_DS5000_2X0] "DECstation 5000/2x0", | ||
38 | [MACH_DS5400] "DECsystem 5400", | ||
39 | [MACH_DS5500] "DECsystem 5500", | ||
40 | [MACH_DS5800] "DECsystem 5800", | ||
41 | [MACH_DS5900] "DECsystem 5900", | ||
42 | }; | ||
43 | |||
44 | const char *get_system_type(void) | ||
45 | { | ||
46 | #define STR_BUF_LEN 64 | ||
47 | static char system[STR_BUF_LEN]; | ||
48 | static int called = 0; | ||
49 | |||
50 | if (called == 0) { | ||
51 | called = 1; | ||
52 | snprintf(system, STR_BUF_LEN, "Digital %s", | ||
53 | dec_system_strings[mips_machtype]); | ||
54 | } | ||
55 | |||
56 | return system; | ||
57 | } | ||
58 | |||
59 | |||
60 | /* | ||
61 | * Setup essential system-specific memory addresses. We need them | ||
62 | * early. Semantically the functions belong to prom/init.c, but they | ||
63 | * are compact enough we want them inlined. --macro | ||
64 | */ | ||
65 | volatile u8 *dec_rtc_base; | ||
66 | |||
67 | EXPORT_SYMBOL(dec_rtc_base); | ||
68 | |||
69 | static inline void prom_init_kn01(void) | ||
70 | { | ||
71 | dec_rtc_base = (void *)KN01_RTC_BASE; | ||
72 | dec_kn_slot_size = KN01_SLOT_SIZE; | ||
73 | } | ||
74 | |||
75 | static inline void prom_init_kn230(void) | ||
76 | { | ||
77 | dec_rtc_base = (void *)KN01_RTC_BASE; | ||
78 | dec_kn_slot_size = KN01_SLOT_SIZE; | ||
79 | } | ||
80 | |||
81 | static inline void prom_init_kn02(void) | ||
82 | { | ||
83 | dec_rtc_base = (void *)KN02_RTC_BASE; | ||
84 | dec_kn_slot_size = KN02_SLOT_SIZE; | ||
85 | } | ||
86 | |||
87 | static inline void prom_init_kn02xa(void) | ||
88 | { | ||
89 | ioasic_base = (void *)KN02XA_IOASIC_BASE; | ||
90 | dec_rtc_base = (void *)KN02XA_RTC_BASE; | ||
91 | dec_kn_slot_size = IOASIC_SLOT_SIZE; | ||
92 | } | ||
93 | |||
94 | static inline void prom_init_kn03(void) | ||
95 | { | ||
96 | ioasic_base = (void *)KN03_IOASIC_BASE; | ||
97 | dec_rtc_base = (void *)KN03_RTC_BASE; | ||
98 | dec_kn_slot_size = IOASIC_SLOT_SIZE; | ||
99 | } | ||
100 | |||
101 | |||
102 | void __init prom_identify_arch(u32 magic) | ||
103 | { | ||
104 | unsigned char dec_cpunum, dec_firmrev, dec_etc, dec_systype; | ||
105 | u32 dec_sysid; | ||
106 | |||
107 | if (!prom_is_rex(magic)) { | ||
108 | dec_sysid = simple_strtoul(prom_getenv("systype"), | ||
109 | (char **)0, 0); | ||
110 | } else { | ||
111 | dec_sysid = rex_getsysid(); | ||
112 | if (dec_sysid == 0) { | ||
113 | printk("Zero sysid returned from PROM! " | ||
114 | "Assuming a PMAX-like machine.\n"); | ||
115 | dec_sysid = 1; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | dec_cpunum = (dec_sysid & 0xff000000) >> 24; | ||
120 | dec_systype = (dec_sysid & 0xff0000) >> 16; | ||
121 | dec_firmrev = (dec_sysid & 0xff00) >> 8; | ||
122 | dec_etc = dec_sysid & 0xff; | ||
123 | |||
124 | /* We're obviously one of the DEC machines */ | ||
125 | mips_machgroup = MACH_GROUP_DEC; | ||
126 | |||
127 | /* | ||
128 | * FIXME: This may not be an exhaustive list of DECStations/Servers! | ||
129 | * Put all model-specific initialisation calls here. | ||
130 | */ | ||
131 | switch (dec_systype) { | ||
132 | case DS2100_3100: | ||
133 | mips_machtype = MACH_DS23100; | ||
134 | prom_init_kn01(); | ||
135 | break; | ||
136 | case DS5100: /* DS5100 MIPSMATE */ | ||
137 | mips_machtype = MACH_DS5100; | ||
138 | prom_init_kn230(); | ||
139 | break; | ||
140 | case DS5000_200: /* DS5000 3max */ | ||
141 | mips_machtype = MACH_DS5000_200; | ||
142 | prom_init_kn02(); | ||
143 | break; | ||
144 | case DS5000_1XX: /* DS5000/100 3min */ | ||
145 | mips_machtype = MACH_DS5000_1XX; | ||
146 | prom_init_kn02xa(); | ||
147 | break; | ||
148 | case DS5000_2X0: /* DS5000/240 3max+ or DS5900 bigmax */ | ||
149 | mips_machtype = MACH_DS5000_2X0; | ||
150 | prom_init_kn03(); | ||
151 | if (!(ioasic_read(IO_REG_SIR) & KN03_IO_INR_3MAXP)) | ||
152 | mips_machtype = MACH_DS5900; | ||
153 | break; | ||
154 | case DS5000_XX: /* Personal DS5000/xx maxine */ | ||
155 | mips_machtype = MACH_DS5000_XX; | ||
156 | prom_init_kn02xa(); | ||
157 | break; | ||
158 | case DS5800: /* DS5800 Isis */ | ||
159 | mips_machtype = MACH_DS5800; | ||
160 | break; | ||
161 | case DS5400: /* DS5400 MIPSfair */ | ||
162 | mips_machtype = MACH_DS5400; | ||
163 | break; | ||
164 | case DS5500: /* DS5500 MIPSfair-2 */ | ||
165 | mips_machtype = MACH_DS5500; | ||
166 | break; | ||
167 | default: | ||
168 | mips_machtype = MACH_DSUNKNOWN; | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | if (mips_machtype == MACH_DSUNKNOWN) | ||
173 | printk("This is an %s, id is %x\n", | ||
174 | dec_system_strings[mips_machtype], dec_systype); | ||
175 | else | ||
176 | printk("This is a %s\n", dec_system_strings[mips_machtype]); | ||
177 | } | ||
diff --git a/arch/mips/dec/prom/init.c b/arch/mips/dec/prom/init.c new file mode 100644 index 000000000000..60f74256e689 --- /dev/null +++ b/arch/mips/dec/prom/init.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * init.c: PROM library initialisation code. | ||
3 | * | ||
4 | * Copyright (C) 1998 Harald Koerfgen | ||
5 | * Copyright (C) 2002, 2004 Maciej W. Rozycki | ||
6 | */ | ||
7 | #include <linux/config.h> | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/smp.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/types.h> | ||
12 | |||
13 | #include <asm/bootinfo.h> | ||
14 | #include <asm/cpu.h> | ||
15 | #include <asm/processor.h> | ||
16 | |||
17 | #include <asm/dec/prom.h> | ||
18 | |||
19 | |||
20 | int (*__rex_bootinit)(void); | ||
21 | int (*__rex_bootread)(void); | ||
22 | int (*__rex_getbitmap)(memmap *); | ||
23 | unsigned long *(*__rex_slot_address)(int); | ||
24 | void *(*__rex_gettcinfo)(void); | ||
25 | int (*__rex_getsysid)(void); | ||
26 | void (*__rex_clear_cache)(void); | ||
27 | |||
28 | int (*__prom_getchar)(void); | ||
29 | char *(*__prom_getenv)(char *); | ||
30 | int (*__prom_printf)(char *, ...); | ||
31 | |||
32 | int (*__pmax_open)(char*, int); | ||
33 | int (*__pmax_lseek)(int, long, int); | ||
34 | int (*__pmax_read)(int, void *, int); | ||
35 | int (*__pmax_close)(int); | ||
36 | |||
37 | |||
38 | /* | ||
39 | * Detect which PROM the DECSTATION has, and set the callback vectors | ||
40 | * appropriately. | ||
41 | */ | ||
42 | void __init which_prom(s32 magic, s32 *prom_vec) | ||
43 | { | ||
44 | /* | ||
45 | * No sign of the REX PROM's magic number means we assume a non-REX | ||
46 | * machine (i.e. we're on a DS2100/3100, DS5100 or DS5000/2xx) | ||
47 | */ | ||
48 | if (prom_is_rex(magic)) { | ||
49 | /* | ||
50 | * Set up prom abstraction structure with REX entry points. | ||
51 | */ | ||
52 | __rex_bootinit = | ||
53 | (void *)(long)*(prom_vec + REX_PROM_BOOTINIT); | ||
54 | __rex_bootread = | ||
55 | (void *)(long)*(prom_vec + REX_PROM_BOOTREAD); | ||
56 | __rex_getbitmap = | ||
57 | (void *)(long)*(prom_vec + REX_PROM_GETBITMAP); | ||
58 | __prom_getchar = | ||
59 | (void *)(long)*(prom_vec + REX_PROM_GETCHAR); | ||
60 | __prom_getenv = | ||
61 | (void *)(long)*(prom_vec + REX_PROM_GETENV); | ||
62 | __rex_getsysid = | ||
63 | (void *)(long)*(prom_vec + REX_PROM_GETSYSID); | ||
64 | __rex_gettcinfo = | ||
65 | (void *)(long)*(prom_vec + REX_PROM_GETTCINFO); | ||
66 | __prom_printf = | ||
67 | (void *)(long)*(prom_vec + REX_PROM_PRINTF); | ||
68 | __rex_slot_address = | ||
69 | (void *)(long)*(prom_vec + REX_PROM_SLOTADDR); | ||
70 | __rex_clear_cache = | ||
71 | (void *)(long)*(prom_vec + REX_PROM_CLEARCACHE); | ||
72 | } else { | ||
73 | /* | ||
74 | * Set up prom abstraction structure with non-REX entry points. | ||
75 | */ | ||
76 | __prom_getchar = (void *)PMAX_PROM_GETCHAR; | ||
77 | __prom_getenv = (void *)PMAX_PROM_GETENV; | ||
78 | __prom_printf = (void *)PMAX_PROM_PRINTF; | ||
79 | __pmax_open = (void *)PMAX_PROM_OPEN; | ||
80 | __pmax_lseek = (void *)PMAX_PROM_LSEEK; | ||
81 | __pmax_read = (void *)PMAX_PROM_READ; | ||
82 | __pmax_close = (void *)PMAX_PROM_CLOSE; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | void __init prom_init(void) | ||
87 | { | ||
88 | extern void dec_machine_halt(void); | ||
89 | static char cpu_msg[] __initdata = | ||
90 | "Sorry, this kernel is compiled for a wrong CPU type!\n"; | ||
91 | static char r3k_msg[] __initdata = | ||
92 | "Please recompile with \"CONFIG_CPU_R3000 = y\".\n"; | ||
93 | static char r4k_msg[] __initdata = | ||
94 | "Please recompile with \"CONFIG_CPU_R4x00 = y\".\n"; | ||
95 | s32 argc = fw_arg0; | ||
96 | s32 argv = fw_arg1; | ||
97 | u32 magic = fw_arg2; | ||
98 | s32 prom_vec = fw_arg3; | ||
99 | |||
100 | /* | ||
101 | * Determine which PROM we have | ||
102 | * (and therefore which machine we're on!) | ||
103 | */ | ||
104 | which_prom(magic, prom_vec); | ||
105 | |||
106 | if (prom_is_rex(magic)) | ||
107 | rex_clear_cache(); | ||
108 | |||
109 | /* Register the early console. */ | ||
110 | register_prom_console(); | ||
111 | |||
112 | /* Were we compiled with the right CPU option? */ | ||
113 | #if defined(CONFIG_CPU_R3000) | ||
114 | if ((current_cpu_data.cputype == CPU_R4000SC) || | ||
115 | (current_cpu_data.cputype == CPU_R4400SC)) { | ||
116 | printk(cpu_msg); | ||
117 | printk(r4k_msg); | ||
118 | dec_machine_halt(); | ||
119 | } | ||
120 | #endif | ||
121 | |||
122 | #if defined(CONFIG_CPU_R4X00) | ||
123 | if ((current_cpu_data.cputype == CPU_R3000) || | ||
124 | (current_cpu_data.cputype == CPU_R3000A)) { | ||
125 | printk(cpu_msg); | ||
126 | printk(r3k_msg); | ||
127 | dec_machine_halt(); | ||
128 | } | ||
129 | #endif | ||
130 | |||
131 | prom_meminit(magic); | ||
132 | prom_identify_arch(magic); | ||
133 | prom_init_cmdline(argc, argv, magic); | ||
134 | } | ||
diff --git a/arch/mips/dec/prom/locore.S b/arch/mips/dec/prom/locore.S new file mode 100644 index 000000000000..d9acdcefee81 --- /dev/null +++ b/arch/mips/dec/prom/locore.S | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * locore.S | ||
3 | */ | ||
4 | #include <asm/asm.h> | ||
5 | #include <asm/regdef.h> | ||
6 | #include <asm/mipsregs.h> | ||
7 | |||
8 | .text | ||
9 | |||
10 | /* | ||
11 | * Simple general exception handling routine. This one is used for the | ||
12 | * Memory sizing routine for pmax machines. HK | ||
13 | */ | ||
14 | |||
15 | NESTED(genexcept_early, 0, sp) | ||
16 | .set noat | ||
17 | .set noreorder | ||
18 | |||
19 | mfc0 k0, CP0_STATUS | ||
20 | la k1, mem_err | ||
21 | |||
22 | sw k0, 0(k1) | ||
23 | |||
24 | mfc0 k0, CP0_EPC | ||
25 | nop | ||
26 | addiu k0, 4 # skip the causing instruction | ||
27 | jr k0 | ||
28 | rfe | ||
29 | END(genexcept_early) | ||
30 | |||
diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c new file mode 100644 index 000000000000..e4f6f26425ea --- /dev/null +++ b/arch/mips/dec/prom/memory.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * memory.c: memory initialisation code. | ||
3 | * | ||
4 | * Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine | ||
5 | * Copyright (C) 2000, 2002 Maciej W. Rozycki | ||
6 | */ | ||
7 | #include <linux/config.h> | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/mm.h> | ||
11 | #include <linux/bootmem.h> | ||
12 | #include <linux/types.h> | ||
13 | |||
14 | #include <asm/addrspace.h> | ||
15 | #include <asm/bootinfo.h> | ||
16 | #include <asm/dec/machtype.h> | ||
17 | #include <asm/dec/prom.h> | ||
18 | #include <asm/page.h> | ||
19 | #include <asm/sections.h> | ||
20 | |||
21 | |||
22 | volatile unsigned long mem_err = 0; /* So we know an error occurred */ | ||
23 | |||
24 | /* | ||
25 | * Probe memory in 4MB chunks, waiting for an error to tell us we've fallen | ||
26 | * off the end of real memory. Only suitable for the 2100/3100's (PMAX). | ||
27 | */ | ||
28 | |||
29 | #define CHUNK_SIZE 0x400000 | ||
30 | |||
31 | static inline void pmax_setup_memory_region(void) | ||
32 | { | ||
33 | volatile unsigned char *memory_page, dummy; | ||
34 | char old_handler[0x80]; | ||
35 | extern char genexcept_early; | ||
36 | |||
37 | /* Install exception handler */ | ||
38 | memcpy(&old_handler, (void *)(KSEG0 + 0x80), 0x80); | ||
39 | memcpy((void *)(KSEG0 + 0x80), &genexcept_early, 0x80); | ||
40 | |||
41 | /* read unmapped and uncached (KSEG1) | ||
42 | * DECstations have at least 4MB RAM | ||
43 | * Assume less than 480MB of RAM, as this is max for 5000/2xx | ||
44 | * FIXME this should be replaced by the first free page! | ||
45 | */ | ||
46 | for (memory_page = (unsigned char *) KSEG1 + CHUNK_SIZE; | ||
47 | (mem_err== 0) && (memory_page < ((unsigned char *) KSEG1+0x1E000000)); | ||
48 | memory_page += CHUNK_SIZE) { | ||
49 | dummy = *memory_page; | ||
50 | } | ||
51 | memcpy((void *)(KSEG0 + 0x80), &old_handler, 0x80); | ||
52 | |||
53 | add_memory_region(0, (unsigned long)memory_page - KSEG1 - CHUNK_SIZE, | ||
54 | BOOT_MEM_RAM); | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * Use the REX prom calls to get hold of the memory bitmap, and thence | ||
59 | * determine memory size. | ||
60 | */ | ||
61 | static inline void rex_setup_memory_region(void) | ||
62 | { | ||
63 | int i, bitmap_size; | ||
64 | unsigned long mem_start = 0, mem_size = 0; | ||
65 | memmap *bm; | ||
66 | |||
67 | /* some free 64k */ | ||
68 | bm = (memmap *)KSEG0ADDR(0x28000); | ||
69 | |||
70 | bitmap_size = rex_getbitmap(bm); | ||
71 | |||
72 | for (i = 0; i < bitmap_size; i++) { | ||
73 | /* FIXME: very simplistically only add full sets of pages */ | ||
74 | if (bm->bitmap[i] == 0xff) | ||
75 | mem_size += (8 * bm->pagesize); | ||
76 | else if (!mem_size) | ||
77 | mem_start += (8 * bm->pagesize); | ||
78 | else { | ||
79 | add_memory_region(mem_start, mem_size, BOOT_MEM_RAM); | ||
80 | mem_start += mem_size + (8 * bm->pagesize); | ||
81 | mem_size = 0; | ||
82 | } | ||
83 | } | ||
84 | if (mem_size) | ||
85 | add_memory_region(mem_start, mem_size, BOOT_MEM_RAM); | ||
86 | } | ||
87 | |||
88 | void __init prom_meminit(u32 magic) | ||
89 | { | ||
90 | if (!prom_is_rex(magic)) | ||
91 | pmax_setup_memory_region(); | ||
92 | else | ||
93 | rex_setup_memory_region(); | ||
94 | } | ||
95 | |||
96 | unsigned long __init prom_free_prom_memory(void) | ||
97 | { | ||
98 | unsigned long addr, end; | ||
99 | |||
100 | /* | ||
101 | * Free everything below the kernel itself but leave | ||
102 | * the first page reserved for the exception handlers. | ||
103 | */ | ||
104 | |||
105 | #if defined(CONFIG_DECLANCE) || defined(CONFIG_DECLANCE_MODULE) | ||
106 | /* | ||
107 | * Leave 128 KB reserved for Lance memory for | ||
108 | * IOASIC DECstations. | ||
109 | * | ||
110 | * XXX: save this address for use in dec_lance.c? | ||
111 | */ | ||
112 | if (IOASIC) | ||
113 | end = __pa(&_text) - 0x00020000; | ||
114 | else | ||
115 | #endif | ||
116 | end = __pa(&_text); | ||
117 | |||
118 | addr = PAGE_SIZE; | ||
119 | while (addr < end) { | ||
120 | ClearPageReserved(virt_to_page(__va(addr))); | ||
121 | set_page_count(virt_to_page(__va(addr)), 1); | ||
122 | free_page((unsigned long)__va(addr)); | ||
123 | addr += PAGE_SIZE; | ||
124 | } | ||
125 | |||
126 | printk("Freeing unused PROM memory: %ldk freed\n", | ||
127 | (end - PAGE_SIZE) >> 10); | ||
128 | |||
129 | return end - PAGE_SIZE; | ||
130 | } | ||