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