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