diff options
Diffstat (limited to 'arch/mips/momentum/ocelot_c/prom.c')
-rw-r--r-- | arch/mips/momentum/ocelot_c/prom.c | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/arch/mips/momentum/ocelot_c/prom.c b/arch/mips/momentum/ocelot_c/prom.c new file mode 100644 index 000000000000..49ac302d8901 --- /dev/null +++ b/arch/mips/momentum/ocelot_c/prom.c | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | * Copyright 2002 Momentum Computer Inc. | ||
3 | * Author: Matthew Dharm <mdharm@momenco.com> | ||
4 | * | ||
5 | * Louis Hamilton, Red Hat, Inc. | ||
6 | * hamilton@redhat.com [MIPS64 modifications] | ||
7 | * | ||
8 | * Based on Ocelot Linux port, which is | ||
9 | * Copyright 2001 MontaVista Software Inc. | ||
10 | * Author: jsun@mvista.com or jsun@junsun.net | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | #include <linux/config.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/mm.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/bootmem.h> | ||
22 | |||
23 | #include <asm/addrspace.h> | ||
24 | #include <asm/bootinfo.h> | ||
25 | #include <asm/mv64340.h> | ||
26 | #include <asm/pmon.h> | ||
27 | |||
28 | #include "ocelot_c_fpga.h" | ||
29 | |||
30 | struct callvectors* debug_vectors; | ||
31 | |||
32 | extern unsigned long marvell_base; | ||
33 | extern unsigned long cpu_clock; | ||
34 | |||
35 | #ifdef CONFIG_MV643XX_ETH | ||
36 | extern unsigned char prom_mac_addr_base[6]; | ||
37 | #endif | ||
38 | |||
39 | const char *get_system_type(void) | ||
40 | { | ||
41 | #ifdef CONFIG_CPU_SR71000 | ||
42 | return "Momentum Ocelot-CS"; | ||
43 | #else | ||
44 | return "Momentum Ocelot-C"; | ||
45 | #endif | ||
46 | } | ||
47 | |||
48 | #ifdef CONFIG_MV643XX_ETH | ||
49 | static void burn_clocks(void) | ||
50 | { | ||
51 | int i; | ||
52 | |||
53 | /* this loop should burn at least 1us -- this should be plenty */ | ||
54 | for (i = 0; i < 0x10000; i++) | ||
55 | ; | ||
56 | } | ||
57 | |||
58 | static u8 exchange_bit(u8 val, u8 cs) | ||
59 | { | ||
60 | /* place the data */ | ||
61 | OCELOT_FPGA_WRITE((val << 2) | cs, EEPROM_MODE); | ||
62 | burn_clocks(); | ||
63 | |||
64 | /* turn the clock on */ | ||
65 | OCELOT_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE); | ||
66 | burn_clocks(); | ||
67 | |||
68 | /* turn the clock off and read-strobe */ | ||
69 | OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE); | ||
70 | |||
71 | /* return the data */ | ||
72 | return ((OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1); | ||
73 | } | ||
74 | |||
75 | void get_mac(char dest[6]) | ||
76 | { | ||
77 | u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | ||
78 | int i,j; | ||
79 | |||
80 | for (i = 0; i < 12; i++) | ||
81 | exchange_bit(read_opcode[i], 1); | ||
82 | |||
83 | for (j = 0; j < 6; j++) { | ||
84 | dest[j] = 0; | ||
85 | for (i = 0; i < 8; i++) { | ||
86 | dest[j] <<= 1; | ||
87 | dest[j] |= exchange_bit(0, 1); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | /* turn off CS */ | ||
92 | exchange_bit(0,0); | ||
93 | } | ||
94 | #endif | ||
95 | |||
96 | |||
97 | #ifdef CONFIG_MIPS64 | ||
98 | |||
99 | unsigned long signext(unsigned long addr) | ||
100 | { | ||
101 | addr &= 0xffffffff; | ||
102 | return (unsigned long)((int)addr); | ||
103 | } | ||
104 | |||
105 | void *get_arg(unsigned long args, int arc) | ||
106 | { | ||
107 | unsigned long ul; | ||
108 | unsigned char *puc, uc; | ||
109 | |||
110 | args += (arc * 4); | ||
111 | ul = (unsigned long)signext(args); | ||
112 | puc = (unsigned char *)ul; | ||
113 | if (puc == 0) | ||
114 | return (void *)0; | ||
115 | |||
116 | #ifdef CONFIG_CPU_LITTLE_ENDIAN | ||
117 | uc = *puc++; | ||
118 | ul = (unsigned long)uc; | ||
119 | uc = *puc++; | ||
120 | ul |= (((unsigned long)uc) << 8); | ||
121 | uc = *puc++; | ||
122 | ul |= (((unsigned long)uc) << 16); | ||
123 | uc = *puc++; | ||
124 | ul |= (((unsigned long)uc) << 24); | ||
125 | #else /* CONFIG_CPU_LITTLE_ENDIAN */ | ||
126 | uc = *puc++; | ||
127 | ul = ((unsigned long)uc) << 24; | ||
128 | uc = *puc++; | ||
129 | ul |= (((unsigned long)uc) << 16); | ||
130 | uc = *puc++; | ||
131 | ul |= (((unsigned long)uc) << 8); | ||
132 | uc = *puc++; | ||
133 | ul |= ((unsigned long)uc); | ||
134 | #endif /* CONFIG_CPU_LITTLE_ENDIAN */ | ||
135 | ul = signext(ul); | ||
136 | return (void *)ul; | ||
137 | } | ||
138 | |||
139 | char *arg64(unsigned long addrin, int arg_index) | ||
140 | { | ||
141 | unsigned long args; | ||
142 | char *p; | ||
143 | args = signext(addrin); | ||
144 | p = (char *)get_arg(args, arg_index); | ||
145 | return p; | ||
146 | } | ||
147 | #endif /* CONFIG_MIPS64 */ | ||
148 | |||
149 | |||
150 | void __init prom_init(void) | ||
151 | { | ||
152 | int argc = fw_arg0; | ||
153 | char **arg = (char **) fw_arg1; | ||
154 | char **env = (char **) fw_arg2; | ||
155 | struct callvectors *cv = (struct callvectors *) fw_arg3; | ||
156 | int i; | ||
157 | |||
158 | #ifdef CONFIG_MIPS64 | ||
159 | char *ptr; | ||
160 | |||
161 | printk("prom_init - MIPS64\n"); | ||
162 | /* save the PROM vectors for debugging use */ | ||
163 | debug_vectors = (struct callvectors *)signext((unsigned long)cv); | ||
164 | |||
165 | /* arg[0] is "g", the rest is boot parameters */ | ||
166 | arcs_cmdline[0] = '\0'; | ||
167 | |||
168 | for (i = 1; i < argc; i++) { | ||
169 | ptr = (char *)arg64((unsigned long)arg, i); | ||
170 | if ((strlen(arcs_cmdline) + strlen(ptr) + 1) >= | ||
171 | sizeof(arcs_cmdline)) | ||
172 | break; | ||
173 | strcat(arcs_cmdline, ptr); | ||
174 | strcat(arcs_cmdline, " "); | ||
175 | } | ||
176 | i = 0; | ||
177 | while (1) { | ||
178 | ptr = (char *)arg64((unsigned long)env, i); | ||
179 | if (! ptr) | ||
180 | break; | ||
181 | |||
182 | if (strncmp("gtbase", ptr, strlen("gtbase")) == 0) { | ||
183 | marvell_base = simple_strtol(ptr + strlen("gtbase="), | ||
184 | NULL, 16); | ||
185 | |||
186 | if ((marvell_base & 0xffffffff00000000) == 0) | ||
187 | marvell_base |= 0xffffffff00000000; | ||
188 | |||
189 | printk("marvell_base set to 0x%016lx\n", marvell_base); | ||
190 | } | ||
191 | if (strncmp("cpuclock", ptr, strlen("cpuclock")) == 0) { | ||
192 | cpu_clock = simple_strtol(ptr + strlen("cpuclock="), | ||
193 | NULL, 10); | ||
194 | printk("cpu_clock set to %d\n", cpu_clock); | ||
195 | } | ||
196 | i++; | ||
197 | } | ||
198 | printk("arcs_cmdline: %s\n", arcs_cmdline); | ||
199 | |||
200 | #else /* CONFIG_MIPS64 */ | ||
201 | /* save the PROM vectors for debugging use */ | ||
202 | debug_vectors = cv; | ||
203 | |||
204 | /* arg[0] is "g", the rest is boot parameters */ | ||
205 | arcs_cmdline[0] = '\0'; | ||
206 | for (i = 1; i < argc; i++) { | ||
207 | if (strlen(arcs_cmdline) + strlen(arg[i] + 1) | ||
208 | >= sizeof(arcs_cmdline)) | ||
209 | break; | ||
210 | strcat(arcs_cmdline, arg[i]); | ||
211 | strcat(arcs_cmdline, " "); | ||
212 | } | ||
213 | |||
214 | while (*env) { | ||
215 | if (strncmp("gtbase", *env, strlen("gtbase")) == 0) { | ||
216 | marvell_base = simple_strtol(*env + strlen("gtbase="), | ||
217 | NULL, 16); | ||
218 | } | ||
219 | if (strncmp("cpuclock", *env, strlen("cpuclock")) == 0) { | ||
220 | cpu_clock = simple_strtol(*env + strlen("cpuclock="), | ||
221 | NULL, 10); | ||
222 | } | ||
223 | env++; | ||
224 | } | ||
225 | #endif /* CONFIG_MIPS64 */ | ||
226 | |||
227 | mips_machgroup = MACH_GROUP_MOMENCO; | ||
228 | mips_machtype = MACH_MOMENCO_OCELOT_C; | ||
229 | |||
230 | #ifdef CONFIG_MV643XX_ETH | ||
231 | /* get the base MAC address for on-board ethernet ports */ | ||
232 | get_mac(prom_mac_addr_base); | ||
233 | #endif | ||
234 | |||
235 | #ifndef CONFIG_MIPS64 | ||
236 | debug_vectors->printf("Booting Linux kernel...\n"); | ||
237 | #endif | ||
238 | } | ||
239 | |||
240 | unsigned long __init prom_free_prom_memory(void) | ||
241 | { | ||
242 | return 0; | ||
243 | } | ||