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