diff options
author | Tejun Heo <tj@kernel.org> | 2009-08-14 01:41:02 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2009-08-14 01:45:31 -0400 |
commit | 384be2b18a5f9475eab9ca2bdfa95cc1a04ef59c (patch) | |
tree | 04c93f391a1b65c8bf8d7ba8643c07d26c26590a /arch/mips/ar7/prom.c | |
parent | a76761b621bcd8336065c4fe3a74f046858bc34c (diff) | |
parent | 142d44b0dd6741a64a7bdbe029110e7c1dcf1d23 (diff) |
Merge branch 'percpu-for-linus' into percpu-for-next
Conflicts:
arch/sparc/kernel/smp_64.c
arch/x86/kernel/cpu/perf_counter.c
arch/x86/kernel/setup_percpu.c
drivers/cpufreq/cpufreq_ondemand.c
mm/percpu.c
Conflicts in core and arch percpu codes are mostly from commit
ed78e1e078dd44249f88b1dd8c76dafb39567161 which substituted many
num_possible_cpus() with nr_cpu_ids. As for-next branch has moved all
the first chunk allocators into mm/percpu.c, the changes are moved
from arch code to mm/percpu.c.
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'arch/mips/ar7/prom.c')
-rw-r--r-- | arch/mips/ar7/prom.c | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/arch/mips/ar7/prom.c b/arch/mips/ar7/prom.c new file mode 100644 index 000000000000..5ad6f1db6567 --- /dev/null +++ b/arch/mips/ar7/prom.c | |||
@@ -0,0 +1,297 @@ | |||
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/init.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/serial_reg.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <asm/bootinfo.h> | ||
28 | |||
29 | #include <asm/mach-ar7/ar7.h> | ||
30 | #include <asm/mach-ar7/prom.h> | ||
31 | |||
32 | #define MAX_ENTRY 80 | ||
33 | |||
34 | struct env_var { | ||
35 | char *name; | ||
36 | char *value; | ||
37 | }; | ||
38 | |||
39 | static struct env_var adam2_env[MAX_ENTRY]; | ||
40 | |||
41 | char *prom_getenv(const char *name) | ||
42 | { | ||
43 | int i; | ||
44 | for (i = 0; (i < MAX_ENTRY) && adam2_env[i].name; i++) | ||
45 | if (!strcmp(name, adam2_env[i].name)) | ||
46 | return adam2_env[i].value; | ||
47 | |||
48 | return NULL; | ||
49 | } | ||
50 | EXPORT_SYMBOL(prom_getenv); | ||
51 | |||
52 | char * __init prom_getcmdline(void) | ||
53 | { | ||
54 | return &(arcs_cmdline[0]); | ||
55 | } | ||
56 | |||
57 | static void __init ar7_init_cmdline(int argc, char *argv[]) | ||
58 | { | ||
59 | char *cp; | ||
60 | int actr; | ||
61 | |||
62 | actr = 1; /* Always ignore argv[0] */ | ||
63 | |||
64 | cp = &(arcs_cmdline[0]); | ||
65 | while (actr < argc) { | ||
66 | strcpy(cp, argv[actr]); | ||
67 | cp += strlen(argv[actr]); | ||
68 | *cp++ = ' '; | ||
69 | actr++; | ||
70 | } | ||
71 | if (cp != &(arcs_cmdline[0])) { | ||
72 | /* get rid of trailing space */ | ||
73 | --cp; | ||
74 | *cp = '\0'; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | struct psbl_rec { | ||
79 | u32 psbl_size; | ||
80 | u32 env_base; | ||
81 | u32 env_size; | ||
82 | u32 ffs_base; | ||
83 | u32 ffs_size; | ||
84 | }; | ||
85 | |||
86 | static __initdata char psp_env_version[] = "TIENV0.8"; | ||
87 | |||
88 | struct psp_env_chunk { | ||
89 | u8 num; | ||
90 | u8 ctrl; | ||
91 | u16 csum; | ||
92 | u8 len; | ||
93 | char data[11]; | ||
94 | } __attribute__ ((packed)); | ||
95 | |||
96 | struct psp_var_map_entry { | ||
97 | u8 num; | ||
98 | char *value; | ||
99 | }; | ||
100 | |||
101 | static struct psp_var_map_entry psp_var_map[] = { | ||
102 | { 1, "cpufrequency" }, | ||
103 | { 2, "memsize" }, | ||
104 | { 3, "flashsize" }, | ||
105 | { 4, "modetty0" }, | ||
106 | { 5, "modetty1" }, | ||
107 | { 8, "maca" }, | ||
108 | { 9, "macb" }, | ||
109 | { 28, "sysfrequency" }, | ||
110 | { 38, "mipsfrequency" }, | ||
111 | }; | ||
112 | |||
113 | /* | ||
114 | |||
115 | Well-known variable (num is looked up in table above for matching variable name) | ||
116 | Example: cpufrequency=211968000 | ||
117 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
118 | | 01 |CTRL|CHECKSUM | 01 | _2 | _1 | _1 | _9 | _6 | _8 | _0 | _0 | _0 | \0 | FF | ||
119 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
120 | |||
121 | Name=Value pair in a single chunk | ||
122 | Example: NAME=VALUE | ||
123 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
124 | | 00 |CTRL|CHECKSUM | 01 | _N | _A | _M | _E | _0 | _V | _A | _L | _U | _E | \0 | ||
125 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
126 | |||
127 | Name=Value pair in 2 chunks (len is the number of chunks) | ||
128 | Example: bootloaderVersion=1.3.7.15 | ||
129 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
130 | | 00 |CTRL|CHECKSUM | 02 | _b | _o | _o | _t | _l | _o | _a | _d | _e | _r | _V | ||
131 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
132 | | _e | _r | _s | _i | _o | _n | \0 | _1 | _. | _3 | _. | _7 | _. | _1 | _5 | \0 | ||
133 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
134 | |||
135 | Data is padded with 0xFF | ||
136 | |||
137 | */ | ||
138 | |||
139 | #define PSP_ENV_SIZE 4096 | ||
140 | |||
141 | static char psp_env_data[PSP_ENV_SIZE] = { 0, }; | ||
142 | |||
143 | static char * __init lookup_psp_var_map(u8 num) | ||
144 | { | ||
145 | int i; | ||
146 | |||
147 | for (i = 0; i < ARRAY_SIZE(psp_var_map); i++) | ||
148 | if (psp_var_map[i].num == num) | ||
149 | return psp_var_map[i].value; | ||
150 | |||
151 | return NULL; | ||
152 | } | ||
153 | |||
154 | static void __init add_adam2_var(char *name, char *value) | ||
155 | { | ||
156 | int i; | ||
157 | for (i = 0; i < MAX_ENTRY; i++) { | ||
158 | if (!adam2_env[i].name) { | ||
159 | adam2_env[i].name = name; | ||
160 | adam2_env[i].value = value; | ||
161 | return; | ||
162 | } else if (!strcmp(adam2_env[i].name, name)) { | ||
163 | adam2_env[i].value = value; | ||
164 | return; | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | |||
169 | static int __init parse_psp_env(void *psp_env_base) | ||
170 | { | ||
171 | int i, n; | ||
172 | char *name, *value; | ||
173 | struct psp_env_chunk *chunks = (struct psp_env_chunk *)psp_env_data; | ||
174 | |||
175 | memcpy_fromio(chunks, psp_env_base, PSP_ENV_SIZE); | ||
176 | |||
177 | i = 1; | ||
178 | n = PSP_ENV_SIZE / sizeof(struct psp_env_chunk); | ||
179 | while (i < n) { | ||
180 | if ((chunks[i].num == 0xff) || ((i + chunks[i].len) > n)) | ||
181 | break; | ||
182 | value = chunks[i].data; | ||
183 | if (chunks[i].num) { | ||
184 | name = lookup_psp_var_map(chunks[i].num); | ||
185 | } else { | ||
186 | name = value; | ||
187 | value += strlen(name) + 1; | ||
188 | } | ||
189 | if (name) | ||
190 | add_adam2_var(name, value); | ||
191 | i += chunks[i].len; | ||
192 | } | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static void __init ar7_init_env(struct env_var *env) | ||
197 | { | ||
198 | int i; | ||
199 | struct psbl_rec *psbl = (struct psbl_rec *)(KSEG1ADDR(0x14000300)); | ||
200 | void *psp_env = (void *)KSEG1ADDR(psbl->env_base); | ||
201 | |||
202 | if (strcmp(psp_env, psp_env_version) == 0) { | ||
203 | parse_psp_env(psp_env); | ||
204 | } else { | ||
205 | for (i = 0; i < MAX_ENTRY; i++, env++) | ||
206 | if (env->name) | ||
207 | add_adam2_var(env->name, env->value); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | static void __init console_config(void) | ||
212 | { | ||
213 | #ifdef CONFIG_SERIAL_8250_CONSOLE | ||
214 | char console_string[40]; | ||
215 | int baud = 0; | ||
216 | char parity = '\0', bits = '\0', flow = '\0'; | ||
217 | char *s, *p; | ||
218 | |||
219 | if (strstr(prom_getcmdline(), "console=")) | ||
220 | return; | ||
221 | |||
222 | #ifdef CONFIG_KGDB | ||
223 | if (!strstr(prom_getcmdline(), "nokgdb")) { | ||
224 | strcat(prom_getcmdline(), " console=kgdb"); | ||
225 | kgdb_enabled = 1; | ||
226 | return; | ||
227 | } | ||
228 | #endif | ||
229 | |||
230 | s = prom_getenv("modetty0"); | ||
231 | if (s) { | ||
232 | baud = simple_strtoul(s, &p, 10); | ||
233 | s = p; | ||
234 | if (*s == ',') | ||
235 | s++; | ||
236 | if (*s) | ||
237 | parity = *s++; | ||
238 | if (*s == ',') | ||
239 | s++; | ||
240 | if (*s) | ||
241 | bits = *s++; | ||
242 | if (*s == ',') | ||
243 | s++; | ||
244 | if (*s == 'h') | ||
245 | flow = 'r'; | ||
246 | } | ||
247 | |||
248 | if (baud == 0) | ||
249 | baud = 38400; | ||
250 | if (parity != 'n' && parity != 'o' && parity != 'e') | ||
251 | parity = 'n'; | ||
252 | if (bits != '7' && bits != '8') | ||
253 | bits = '8'; | ||
254 | |||
255 | if (flow == 'r') | ||
256 | sprintf(console_string, " console=ttyS0,%d%c%c%c", baud, | ||
257 | parity, bits, flow); | ||
258 | else | ||
259 | sprintf(console_string, " console=ttyS0,%d%c%c", baud, parity, | ||
260 | bits); | ||
261 | strcat(prom_getcmdline(), console_string); | ||
262 | #endif | ||
263 | } | ||
264 | |||
265 | void __init prom_init(void) | ||
266 | { | ||
267 | ar7_init_cmdline(fw_arg0, (char **)fw_arg1); | ||
268 | ar7_init_env((struct env_var *)fw_arg2); | ||
269 | console_config(); | ||
270 | } | ||
271 | |||
272 | #define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4))) | ||
273 | static inline unsigned int serial_in(int offset) | ||
274 | { | ||
275 | return readl((void *)PORT(offset)); | ||
276 | } | ||
277 | |||
278 | static inline void serial_out(int offset, int value) | ||
279 | { | ||
280 | writel(value, (void *)PORT(offset)); | ||
281 | } | ||
282 | |||
283 | char prom_getchar(void) | ||
284 | { | ||
285 | while (!(serial_in(UART_LSR) & UART_LSR_DR)) | ||
286 | ; | ||
287 | return serial_in(UART_RX); | ||
288 | } | ||
289 | |||
290 | int prom_putchar(char c) | ||
291 | { | ||
292 | while ((serial_in(UART_LSR) & UART_LSR_TEMT) == 0) | ||
293 | ; | ||
294 | serial_out(UART_TX, c); | ||
295 | return 1; | ||
296 | } | ||
297 | |||