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