]>
Commit | Line | Data |
---|---|---|
1e9a164e DH |
1 | /* prom.c - emulates a sparc v0 PROM for the linux kernel. |
2 | * | |
3 | * Copyright (C) 2003 Konrad Eisele <eiselekd@web.de> | |
4 | * Copyright (C) 2004 Stefan Holst <mail@s-holst.de> | |
5 | * Copyright (C) 2007 Daniel Hellstrom <daniel@gaisler.com> | |
6 | * | |
7 | * See file CREDITS for list of people who contributed to this | |
8 | * project. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU General Public License as | |
12 | * published by the Free Software Foundation; either version 2 of | |
13 | * the License, or (at your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
23 | * MA 02111-1307 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | #include <common.h> | |
28 | #include <asm/prom.h> | |
29 | #include <asm/machines.h> | |
30 | #include <asm/srmmu.h> | |
31 | #include <asm/processor.h> | |
32 | #include <asm/irq.h> | |
33 | #include <asm/leon.h> | |
34 | #include <ambapp.h> | |
35 | ||
36 | #include <config.h> | |
37 | /* | |
38 | #define PRINT_ROM_VEC | |
39 | */ | |
40 | extern struct linux_romvec *kernel_arg_promvec; | |
41 | extern ambapp_dev_apbuart *leon3_apbuart; | |
42 | ||
43 | #define PROM_PGT __attribute__ ((__section__ (".prom.pgt"))) | |
44 | #define PROM_TEXT __attribute__ ((__section__ (".prom.text"))) | |
45 | #define PROM_DATA __attribute__ ((__section__ (".prom.data"))) | |
46 | ||
47 | ambapp_dev_gptimer *gptimer; | |
48 | ||
49 | /* for __va */ | |
50 | extern int __prom_start; | |
51 | #define PAGE_OFFSET 0xf0000000 | |
6d0f6bcf | 52 | #define phys_base CONFIG_SYS_SDRAM_BASE |
1e9a164e DH |
53 | #define PROM_OFFS 8192 |
54 | #define PROM_SIZE_MASK (PROM_OFFS-1) | |
55 | #define __va(x) ( \ | |
56 | (void *)( ((unsigned long)(x))-PROM_OFFS+ \ | |
6d0f6bcf | 57 | (CONFIG_SYS_PROM_OFFSET-phys_base)+PAGE_OFFSET-TEXT_BASE ) \ |
1e9a164e | 58 | ) |
6d0f6bcf | 59 | #define __phy(x) ((void *)(((unsigned long)(x))-PROM_OFFS+CONFIG_SYS_PROM_OFFSET-TEXT_BASE)) |
1e9a164e DH |
60 | |
61 | struct property { | |
62 | char *name; | |
63 | char *value; | |
64 | int length; | |
65 | }; | |
66 | ||
67 | struct node { | |
68 | int level; | |
69 | struct property *properties; | |
70 | }; | |
71 | ||
72 | static void leon_reboot(char *bcommand); | |
73 | static void leon_halt(void); | |
74 | static int leon_nbputchar(int c); | |
75 | static int leon_nbgetchar(void); | |
76 | ||
77 | static int no_nextnode(int node); | |
78 | static int no_child(int node); | |
79 | static int no_proplen(int node, char *name); | |
80 | static int no_getprop(int node, char *name, char *value); | |
81 | static int no_setprop(int node, char *name, char *value, int len); | |
82 | static char *no_nextprop(int node, char *name); | |
83 | ||
84 | static struct property PROM_TEXT *find_property(int node, char *name); | |
85 | static int PROM_TEXT leon_strcmp(const char *s1, const char *s2); | |
86 | static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n); | |
87 | static void PROM_TEXT leon_reboot_physical(char *bcommand); | |
88 | ||
89 | void __inline__ leon_flush_cache_all(void) | |
90 | { | |
91 | __asm__ __volatile__(" flush "); | |
92 | __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"::"i"(ASI_DFLUSH):"memory"); | |
93 | } | |
94 | ||
95 | void __inline__ leon_flush_tlb_all(void) | |
96 | { | |
97 | leon_flush_cache_all(); | |
98 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t"::"r"(0x400), | |
99 | "i"(ASI_MMUFLUSH):"memory"); | |
100 | } | |
101 | ||
102 | typedef struct { | |
103 | unsigned int ctx_table[256]; | |
104 | unsigned int pgd_table[256]; | |
105 | } sparc_srmmu_setup; | |
106 | ||
107 | sparc_srmmu_setup srmmu_tables PROM_PGT = { | |
108 | {0}, | |
109 | {0x1e, | |
110 | 0x10001e, | |
111 | 0x20001e, | |
112 | 0x30001e, | |
113 | 0x40001e, | |
114 | 0x50001e, | |
115 | 0x60001e, | |
116 | 0x70001e, | |
117 | 0x80001e, | |
118 | 0x90001e, | |
119 | 0xa0001e, | |
120 | 0xb0001e, | |
121 | 0xc0001e, | |
122 | 0xd0001e, | |
123 | 0xe0001e, | |
124 | 0xf0001e, | |
125 | 0x100001e, | |
126 | 0x110001e, | |
127 | 0x120001e, | |
128 | 0x130001e, | |
129 | 0x140001e, | |
130 | 0x150001e, | |
131 | 0x160001e, | |
132 | 0x170001e, | |
133 | 0x180001e, | |
134 | 0x190001e, | |
135 | 0x1a0001e, | |
136 | 0x1b0001e, | |
137 | 0x1c0001e, | |
138 | 0x1d0001e, | |
139 | 0x1e0001e, | |
140 | 0x1f0001e, | |
141 | 0x200001e, | |
142 | 0x210001e, | |
143 | 0x220001e, | |
144 | 0x230001e, | |
145 | 0x240001e, | |
146 | 0x250001e, | |
147 | 0x260001e, | |
148 | 0x270001e, | |
149 | 0x280001e, | |
150 | 0x290001e, | |
151 | 0x2a0001e, | |
152 | 0x2b0001e, | |
153 | 0x2c0001e, | |
154 | 0x2d0001e, | |
155 | 0x2e0001e, | |
156 | 0x2f0001e, | |
157 | 0x300001e, | |
158 | 0x310001e, | |
159 | 0x320001e, | |
160 | 0x330001e, | |
161 | 0x340001e, | |
162 | 0x350001e, | |
163 | 0x360001e, | |
164 | 0x370001e, | |
165 | 0x380001e, | |
166 | 0x390001e, | |
167 | 0x3a0001e, | |
168 | 0x3b0001e, | |
169 | 0x3c0001e, | |
170 | 0x3d0001e, | |
171 | 0x3e0001e, | |
172 | 0x3f0001e, | |
173 | 0x400001e, | |
174 | 0x410001e, | |
175 | 0x420001e, | |
176 | 0x430001e, | |
177 | 0x440001e, | |
178 | 0x450001e, | |
179 | 0x460001e, | |
180 | 0x470001e, | |
181 | 0x480001e, | |
182 | 0x490001e, | |
183 | 0x4a0001e, | |
184 | 0x4b0001e, | |
185 | 0x4c0001e, | |
186 | 0x4d0001e, | |
187 | 0x4e0001e, | |
188 | 0x4f0001e, | |
189 | 0x500001e, | |
190 | 0x510001e, | |
191 | 0x520001e, | |
192 | 0x530001e, | |
193 | 0x540001e, | |
194 | 0x550001e, | |
195 | 0x560001e, | |
196 | 0x570001e, | |
197 | 0x580001e, | |
198 | 0x590001e, | |
199 | 0x5a0001e, | |
200 | 0x5b0001e, | |
201 | 0x5c0001e, | |
202 | 0x5d0001e, | |
203 | 0x5e0001e, | |
204 | 0x5f0001e, | |
205 | 0x600001e, | |
206 | 0x610001e, | |
207 | 0x620001e, | |
208 | 0x630001e, | |
209 | 0x640001e, | |
210 | 0x650001e, | |
211 | 0x660001e, | |
212 | 0x670001e, | |
213 | 0x680001e, | |
214 | 0x690001e, | |
215 | 0x6a0001e, | |
216 | 0x6b0001e, | |
217 | 0x6c0001e, | |
218 | 0x6d0001e, | |
219 | 0x6e0001e, | |
220 | 0x6f0001e, | |
221 | 0x700001e, | |
222 | 0x710001e, | |
223 | 0x720001e, | |
224 | 0x730001e, | |
225 | 0x740001e, | |
226 | 0x750001e, | |
227 | 0x760001e, | |
228 | 0x770001e, | |
229 | 0x780001e, | |
230 | 0x790001e, | |
231 | 0x7a0001e, | |
232 | 0x7b0001e, | |
233 | 0x7c0001e, | |
234 | 0x7d0001e, | |
235 | 0x7e0001e, | |
236 | 0x7f0001e, | |
237 | 0x800001e, | |
238 | 0x810001e, | |
239 | 0x820001e, | |
240 | 0x830001e, | |
241 | 0x840001e, | |
242 | 0x850001e, | |
243 | 0x860001e, | |
244 | 0x870001e, | |
245 | 0x880001e, | |
246 | 0x890001e, | |
247 | 0x8a0001e, | |
248 | 0x8b0001e, | |
249 | 0x8c0001e, | |
250 | 0x8d0001e, | |
251 | 0x8e0001e, | |
252 | 0x8f0001e, | |
253 | 0x900001e, | |
254 | 0x910001e, | |
255 | 0x920001e, | |
256 | 0x930001e, | |
257 | 0x940001e, | |
258 | 0x950001e, | |
259 | 0x960001e, | |
260 | 0x970001e, | |
261 | 0x980001e, | |
262 | 0x990001e, | |
263 | 0x9a0001e, | |
264 | 0x9b0001e, | |
265 | 0x9c0001e, | |
266 | 0x9d0001e, | |
267 | 0x9e0001e, | |
268 | 0x9f0001e, | |
269 | 0xa00001e, | |
270 | 0xa10001e, | |
271 | 0xa20001e, | |
272 | 0xa30001e, | |
273 | 0xa40001e, | |
274 | 0xa50001e, | |
275 | 0xa60001e, | |
276 | 0xa70001e, | |
277 | 0xa80001e, | |
278 | 0xa90001e, | |
279 | 0xaa0001e, | |
280 | 0xab0001e, | |
281 | 0xac0001e, | |
282 | 0xad0001e, | |
283 | 0xae0001e, | |
284 | 0xaf0001e, | |
285 | 0xb00001e, | |
286 | 0xb10001e, | |
287 | 0xb20001e, | |
288 | 0xb30001e, | |
289 | 0xb40001e, | |
290 | 0xb50001e, | |
291 | 0xb60001e, | |
292 | 0xb70001e, | |
293 | 0xb80001e, | |
294 | 0xb90001e, | |
295 | 0xba0001e, | |
296 | 0xbb0001e, | |
297 | 0xbc0001e, | |
298 | 0xbd0001e, | |
299 | 0xbe0001e, | |
300 | 0xbf0001e, | |
301 | 0xc00001e, | |
302 | 0xc10001e, | |
303 | 0xc20001e, | |
304 | 0xc30001e, | |
305 | 0xc40001e, | |
306 | 0xc50001e, | |
307 | 0xc60001e, | |
308 | 0xc70001e, | |
309 | 0xc80001e, | |
310 | 0xc90001e, | |
311 | 0xca0001e, | |
312 | 0xcb0001e, | |
313 | 0xcc0001e, | |
314 | 0xcd0001e, | |
315 | 0xce0001e, | |
316 | 0xcf0001e, | |
317 | 0xd00001e, | |
318 | 0xd10001e, | |
319 | 0xd20001e, | |
320 | 0xd30001e, | |
321 | 0xd40001e, | |
322 | 0xd50001e, | |
323 | 0xd60001e, | |
324 | 0xd70001e, | |
325 | 0xd80001e, | |
326 | 0xd90001e, | |
327 | 0xda0001e, | |
328 | 0xdb0001e, | |
329 | 0xdc0001e, | |
330 | 0xdd0001e, | |
331 | 0xde0001e, | |
332 | 0xdf0001e, | |
333 | 0xe00001e, | |
334 | 0xe10001e, | |
335 | 0xe20001e, | |
336 | 0xe30001e, | |
337 | 0xe40001e, | |
338 | 0xe50001e, | |
339 | 0xe60001e, | |
340 | 0xe70001e, | |
341 | 0xe80001e, | |
342 | 0xe90001e, | |
343 | 0xea0001e, | |
344 | 0xeb0001e, | |
345 | 0xec0001e, | |
346 | 0xed0001e, | |
347 | 0xee0001e, | |
348 | 0xef0001e, | |
349 | 0x400001e /* default */ | |
350 | } | |
351 | }; | |
352 | ||
353 | /* a self contained prom info structure */ | |
354 | struct leon_reloc_func { | |
355 | struct property *(*find_property) (int node, char *name); | |
356 | int (*strcmp) (char *s1, char *s2); | |
357 | void *(*memcpy) (void *dest, const void *src, size_t n); | |
358 | void (*reboot_physical) (char *cmd); | |
359 | ambapp_dev_apbuart *leon3_apbuart; | |
360 | }; | |
361 | ||
362 | struct leon_prom_info { | |
363 | int freq_khz; | |
364 | int leon_nctx; | |
365 | int mids[32]; | |
366 | int baudrates[2]; | |
367 | struct leon_reloc_func reloc_funcs; | |
368 | struct property root_properties[4]; | |
369 | struct property cpu_properties[7]; | |
370 | #undef CPUENTRY | |
371 | #define CPUENTRY(idx) struct property cpu_properties##idx[4] | |
372 | CPUENTRY(1); | |
373 | CPUENTRY(2); | |
374 | CPUENTRY(3); | |
375 | CPUENTRY(4); | |
376 | CPUENTRY(5); | |
377 | CPUENTRY(6); | |
378 | CPUENTRY(7); | |
379 | CPUENTRY(8); | |
380 | CPUENTRY(9); | |
381 | CPUENTRY(10); | |
382 | CPUENTRY(11); | |
383 | CPUENTRY(12); | |
384 | CPUENTRY(13); | |
385 | CPUENTRY(14); | |
386 | CPUENTRY(15); | |
387 | CPUENTRY(16); | |
388 | CPUENTRY(17); | |
389 | CPUENTRY(18); | |
390 | CPUENTRY(19); | |
391 | CPUENTRY(20); | |
392 | CPUENTRY(21); | |
393 | CPUENTRY(22); | |
394 | CPUENTRY(23); | |
395 | CPUENTRY(24); | |
396 | CPUENTRY(25); | |
397 | CPUENTRY(26); | |
398 | CPUENTRY(27); | |
399 | CPUENTRY(28); | |
400 | CPUENTRY(29); | |
401 | CPUENTRY(30); | |
402 | CPUENTRY(31); | |
403 | struct idprom idprom; | |
404 | struct linux_nodeops nodeops; | |
405 | struct linux_mlist_v0 *totphys_p; | |
406 | struct linux_mlist_v0 totphys; | |
407 | struct linux_mlist_v0 *avail_p; | |
408 | struct linux_mlist_v0 avail; | |
409 | struct linux_mlist_v0 *prommap_p; | |
410 | void (*synchook) (void); | |
411 | struct linux_arguments_v0 *bootargs_p; | |
412 | struct linux_arguments_v0 bootargs; | |
413 | struct linux_romvec romvec; | |
414 | struct node nodes[35]; | |
415 | char s_device_type[12]; | |
416 | char s_cpu[4]; | |
417 | char s_mid[4]; | |
418 | char s_idprom[7]; | |
419 | char s_compatability[14]; | |
420 | char s_leon2[6]; | |
421 | char s_mmu_nctx[9]; | |
422 | char s_frequency[16]; | |
423 | char s_uart1_baud[11]; | |
424 | char s_uart2_baud[11]; | |
425 | char arg[256]; | |
426 | }; | |
427 | ||
428 | /* static prom info */ | |
429 | static struct leon_prom_info PROM_DATA spi = { | |
430 | CONFIG_SYS_CLK_FREQ / 1000, | |
431 | 256, | |
432 | { | |
433 | #undef CPUENTRY | |
434 | #define CPUENTRY(idx) idx | |
435 | CPUENTRY(0), | |
436 | CPUENTRY(1), | |
437 | CPUENTRY(2), | |
438 | CPUENTRY(3), | |
439 | CPUENTRY(4), | |
440 | CPUENTRY(5), | |
441 | CPUENTRY(6), | |
442 | CPUENTRY(7), | |
443 | CPUENTRY(8), | |
444 | CPUENTRY(9), | |
445 | CPUENTRY(10), | |
446 | CPUENTRY(11), | |
447 | CPUENTRY(12), | |
448 | CPUENTRY(13), | |
449 | CPUENTRY(14), | |
450 | CPUENTRY(15), | |
451 | CPUENTRY(16), | |
452 | CPUENTRY(17), | |
453 | CPUENTRY(18), | |
454 | CPUENTRY(19), | |
455 | CPUENTRY(20), | |
456 | CPUENTRY(21), | |
457 | CPUENTRY(22), | |
458 | CPUENTRY(23), | |
459 | CPUENTRY(24), | |
460 | CPUENTRY(25), | |
461 | CPUENTRY(26), | |
462 | CPUENTRY(27), | |
463 | CPUENTRY(28), | |
464 | CPUENTRY(29), | |
465 | CPUENTRY(30), | |
466 | 31}, | |
467 | {38400, 38400}, | |
468 | { | |
469 | __va(find_property), | |
470 | __va(leon_strcmp), | |
471 | __va(leon_memcpy), | |
472 | __phy(leon_reboot_physical), | |
473 | }, | |
474 | { | |
475 | {__va(spi.s_device_type), __va(spi.s_idprom), 4}, | |
476 | {__va(spi.s_idprom), (char *)__va(&spi.idprom), sizeof(struct idprom)}, | |
477 | {__va(spi.s_compatability), __va(spi.s_leon2), 5}, | |
478 | {NULL, NULL, -1} | |
479 | }, | |
480 | { | |
481 | {__va(spi.s_device_type), __va(spi.s_cpu), 4}, | |
482 | {__va(spi.s_mid), __va(&spi.mids[0]), 4}, | |
483 | {__va(spi.s_mmu_nctx), (char *)__va(&spi.leon_nctx), 4}, | |
484 | {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4}, | |
485 | {__va(spi.s_uart1_baud), (char *)__va(&spi.baudrates[0]), 4}, | |
486 | {__va(spi.s_uart2_baud), (char *)__va(&spi.baudrates[1]), 4}, | |
487 | {NULL, NULL, -1} | |
488 | }, | |
489 | #undef CPUENTRY | |
490 | #define CPUENTRY(idx) \ | |
491 | { /* cpu_properties */ \ | |
492 | {__va(spi.s_device_type), __va(spi.s_cpu), 4}, \ | |
493 | {__va(spi.s_mid), __va(&spi.mids[idx]), 4}, \ | |
494 | {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4}, \ | |
495 | {NULL, NULL, -1} \ | |
496 | } | |
497 | CPUENTRY(1), | |
498 | CPUENTRY(2), | |
499 | CPUENTRY(3), | |
500 | CPUENTRY(4), | |
501 | CPUENTRY(5), | |
502 | CPUENTRY(6), | |
503 | CPUENTRY(7), | |
504 | CPUENTRY(8), | |
505 | CPUENTRY(9), | |
506 | CPUENTRY(10), | |
507 | CPUENTRY(11), | |
508 | CPUENTRY(12), | |
509 | CPUENTRY(13), | |
510 | CPUENTRY(14), | |
511 | CPUENTRY(15), | |
512 | CPUENTRY(16), | |
513 | CPUENTRY(17), | |
514 | CPUENTRY(18), | |
515 | CPUENTRY(19), | |
516 | CPUENTRY(20), | |
517 | CPUENTRY(21), | |
518 | CPUENTRY(22), | |
519 | CPUENTRY(23), | |
520 | CPUENTRY(24), | |
521 | CPUENTRY(25), | |
522 | CPUENTRY(26), | |
523 | CPUENTRY(27), | |
524 | CPUENTRY(28), | |
525 | CPUENTRY(29), | |
526 | CPUENTRY(30), | |
527 | CPUENTRY(31), | |
528 | { | |
529 | 0x01, /* format */ | |
530 | M_LEON2 | M_LEON2_SOC, /* machine type */ | |
531 | {0, 0, 0, 0, 0, 0}, /* eth */ | |
532 | 0, /* date */ | |
533 | 0, /* sernum */ | |
534 | 0, /* checksum */ | |
535 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* reserved */ | |
536 | }, | |
537 | { | |
538 | __va(no_nextnode), | |
539 | __va(no_child), | |
540 | __va(no_proplen), | |
541 | __va(no_getprop), | |
542 | __va(no_setprop), | |
543 | __va(no_nextprop) | |
544 | }, | |
545 | __va(&spi.totphys), | |
546 | { | |
547 | NULL, | |
6d0f6bcf | 548 | (char *)CONFIG_SYS_SDRAM_BASE, |
1e9a164e DH |
549 | 0, |
550 | }, | |
551 | __va(&spi.avail), | |
552 | { | |
553 | NULL, | |
6d0f6bcf | 554 | (char *)CONFIG_SYS_SDRAM_BASE, |
1e9a164e DH |
555 | 0, |
556 | }, | |
557 | NULL, /* prommap_p */ | |
558 | NULL, | |
559 | __va(&spi.bootargs), | |
560 | { | |
561 | {NULL, __va(spi.arg), NULL /*... */ }, | |
562 | /*... */ | |
563 | }, | |
564 | { | |
565 | 0, | |
566 | 0, /* sun4c v0 prom */ | |
567 | 0, 0, | |
568 | {__va(&spi.totphys_p), __va(&spi.prommap_p), __va(&spi.avail_p)}, | |
569 | __va(&spi.nodeops), | |
570 | NULL, {NULL /* ... */ }, | |
571 | NULL, NULL, | |
572 | NULL, NULL, /* pv_getchar, pv_putchar */ | |
573 | __va(leon_nbgetchar), __va(leon_nbputchar), | |
574 | NULL, | |
575 | __va(leon_reboot), | |
576 | NULL, | |
577 | NULL, | |
578 | NULL, | |
579 | __va(leon_halt), | |
580 | __va(&spi.synchook), | |
581 | {NULL}, | |
582 | __va(&spi.bootargs_p) | |
583 | /*... */ | |
584 | }, | |
585 | { | |
586 | {0, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ }, | |
587 | {0, __va(spi.root_properties)}, | |
588 | /* cpu 0, must be spi.nodes[2] see leon_prom_init() */ | |
589 | {1, __va(spi.cpu_properties)}, | |
590 | ||
591 | #undef CPUENTRY | |
592 | #define CPUENTRY(idx) \ | |
593 | {1, __va(spi.cpu_properties##idx) } /* cpu <idx> */ | |
594 | CPUENTRY(1), | |
595 | CPUENTRY(2), | |
596 | CPUENTRY(3), | |
597 | CPUENTRY(4), | |
598 | CPUENTRY(5), | |
599 | CPUENTRY(6), | |
600 | CPUENTRY(7), | |
601 | CPUENTRY(8), | |
602 | CPUENTRY(9), | |
603 | CPUENTRY(10), | |
604 | CPUENTRY(11), | |
605 | CPUENTRY(12), | |
606 | CPUENTRY(13), | |
607 | CPUENTRY(14), | |
608 | CPUENTRY(15), | |
609 | CPUENTRY(16), | |
610 | CPUENTRY(17), | |
611 | CPUENTRY(18), | |
612 | CPUENTRY(19), | |
613 | CPUENTRY(20), | |
614 | CPUENTRY(21), | |
615 | CPUENTRY(22), | |
616 | CPUENTRY(23), | |
617 | CPUENTRY(24), | |
618 | CPUENTRY(25), | |
619 | CPUENTRY(26), | |
620 | CPUENTRY(27), | |
621 | CPUENTRY(28), | |
622 | CPUENTRY(29), | |
623 | CPUENTRY(30), | |
624 | CPUENTRY(31), | |
625 | {-1, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ } | |
626 | }, | |
627 | "device_type", | |
628 | "cpu", | |
629 | "mid", | |
630 | "idprom", | |
631 | "compatability", | |
632 | "leon2", | |
633 | "mmu-nctx", | |
634 | "clock-frequency", | |
635 | "uart1_baud", | |
636 | "uart2_baud", | |
637 | CONFIG_DEFAULT_KERNEL_COMMAND_LINE | |
638 | }; | |
639 | ||
640 | /* from arch/sparc/kernel/setup.c */ | |
641 | #define RAMDISK_LOAD_FLAG 0x4000 | |
642 | extern unsigned short root_flags; | |
643 | extern unsigned short root_dev; | |
644 | extern unsigned short ram_flags; | |
645 | extern unsigned int sparc_ramdisk_image; | |
646 | extern unsigned int sparc_ramdisk_size; | |
647 | extern int root_mountflags; | |
648 | ||
649 | extern char initrd_end, initrd_start; | |
650 | ||
651 | /* Reboot the CPU = jump to beginning of flash again. | |
652 | * | |
653 | * Make sure that all function are inlined here. | |
654 | */ | |
655 | static void PROM_TEXT leon_reboot(char *bcommand) | |
656 | { | |
657 | register char *arg = bcommand; | |
658 | void __attribute__ ((noreturn)) (*reboot_physical) (char *cmd); | |
659 | ||
660 | /* get physical address */ | |
661 | struct leon_prom_info *pspi = | |
6d0f6bcf | 662 | (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); |
1e9a164e DH |
663 | |
664 | unsigned int *srmmu_ctx_table; | |
665 | ||
666 | /* Turn of Interrupts */ | |
667 | set_pil(0xf); | |
668 | ||
669 | /* Set kernel's context, context zero */ | |
670 | srmmu_set_context(0); | |
671 | ||
672 | /* Get physical address of the MMU shutdown routine */ | |
673 | reboot_physical = (void *) | |
674 | SPARC_BYPASS_READ(&pspi->reloc_funcs.reboot_physical); | |
675 | ||
676 | /* Now that we know the physical address of the function | |
677 | * we can make the MMU allow jumping to it. | |
678 | */ | |
679 | srmmu_ctx_table = (unsigned int *)srmmu_get_ctable_ptr(); | |
680 | ||
681 | srmmu_ctx_table = (unsigned int *)SPARC_BYPASS_READ(srmmu_ctx_table); | |
682 | ||
683 | /* get physical address of kernel's context table (assume ptd) */ | |
684 | srmmu_ctx_table = (unsigned int *) | |
685 | (((unsigned int)srmmu_ctx_table & 0xfffffffc) << 4); | |
686 | ||
687 | /* enable access to physical address of MMU shutdown function */ | |
688 | SPARC_BYPASS_WRITE(&srmmu_ctx_table | |
689 | [((unsigned int)reboot_physical) >> 24], | |
690 | (((unsigned int)reboot_physical & 0xff000000) >> 4) | | |
691 | 0x1e); | |
692 | ||
693 | /* flush TLB cache */ | |
694 | leon_flush_tlb_all(); | |
695 | ||
696 | /* flash instruction & data cache */ | |
697 | sparc_icache_flush_all(); | |
698 | sparc_dcache_flush_all(); | |
699 | ||
700 | /* jump to physical address function | |
701 | * so that when the MMU is disabled | |
702 | * we can continue to execute | |
703 | */ | |
704 | reboot_physical(arg); | |
705 | } | |
706 | ||
707 | static void PROM_TEXT leon_reboot_physical(char *bcommand) | |
708 | { | |
709 | void __attribute__ ((noreturn)) (*reset) (void); | |
710 | ||
711 | /* Turn off MMU */ | |
712 | srmmu_set_mmureg(0); | |
713 | ||
714 | /* Hardcoded start address */ | |
6d0f6bcf | 715 | reset = CONFIG_SYS_MONITOR_BASE; |
1e9a164e DH |
716 | |
717 | /* flush data cache */ | |
718 | sparc_dcache_flush_all(); | |
719 | ||
720 | /* flush instruction cache */ | |
721 | sparc_icache_flush_all(); | |
722 | ||
723 | /* Jump to start in Flash */ | |
724 | reset(); | |
725 | } | |
726 | ||
727 | static void PROM_TEXT leon_halt(void) | |
728 | { | |
729 | while (1) ; | |
730 | } | |
731 | ||
732 | /* get single char, don't care for blocking*/ | |
733 | static int PROM_TEXT leon_nbgetchar(void) | |
734 | { | |
735 | return -1; | |
736 | } | |
737 | ||
738 | /* put single char, don't care for blocking*/ | |
739 | static int PROM_TEXT leon_nbputchar(int c) | |
740 | { | |
741 | ambapp_dev_apbuart *uart; | |
742 | ||
743 | /* get physical address */ | |
744 | struct leon_prom_info *pspi = | |
6d0f6bcf | 745 | (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); |
1e9a164e DH |
746 | |
747 | uart = (ambapp_dev_apbuart *) | |
748 | SPARC_BYPASS_READ(&pspi->reloc_funcs.leon3_apbuart); | |
749 | ||
750 | /* no UART? */ | |
751 | if (!uart) | |
752 | return 0; | |
753 | ||
754 | /***** put char in buffer... *********** | |
755 | * Make sure all functions are inline! * | |
756 | ***************************************/ | |
757 | ||
758 | /* Wait for last character to go. */ | |
759 | while (!(SPARC_BYPASS_READ(&uart->status) | |
760 | & LEON_REG_UART_STATUS_THE)) ; | |
761 | ||
762 | /* Send data */ | |
763 | SPARC_BYPASS_WRITE(&uart->data, c); | |
764 | ||
765 | /* Wait for data to be sent */ | |
766 | while (!(SPARC_BYPASS_READ(&uart->status) | |
767 | & LEON_REG_UART_STATUS_TSE)) ; | |
768 | ||
769 | return 0; | |
770 | } | |
771 | ||
772 | /* node ops */ | |
773 | ||
774 | /*#define nodes ((struct node *)__va(&pspi->nodes))*/ | |
775 | #define nodes ((struct node *)(pspi->nodes)) | |
776 | ||
777 | static int PROM_TEXT no_nextnode(int node) | |
778 | { | |
779 | /* get physical address */ | |
780 | struct leon_prom_info *pspi = | |
6d0f6bcf | 781 | (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); |
1e9a164e DH |
782 | |
783 | /* convert into virtual address */ | |
784 | pspi = (struct leon_prom_info *) | |
785 | (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); | |
786 | ||
787 | if (nodes[node].level == nodes[node + 1].level) | |
788 | return node + 1; | |
789 | return -1; | |
790 | } | |
791 | ||
792 | static int PROM_TEXT no_child(int node) | |
793 | { | |
794 | /* get physical address */ | |
795 | struct leon_prom_info *pspi = (struct leon_prom_info *) | |
6d0f6bcf | 796 | (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); |
1e9a164e DH |
797 | |
798 | /* convert into virtual address */ | |
799 | pspi = (struct leon_prom_info *) | |
800 | (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); | |
801 | ||
802 | if (nodes[node].level == nodes[node + 1].level - 1) | |
803 | return node + 1; | |
804 | return -1; | |
805 | } | |
806 | ||
807 | static struct property PROM_TEXT *find_property(int node, char *name) | |
808 | { | |
809 | /* get physical address */ | |
810 | struct leon_prom_info *pspi = (struct leon_prom_info *) | |
6d0f6bcf | 811 | (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); |
1e9a164e DH |
812 | |
813 | /* convert into virtual address */ | |
814 | pspi = (struct leon_prom_info *) | |
815 | (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); | |
816 | ||
817 | struct property *prop = &nodes[node].properties[0]; | |
818 | while (prop && prop->name) { | |
819 | if (pspi->reloc_funcs.strcmp(prop->name, name) == 0) | |
820 | return prop; | |
821 | prop++; | |
822 | } | |
823 | return NULL; | |
824 | } | |
825 | ||
826 | static int PROM_TEXT no_proplen(int node, char *name) | |
827 | { | |
828 | /* get physical address */ | |
829 | struct leon_prom_info *pspi = (struct leon_prom_info *) | |
6d0f6bcf | 830 | (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); |
1e9a164e DH |
831 | |
832 | /* convert into virtual address */ | |
833 | pspi = (struct leon_prom_info *) | |
834 | (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); | |
835 | ||
836 | struct property *prop = pspi->reloc_funcs.find_property(node, name); | |
837 | if (prop) | |
838 | return prop->length; | |
839 | return -1; | |
840 | } | |
841 | ||
842 | static int PROM_TEXT no_getprop(int node, char *name, char *value) | |
843 | { | |
844 | /* get physical address */ | |
845 | struct leon_prom_info *pspi = (struct leon_prom_info *) | |
6d0f6bcf | 846 | (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); |
1e9a164e DH |
847 | |
848 | /* convert into virtual address */ | |
849 | pspi = (struct leon_prom_info *) | |
850 | (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); | |
851 | ||
852 | struct property *prop = pspi->reloc_funcs.find_property(node, name); | |
853 | if (prop) { | |
854 | pspi->reloc_funcs.memcpy(value, prop->value, prop->length); | |
855 | return 1; | |
856 | } | |
857 | return -1; | |
858 | } | |
859 | ||
860 | static int PROM_TEXT no_setprop(int node, char *name, char *value, int len) | |
861 | { | |
862 | return -1; | |
863 | } | |
864 | ||
865 | static char PROM_TEXT *no_nextprop(int node, char *name) | |
866 | { | |
867 | /* get physical address */ | |
868 | struct leon_prom_info *pspi = (struct leon_prom_info *) | |
6d0f6bcf | 869 | (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables)); |
1e9a164e DH |
870 | struct property *prop; |
871 | ||
872 | /* convert into virtual address */ | |
873 | pspi = (struct leon_prom_info *) | |
874 | (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET); | |
875 | ||
876 | if (!name || !name[0]) | |
877 | return nodes[node].properties[0].name; | |
878 | ||
879 | prop = pspi->reloc_funcs.find_property(node, name); | |
880 | if (prop) | |
881 | return prop[1].name; | |
882 | return NULL; | |
883 | } | |
884 | ||
885 | static int PROM_TEXT leon_strcmp(const char *s1, const char *s2) | |
886 | { | |
887 | register char result; | |
888 | ||
889 | while (1) { | |
890 | result = *s1 - *s2; | |
891 | if (result || !*s1) | |
892 | break; | |
893 | s2++; | |
894 | s1++; | |
895 | } | |
896 | ||
897 | return result; | |
898 | } | |
899 | ||
900 | static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n) | |
901 | { | |
902 | char *dst = (char *)dest, *source = (char *)src; | |
903 | ||
904 | while (n--) { | |
905 | *dst = *source; | |
906 | dst++; | |
907 | source++; | |
908 | } | |
909 | return dest; | |
910 | } | |
911 | ||
912 | #define GETREGSP(sp) __asm__ __volatile__("mov %%sp, %0" : "=r" (sp)) | |
913 | ||
914 | void leon_prom_init(struct leon_prom_info *pspi) | |
915 | { | |
916 | unsigned long i; | |
917 | unsigned char cksum, *ptr; | |
918 | char *addr_str, *end; | |
919 | unsigned long sp; | |
920 | GETREGSP(sp); | |
921 | ||
922 | pspi->freq_khz = CONFIG_SYS_CLK_FREQ / 1000; | |
923 | ||
924 | /* Set Available main memory size */ | |
6d0f6bcf | 925 | pspi->totphys.num_bytes = CONFIG_SYS_PROM_OFFSET - CONFIG_SYS_SDRAM_BASE; |
1e9a164e DH |
926 | pspi->avail.num_bytes = pspi->totphys.num_bytes; |
927 | ||
928 | /* Set the pointer to the Console UART in romvec */ | |
929 | pspi->reloc_funcs.leon3_apbuart = leon3_apbuart; | |
930 | ||
931 | { | |
932 | int j = 1; | |
933 | #ifdef CONFIG_SMP | |
934 | ambapp_dev_irqmp *b; | |
935 | b = (ambapp_dev_irqmp *) leon3_getapbbase(VENDOR_GAISLER, | |
936 | GAISLER_IRQMP); | |
937 | if (b) { | |
938 | j = 1 + ((LEON3_BYPASS_LOAD_PA(&(b->mpstatus)) | |
939 | >> LEON3_IRQMPSTATUS_CPUNR) & 0xf); | |
940 | } | |
941 | #endif | |
942 | #undef nodes | |
943 | pspi->nodes[2 + j].level = -1; | |
944 | pspi->nodes[2 + j].properties = __va(spi.root_properties + 3); | |
945 | } | |
946 | ||
947 | /* Set Ethernet MAC address from environment */ | |
948 | if ((addr_str = getenv("ethaddr")) != NULL) { | |
949 | for (i = 0; i < 6; i++) { | |
950 | pspi->idprom.id_ethaddr[i] = addr_str ? | |
951 | simple_strtoul(addr_str, &end, 16) : 0; | |
952 | if (addr_str) { | |
953 | addr_str = (*end) ? end + 1 : end; | |
954 | } | |
955 | } | |
956 | } else { | |
957 | /* HW Address not found in environment, | |
958 | * Set default HW address | |
959 | */ | |
960 | pspi->idprom.id_ethaddr[0] = 0; | |
961 | pspi->idprom.id_ethaddr[1] = 0; | |
962 | pspi->idprom.id_ethaddr[2] = 0; | |
963 | pspi->idprom.id_ethaddr[3] = 0; | |
964 | pspi->idprom.id_ethaddr[4] = 0; | |
965 | pspi->idprom.id_ethaddr[5] = 0; | |
966 | } | |
967 | ||
968 | ptr = (unsigned char *)&pspi->idprom; | |
969 | for (i = cksum = 0; i <= 0x0E; i++) | |
970 | cksum ^= *ptr++; | |
971 | pspi->idprom.id_cksum = cksum; | |
972 | } | |
973 | ||
974 | static inline void set_cache(unsigned long regval) | |
975 | { | |
976 | asm volatile ("sta %0, [%%g0] %1\n\t":: "r" (regval), "i"(2):"memory"); | |
977 | } | |
978 | ||
979 | extern unsigned short bss_start, bss_end; | |
980 | ||
981 | /* mark as section .img.main.text, to be referenced in linker script */ | |
982 | int prom_init(void) | |
983 | { | |
984 | struct leon_prom_info *pspi = (void *) | |
6d0f6bcf | 985 | ((((unsigned int)&spi) & PROM_SIZE_MASK) + CONFIG_SYS_PROM_OFFSET); |
1e9a164e DH |
986 | |
987 | /* disable mmu */ | |
988 | srmmu_set_mmureg(0x00000000); | |
989 | __asm__ __volatile__("flush\n\t"); | |
990 | ||
991 | /* init prom info struct */ | |
992 | leon_prom_init(pspi); | |
993 | ||
994 | kernel_arg_promvec = &pspi->romvec; | |
995 | #ifdef PRINT_ROM_VEC | |
996 | printf("Kernel rom vec: 0x%lx\n", (unsigned int)(&pspi->romvec)); | |
997 | #endif | |
998 | return 0; | |
999 | } | |
1000 | ||
1001 | /* Copy current kernel boot argument to ROMvec */ | |
1002 | void prepare_bootargs(char *bootargs) | |
1003 | { | |
1004 | struct leon_prom_info *pspi; | |
1005 | char *src, *dst; | |
1006 | int left; | |
1007 | ||
1008 | /* if no bootargs set, skip copying ==> default bootline */ | |
1009 | if (bootargs && (*bootargs != '\0')) { | |
1010 | pspi = (void *)((((unsigned int)&spi) & PROM_SIZE_MASK) + | |
6d0f6bcf | 1011 | CONFIG_SYS_PROM_OFFSET); |
1e9a164e DH |
1012 | src = bootargs; |
1013 | dst = &pspi->arg[0]; | |
1014 | left = 255; /* max len */ | |
1015 | while (*src && left > 0) { | |
1016 | *dst++ = *src++; | |
1017 | left--; | |
1018 | } | |
1019 | /* terminate kernel command line string */ | |
1020 | *dst = 0; | |
1021 | } | |
1022 | } | |
1023 | ||
1024 | void srmmu_init_cpu(unsigned int entry) | |
1025 | { | |
1026 | sparc_srmmu_setup *psrmmu_tables = (void *) | |
1027 | ((((unsigned int)&srmmu_tables) & PROM_SIZE_MASK) + | |
6d0f6bcf | 1028 | CONFIG_SYS_PROM_OFFSET); |
1e9a164e DH |
1029 | |
1030 | /* Make context 0 (kernel's context) point | |
1031 | * to our prepared memory mapping | |
1032 | */ | |
1033 | #define PTD 1 | |
1034 | psrmmu_tables->ctx_table[0] = | |
1035 | ((unsigned int)&psrmmu_tables->pgd_table[0x00]) >> 4 | PTD; | |
1036 | ||
1037 | /* Set virtual kernel address 0xf0000000 | |
1038 | * to SRAM/SDRAM address. | |
1039 | * Make it READ/WRITE/EXEC to SuperUser | |
1040 | */ | |
1041 | #define PTE 2 | |
1042 | #define ACC_SU_ALL 0x1c | |
1043 | psrmmu_tables->pgd_table[0xf0] = | |
6d0f6bcf | 1044 | (CONFIG_SYS_SDRAM_BASE >> 4) | ACC_SU_ALL | PTE; |
1e9a164e | 1045 | psrmmu_tables->pgd_table[0xf1] = |
6d0f6bcf | 1046 | ((CONFIG_SYS_SDRAM_BASE + 0x1000000) >> 4) | ACC_SU_ALL | PTE; |
1e9a164e | 1047 | psrmmu_tables->pgd_table[0xf2] = |
6d0f6bcf | 1048 | ((CONFIG_SYS_SDRAM_BASE + 0x2000000) >> 4) | ACC_SU_ALL | PTE; |
1e9a164e | 1049 | psrmmu_tables->pgd_table[0xf3] = |
6d0f6bcf | 1050 | ((CONFIG_SYS_SDRAM_BASE + 0x3000000) >> 4) | ACC_SU_ALL | PTE; |
1e9a164e | 1051 | psrmmu_tables->pgd_table[0xf4] = |
6d0f6bcf | 1052 | ((CONFIG_SYS_SDRAM_BASE + 0x4000000) >> 4) | ACC_SU_ALL | PTE; |
1e9a164e | 1053 | psrmmu_tables->pgd_table[0xf5] = |
6d0f6bcf | 1054 | ((CONFIG_SYS_SDRAM_BASE + 0x5000000) >> 4) | ACC_SU_ALL | PTE; |
1e9a164e | 1055 | psrmmu_tables->pgd_table[0xf6] = |
6d0f6bcf | 1056 | ((CONFIG_SYS_SDRAM_BASE + 0x6000000) >> 4) | ACC_SU_ALL | PTE; |
1e9a164e | 1057 | psrmmu_tables->pgd_table[0xf7] = |
6d0f6bcf | 1058 | ((CONFIG_SYS_SDRAM_BASE + 0x7000000) >> 4) | ACC_SU_ALL | PTE; |
1e9a164e DH |
1059 | |
1060 | /* convert rom vec pointer to virtual address */ | |
1061 | kernel_arg_promvec = (struct linux_romvec *) | |
1062 | (((unsigned int)kernel_arg_promvec & 0x0fffffff) | 0xf0000000); | |
1063 | ||
1064 | /* Set Context pointer to point to context table | |
1065 | * 256 contexts supported. | |
1066 | */ | |
1067 | srmmu_set_ctable_ptr((unsigned int)&psrmmu_tables->ctx_table[0]); | |
1068 | ||
1069 | /* Set kernel's context, context zero */ | |
1070 | srmmu_set_context(0); | |
1071 | ||
1072 | /* Invalidate all Cache */ | |
1073 | __asm__ __volatile__("flush\n\t"); | |
1074 | ||
1075 | srmmu_set_mmureg(0x00000001); | |
1076 | leon_flush_tlb_all(); | |
1077 | leon_flush_cache_all(); | |
1078 | } |