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