blob: 1f185b776b48ed9ca43c75f4f3c69cfed67c4483 [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>
Daniel Hellstrom9d59af92010-01-21 16:09:37 +010018#include <grlib/apbuart.h>
19#include <grlib/irqmp.h>
20#include <grlib/gptimer.h>
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010021
22#include <config.h>
23/*
24#define PRINT_ROM_VEC
25*/
26extern struct linux_romvec *kernel_arg_promvec;
Francois Retiefff6929d2015-10-28 10:35:12 +020027
28DECLARE_GLOBAL_DATA_PTR;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010029
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
34ambapp_dev_gptimer *gptimer;
35
Francois Retieffc7784e2015-11-23 13:05:44 +020036void *__prom_start_reloc; /* relocated prom_start address */
37
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010038/* for __va */
39extern int __prom_start;
40#define PAGE_OFFSET 0xf0000000
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020041#define phys_base CONFIG_SYS_SDRAM_BASE
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010042#define PROM_OFFS 8192
43#define PROM_SIZE_MASK (PROM_OFFS-1)
44#define __va(x) ( \
45 (void *)( ((unsigned long)(x))-PROM_OFFS+ \
Wolfgang Denk0708bc62010-10-07 21:51:12 +020046 (CONFIG_SYS_PROM_OFFSET-phys_base)+PAGE_OFFSET-CONFIG_SYS_TEXT_BASE ) \
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010047 )
Wolfgang Denk0708bc62010-10-07 21:51:12 +020048#define __phy(x) ((void *)(((unsigned long)(x))-PROM_OFFS+CONFIG_SYS_PROM_OFFSET-CONFIG_SYS_TEXT_BASE))
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010049
50struct property {
51 char *name;
52 char *value;
53 int length;
54};
55
56struct node {
57 int level;
58 struct property *properties;
59};
60
61static void leon_reboot(char *bcommand);
62static void leon_halt(void);
63static int leon_nbputchar(int c);
64static int leon_nbgetchar(void);
65
66static int no_nextnode(int node);
67static int no_child(int node);
68static int no_proplen(int node, char *name);
69static int no_getprop(int node, char *name, char *value);
70static int no_setprop(int node, char *name, char *value, int len);
71static char *no_nextprop(int node, char *name);
72
73static struct property PROM_TEXT *find_property(int node, char *name);
74static int PROM_TEXT leon_strcmp(const char *s1, const char *s2);
75static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n);
76static void PROM_TEXT leon_reboot_physical(char *bcommand);
77
78void __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
84void __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
91typedef struct {
92 unsigned int ctx_table[256];
93 unsigned int pgd_table[256];
94} sparc_srmmu_setup;
95
96sparc_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 */
343struct 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
351struct 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 */
418static 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,
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200537 (char *)CONFIG_SYS_SDRAM_BASE,
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100538 0,
539 },
540 __va(&spi.avail),
541 {
542 NULL,
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200543 (char *)CONFIG_SYS_SDRAM_BASE,
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100544 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
631extern unsigned short root_flags;
632extern unsigned short root_dev;
633extern unsigned short ram_flags;
634extern unsigned int sparc_ramdisk_image;
635extern unsigned int sparc_ramdisk_size;
636extern int root_mountflags;
637
638extern 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 */
644static 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 =
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200651 (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100652
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
696static 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 */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200704 reset = CONFIG_SYS_MONITOR_BASE;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100705
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
716static void PROM_TEXT leon_halt(void)
717{
718 while (1) ;
719}
720
721/* get single char, don't care for blocking*/
722static int PROM_TEXT leon_nbgetchar(void)
723{
724 return -1;
725}
726
727/* put single char, don't care for blocking*/
728static int PROM_TEXT leon_nbputchar(int c)
729{
730 ambapp_dev_apbuart *uart;
731
732 /* get physical address */
733 struct leon_prom_info *pspi =
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200734 (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100735
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)
Daniel Hellstrom9d59af92010-01-21 16:09:37 +0100749 & APBUART_STATUS_THE));
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100750
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)
Daniel Hellstrom9d59af92010-01-21 16:09:37 +0100756 & APBUART_STATUS_TSE));
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100757
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
766static int PROM_TEXT no_nextnode(int node)
767{
768 /* get physical address */
769 struct leon_prom_info *pspi =
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200770 (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100771
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
781static int PROM_TEXT no_child(int node)
782{
783 /* get physical address */
784 struct leon_prom_info *pspi = (struct leon_prom_info *)
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200785 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100786
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
796static 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 *)
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200800 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100801
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
815static int PROM_TEXT no_proplen(int node, char *name)
816{
817 /* get physical address */
818 struct leon_prom_info *pspi = (struct leon_prom_info *)
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200819 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100820
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
831static 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 *)
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200835 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100836
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
849static int PROM_TEXT no_setprop(int node, char *name, char *value, int len)
850{
851 return -1;
852}
853
854static char PROM_TEXT *no_nextprop(int node, char *name)
855{
856 /* get physical address */
857 struct leon_prom_info *pspi = (struct leon_prom_info *)
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200858 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100859 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
874static 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
889static 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
903void 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 */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200914 pspi->totphys.num_bytes = CONFIG_SYS_PROM_OFFSET - CONFIG_SYS_SDRAM_BASE;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100915 pspi->avail.num_bytes = pspi->totphys.num_bytes;
916
917 /* Set the pointer to the Console UART in romvec */
Francois Retiefff6929d2015-10-28 10:35:12 +0200918 pspi->reloc_funcs.leon3_apbuart = gd->arch.uart;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100919
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
963static inline void set_cache(unsigned long regval)
964{
965 asm volatile ("sta %0, [%%g0] %1\n\t":: "r" (regval), "i"(2):"memory");
966}
967
968extern unsigned short bss_start, bss_end;
969
970/* mark as section .img.main.text, to be referenced in linker script */
971int prom_init(void)
972{
973 struct leon_prom_info *pspi = (void *)
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200974 ((((unsigned int)&spi) & PROM_SIZE_MASK) + CONFIG_SYS_PROM_OFFSET);
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100975
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 */
991void 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) +
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001000 CONFIG_SYS_PROM_OFFSET);
Daniel Hellstromb552dbe2008-03-26 22:51:29 +01001001 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
1013void srmmu_init_cpu(unsigned int entry)
1014{
1015 sparc_srmmu_setup *psrmmu_tables = (void *)
1016 ((((unsigned int)&srmmu_tables) & PROM_SIZE_MASK) +
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001017 CONFIG_SYS_PROM_OFFSET);
Daniel Hellstromb552dbe2008-03-26 22:51:29 +01001018
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] =
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001033 (CONFIG_SYS_SDRAM_BASE >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +01001034 psrmmu_tables->pgd_table[0xf1] =
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001035 ((CONFIG_SYS_SDRAM_BASE + 0x1000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +01001036 psrmmu_tables->pgd_table[0xf2] =
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001037 ((CONFIG_SYS_SDRAM_BASE + 0x2000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +01001038 psrmmu_tables->pgd_table[0xf3] =
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001039 ((CONFIG_SYS_SDRAM_BASE + 0x3000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +01001040 psrmmu_tables->pgd_table[0xf4] =
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001041 ((CONFIG_SYS_SDRAM_BASE + 0x4000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +01001042 psrmmu_tables->pgd_table[0xf5] =
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001043 ((CONFIG_SYS_SDRAM_BASE + 0x5000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +01001044 psrmmu_tables->pgd_table[0xf6] =
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001045 ((CONFIG_SYS_SDRAM_BASE + 0x6000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +01001046 psrmmu_tables->pgd_table[0xf7] =
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001047 ((CONFIG_SYS_SDRAM_BASE + 0x7000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +01001048
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}