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