blob: 1a6c7f79cd5a8ef26afdb5aedfcefd1c0f9a34e2 [file] [log] [blame]
Daniel Hellstromb3309902008-03-28 10:00:33 +01001/* prom.c - emulates a sparc v0 PROM for the linux kernel.
2 *
3 * Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
4 * Copyright (C) 2004 Stefan Holst <mail@s-holst.de>
5 * Copyright (C) 2007 Daniel Hellstrom <daniel@gaisler.com>
6 *
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
35#include <config.h>
36/*
37#define PRINT_ROM_VEC
38*/
39extern struct linux_romvec *kernel_arg_promvec;
40
41#define PROM_PGT __attribute__ ((__section__ (".prom.pgt")))
42#define PROM_TEXT __attribute__ ((__section__ (".prom.text")))
43#define PROM_DATA __attribute__ ((__section__ (".prom.data")))
44
45/* for __va */
46extern int __prom_start;
47#define PAGE_OFFSET 0xf0000000
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020048#define phys_base CONFIG_SYS_SDRAM_BASE
Daniel Hellstromb3309902008-03-28 10:00:33 +010049#define PROM_OFFS 8192
50#define PROM_SIZE_MASK (PROM_OFFS-1)
51#define __va(x) ( \
52 (void *)( ((unsigned long)(x))-PROM_OFFS+ \
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020053 (CONFIG_SYS_PROM_OFFSET-phys_base)+PAGE_OFFSET-TEXT_BASE ) \
Daniel Hellstromb3309902008-03-28 10:00:33 +010054 )
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020055#define __phy(x) ((void *)(((unsigned long)(x))-PROM_OFFS+CONFIG_SYS_PROM_OFFSET-TEXT_BASE))
Daniel Hellstromb3309902008-03-28 10:00:33 +010056
57struct property {
58 char *name;
59 char *value;
60 int length;
61};
62
63struct node {
64 int level;
65 struct property *properties;
66};
67
68static void leon_reboot(char *bcommand);
69static void leon_halt(void);
70static int leon_nbputchar(int c);
71static int leon_nbgetchar(void);
72
73static int no_nextnode(int node);
74static int no_child(int node);
75static int no_proplen(int node, char *name);
76static int no_getprop(int node, char *name, char *value);
77static int no_setprop(int node, char *name, char *value, int len);
78static char *no_nextprop(int node, char *name);
79
80static struct property PROM_TEXT *find_property(int node, char *name);
81static int PROM_TEXT leon_strcmp(const char *s1, const char *s2);
82static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n);
83static void PROM_TEXT leon_reboot_physical(char *bcommand);
84
85void __inline__ leon_flush_cache_all(void)
86{
87 __asm__ __volatile__(" flush ");
88 __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"::"i"(ASI_DFLUSH):"memory");
89}
90
91void __inline__ leon_flush_tlb_all(void)
92{
93 leon_flush_cache_all();
94 __asm__ __volatile__("sta %%g0, [%0] %1\n\t"::"r"(0x400),
95 "i"(ASI_MMUFLUSH):"memory");
96}
97
98typedef struct {
99 unsigned int ctx_table[256];
100 unsigned int pgd_table[256];
101} sparc_srmmu_setup;
102
103sparc_srmmu_setup srmmu_tables PROM_PGT = {
104 {0},
105 {0x1e,
106 0x10001e,
107 0x20001e,
108 0x30001e,
109 0x40001e,
110 0x50001e,
111 0x60001e,
112 0x70001e,
113 0x80001e,
114 0x90001e,
115 0xa0001e,
116 0xb0001e,
117 0xc0001e,
118 0xd0001e,
119 0xe0001e,
120 0xf0001e,
121 0x100001e,
122 0x110001e,
123 0x120001e,
124 0x130001e,
125 0x140001e,
126 0x150001e,
127 0x160001e,
128 0x170001e,
129 0x180001e,
130 0x190001e,
131 0x1a0001e,
132 0x1b0001e,
133 0x1c0001e,
134 0x1d0001e,
135 0x1e0001e,
136 0x1f0001e,
137 0x200001e,
138 0x210001e,
139 0x220001e,
140 0x230001e,
141 0x240001e,
142 0x250001e,
143 0x260001e,
144 0x270001e,
145 0x280001e,
146 0x290001e,
147 0x2a0001e,
148 0x2b0001e,
149 0x2c0001e,
150 0x2d0001e,
151 0x2e0001e,
152 0x2f0001e,
153 0x300001e,
154 0x310001e,
155 0x320001e,
156 0x330001e,
157 0x340001e,
158 0x350001e,
159 0x360001e,
160 0x370001e,
161 0x380001e,
162 0x390001e,
163 0x3a0001e,
164 0x3b0001e,
165 0x3c0001e,
166 0x3d0001e,
167 0x3e0001e,
168 0x3f0001e,
169 0x400001e,
170 0x410001e,
171 0x420001e,
172 0x430001e,
173 0x440001e,
174 0x450001e,
175 0x460001e,
176 0x470001e,
177 0x480001e,
178 0x490001e,
179 0x4a0001e,
180 0x4b0001e,
181 0x4c0001e,
182 0x4d0001e,
183 0x4e0001e,
184 0x4f0001e,
185 0x500001e,
186 0x510001e,
187 0x520001e,
188 0x530001e,
189 0x540001e,
190 0x550001e,
191 0x560001e,
192 0x570001e,
193 0x580001e,
194 0x590001e,
195 0x5a0001e,
196 0x5b0001e,
197 0x5c0001e,
198 0x5d0001e,
199 0x5e0001e,
200 0x5f0001e,
201 0x600001e,
202 0x610001e,
203 0x620001e,
204 0x630001e,
205 0x640001e,
206 0x650001e,
207 0x660001e,
208 0x670001e,
209 0x680001e,
210 0x690001e,
211 0x6a0001e,
212 0x6b0001e,
213 0x6c0001e,
214 0x6d0001e,
215 0x6e0001e,
216 0x6f0001e,
217 0x700001e,
218 0x710001e,
219 0x720001e,
220 0x730001e,
221 0x740001e,
222 0x750001e,
223 0x760001e,
224 0x770001e,
225 0x780001e,
226 0x790001e,
227 0x7a0001e,
228 0x7b0001e,
229 0x7c0001e,
230 0x7d0001e,
231 0x7e0001e,
232 0x7f0001e,
233 0x800001e,
234 0x810001e,
235 0x820001e,
236 0x830001e,
237 0x840001e,
238 0x850001e,
239 0x860001e,
240 0x870001e,
241 0x880001e,
242 0x890001e,
243 0x8a0001e,
244 0x8b0001e,
245 0x8c0001e,
246 0x8d0001e,
247 0x8e0001e,
248 0x8f0001e,
249 0x900001e,
250 0x910001e,
251 0x920001e,
252 0x930001e,
253 0x940001e,
254 0x950001e,
255 0x960001e,
256 0x970001e,
257 0x980001e,
258 0x990001e,
259 0x9a0001e,
260 0x9b0001e,
261 0x9c0001e,
262 0x9d0001e,
263 0x9e0001e,
264 0x9f0001e,
265 0xa00001e,
266 0xa10001e,
267 0xa20001e,
268 0xa30001e,
269 0xa40001e,
270 0xa50001e,
271 0xa60001e,
272 0xa70001e,
273 0xa80001e,
274 0xa90001e,
275 0xaa0001e,
276 0xab0001e,
277 0xac0001e,
278 0xad0001e,
279 0xae0001e,
280 0xaf0001e,
281 0xb00001e,
282 0xb10001e,
283 0xb20001e,
284 0xb30001e,
285 0xb40001e,
286 0xb50001e,
287 0xb60001e,
288 0xb70001e,
289 0xb80001e,
290 0xb90001e,
291 0xba0001e,
292 0xbb0001e,
293 0xbc0001e,
294 0xbd0001e,
295 0xbe0001e,
296 0xbf0001e,
297 0xc00001e,
298 0xc10001e,
299 0xc20001e,
300 0xc30001e,
301 0xc40001e,
302 0xc50001e,
303 0xc60001e,
304 0xc70001e,
305 0xc80001e,
306 0xc90001e,
307 0xca0001e,
308 0xcb0001e,
309 0xcc0001e,
310 0xcd0001e,
311 0xce0001e,
312 0xcf0001e,
313 0xd00001e,
314 0xd10001e,
315 0xd20001e,
316 0xd30001e,
317 0xd40001e,
318 0xd50001e,
319 0xd60001e,
320 0xd70001e,
321 0xd80001e,
322 0xd90001e,
323 0xda0001e,
324 0xdb0001e,
325 0xdc0001e,
326 0xdd0001e,
327 0xde0001e,
328 0xdf0001e,
329 0xe00001e,
330 0xe10001e,
331 0xe20001e,
332 0xe30001e,
333 0xe40001e,
334 0xe50001e,
335 0xe60001e,
336 0xe70001e,
337 0xe80001e,
338 0xe90001e,
339 0xea0001e,
340 0xeb0001e,
341 0xec0001e,
342 0xed0001e,
343 0xee0001e,
344 0xef0001e,
345 0x400001e /* default */
346 }
347};
348
349/* a self contained prom info structure */
350struct leon_reloc_func {
351 struct property *(*find_property) (int node, char *name);
352 int (*strcmp) (char *s1, char *s2);
353 void *(*memcpy) (void *dest, const void *src, size_t n);
354 void (*reboot_physical) (char *cmd);
355};
356
357struct leon_prom_info {
358 int freq_khz;
359 int leon_nctx;
360 int mids[32];
361 int baudrates[2];
362 struct leon_reloc_func reloc_funcs;
363 struct property root_properties[4];
364 struct property cpu_properties[7];
365#undef CPUENTRY
366#define CPUENTRY(idx) struct property cpu_properties##idx[4]
367 CPUENTRY(1);
368 CPUENTRY(2);
369 CPUENTRY(3);
370 CPUENTRY(4);
371 CPUENTRY(5);
372 CPUENTRY(6);
373 CPUENTRY(7);
374 CPUENTRY(8);
375 CPUENTRY(9);
376 CPUENTRY(10);
377 CPUENTRY(11);
378 CPUENTRY(12);
379 CPUENTRY(13);
380 CPUENTRY(14);
381 CPUENTRY(15);
382 CPUENTRY(16);
383 CPUENTRY(17);
384 CPUENTRY(18);
385 CPUENTRY(19);
386 CPUENTRY(20);
387 CPUENTRY(21);
388 CPUENTRY(22);
389 CPUENTRY(23);
390 CPUENTRY(24);
391 CPUENTRY(25);
392 CPUENTRY(26);
393 CPUENTRY(27);
394 CPUENTRY(28);
395 CPUENTRY(29);
396 CPUENTRY(30);
397 CPUENTRY(31);
398 struct idprom idprom;
399 struct linux_nodeops nodeops;
400 struct linux_mlist_v0 *totphys_p;
401 struct linux_mlist_v0 totphys;
402 struct linux_mlist_v0 *avail_p;
403 struct linux_mlist_v0 avail;
404 struct linux_mlist_v0 *prommap_p;
405 void (*synchook) (void);
406 struct linux_arguments_v0 *bootargs_p;
407 struct linux_arguments_v0 bootargs;
408 struct linux_romvec romvec;
409 struct node nodes[35];
410 char s_device_type[12];
411 char s_cpu[4];
412 char s_mid[4];
413 char s_idprom[7];
414 char s_compatability[14];
415 char s_leon2[6];
416 char s_mmu_nctx[9];
417 char s_frequency[16];
418 char s_uart1_baud[11];
419 char s_uart2_baud[11];
420 char arg[256];
421};
422
423/* static prom info */
424static struct leon_prom_info PROM_DATA spi = {
425 CONFIG_SYS_CLK_FREQ / 1000,
426 256,
427 {
428#undef CPUENTRY
429#define CPUENTRY(idx) idx
430 CPUENTRY(0),
431 CPUENTRY(1),
432 CPUENTRY(2),
433 CPUENTRY(3),
434 CPUENTRY(4),
435 CPUENTRY(5),
436 CPUENTRY(6),
437 CPUENTRY(7),
438 CPUENTRY(8),
439 CPUENTRY(9),
440 CPUENTRY(10),
441 CPUENTRY(11),
442 CPUENTRY(12),
443 CPUENTRY(13),
444 CPUENTRY(14),
445 CPUENTRY(15),
446 CPUENTRY(16),
447 CPUENTRY(17),
448 CPUENTRY(18),
449 CPUENTRY(19),
450 CPUENTRY(20),
451 CPUENTRY(21),
452 CPUENTRY(22),
453 CPUENTRY(23),
454 CPUENTRY(24),
455 CPUENTRY(25),
456 CPUENTRY(26),
457 CPUENTRY(27),
458 CPUENTRY(28),
459 CPUENTRY(29),
460 CPUENTRY(30),
461 31},
462 {38400, 38400},
463 {
464 __va(find_property),
465 __va(leon_strcmp),
466 __va(leon_memcpy),
467 __phy(leon_reboot_physical),
468 },
469 {
470 {__va(spi.s_device_type), __va(spi.s_idprom), 4},
471 {__va(spi.s_idprom), (char *)__va(&spi.idprom), sizeof(struct idprom)},
472 {__va(spi.s_compatability), __va(spi.s_leon2), 5},
473 {NULL, NULL, -1}
474 },
475 {
476 {__va(spi.s_device_type), __va(spi.s_cpu), 4},
477 {__va(spi.s_mid), __va(&spi.mids[0]), 4},
478 {__va(spi.s_mmu_nctx), (char *)__va(&spi.leon_nctx), 4},
479 {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4},
480 {__va(spi.s_uart1_baud), (char *)__va(&spi.baudrates[0]), 4},
481 {__va(spi.s_uart2_baud), (char *)__va(&spi.baudrates[1]), 4},
482 {NULL, NULL, -1}
483 },
484#undef CPUENTRY
485#define CPUENTRY(idx) \
486 { /* cpu_properties */ \
487 {__va(spi.s_device_type), __va(spi.s_cpu), 4}, \
488 {__va(spi.s_mid), __va(&spi.mids[idx]), 4}, \
489 {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4}, \
490 {NULL, NULL, -1} \
491 }
492 CPUENTRY(1),
493 CPUENTRY(2),
494 CPUENTRY(3),
495 CPUENTRY(4),
496 CPUENTRY(5),
497 CPUENTRY(6),
498 CPUENTRY(7),
499 CPUENTRY(8),
500 CPUENTRY(9),
501 CPUENTRY(10),
502 CPUENTRY(11),
503 CPUENTRY(12),
504 CPUENTRY(13),
505 CPUENTRY(14),
506 CPUENTRY(15),
507 CPUENTRY(16),
508 CPUENTRY(17),
509 CPUENTRY(18),
510 CPUENTRY(19),
511 CPUENTRY(20),
512 CPUENTRY(21),
513 CPUENTRY(22),
514 CPUENTRY(23),
515 CPUENTRY(24),
516 CPUENTRY(25),
517 CPUENTRY(26),
518 CPUENTRY(27),
519 CPUENTRY(28),
520 CPUENTRY(29),
521 CPUENTRY(30),
522 CPUENTRY(31),
523 {
524 0x01, /* format */
525 M_LEON2 | M_LEON2_SOC, /* machine type */
526 {0, 0, 0, 0, 0, 0}, /* eth */
527 0, /* date */
528 0, /* sernum */
529 0, /* checksum */
530 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* reserved */
531 },
532 {
533 __va(no_nextnode),
534 __va(no_child),
535 __va(no_proplen),
536 __va(no_getprop),
537 __va(no_setprop),
538 __va(no_nextprop)
539 },
540 __va(&spi.totphys),
541 {
542 NULL,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200543 (char *)CONFIG_SYS_SDRAM_BASE,
Daniel Hellstromb3309902008-03-28 10:00:33 +0100544 0,
545 },
546 __va(&spi.avail),
547 {
548 NULL,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200549 (char *)CONFIG_SYS_SDRAM_BASE,
Daniel Hellstromb3309902008-03-28 10:00:33 +0100550 0,
551 },
552 NULL, /* prommap_p */
553 NULL,
554 __va(&spi.bootargs),
555 {
556 {NULL, __va(spi.arg), NULL /*... */ },
557 /*... */
558 },
559 {
560 0,
561 0, /* sun4c v0 prom */
562 0, 0,
563 {__va(&spi.totphys_p), __va(&spi.prommap_p), __va(&spi.avail_p)},
564 __va(&spi.nodeops),
565 NULL, {NULL /* ... */ },
566 NULL, NULL,
567 NULL, NULL, /* pv_getchar, pv_putchar */
568 __va(leon_nbgetchar), __va(leon_nbputchar),
569 NULL,
570 __va(leon_reboot),
571 NULL,
572 NULL,
573 NULL,
574 __va(leon_halt),
575 __va(&spi.synchook),
576 {NULL},
577 __va(&spi.bootargs_p)
578 /*... */
579 },
580 {
581 {0, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ },
582 {0, __va(spi.root_properties)},
583 /* cpu 0, must be spi.nodes[2] see leon_prom_init() */
584 {1, __va(spi.cpu_properties)},
585
586#undef CPUENTRY
587#define CPUENTRY(idx) \
588 {1, __va(spi.cpu_properties##idx) } /* cpu <idx> */
589 CPUENTRY(1),
590 CPUENTRY(2),
591 CPUENTRY(3),
592 CPUENTRY(4),
593 CPUENTRY(5),
594 CPUENTRY(6),
595 CPUENTRY(7),
596 CPUENTRY(8),
597 CPUENTRY(9),
598 CPUENTRY(10),
599 CPUENTRY(11),
600 CPUENTRY(12),
601 CPUENTRY(13),
602 CPUENTRY(14),
603 CPUENTRY(15),
604 CPUENTRY(16),
605 CPUENTRY(17),
606 CPUENTRY(18),
607 CPUENTRY(19),
608 CPUENTRY(20),
609 CPUENTRY(21),
610 CPUENTRY(22),
611 CPUENTRY(23),
612 CPUENTRY(24),
613 CPUENTRY(25),
614 CPUENTRY(26),
615 CPUENTRY(27),
616 CPUENTRY(28),
617 CPUENTRY(29),
618 CPUENTRY(30),
619 CPUENTRY(31),
620 {-1, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ }
621 },
622 "device_type",
623 "cpu",
624 "mid",
625 "idprom",
626 "compatability",
627 "leon2",
628 "mmu-nctx",
629 "clock-frequency",
630 "uart1_baud",
631 "uart2_baud",
632 CONFIG_DEFAULT_KERNEL_COMMAND_LINE
633};
634
635/* from arch/sparc/kernel/setup.c */
636#define RAMDISK_LOAD_FLAG 0x4000
637extern unsigned short root_flags;
638extern unsigned short root_dev;
639extern unsigned short ram_flags;
640extern unsigned int sparc_ramdisk_image;
641extern unsigned int sparc_ramdisk_size;
642extern int root_mountflags;
643
644extern char initrd_end, initrd_start;
645
646/* Reboot the CPU = jump to beginning of flash again.
647 *
648 * Make sure that all function are inlined here.
649 */
650static void PROM_TEXT leon_reboot(char *bcommand)
651{
652 register char *arg = bcommand;
653 void __attribute__ ((noreturn)) (*reboot_physical) (char *cmd);
654
655 /* get physical address */
656 struct leon_prom_info *pspi =
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200657 (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb3309902008-03-28 10:00:33 +0100658
659 unsigned int *srmmu_ctx_table;
660
661 /* Turn of Interrupts */
662 set_pil(0xf);
663
664 /* Set kernel's context, context zero */
665 srmmu_set_context(0);
666
667 /* Get physical address of the MMU shutdown routine */
668 reboot_physical = (void *)
669 SPARC_BYPASS_READ(&pspi->reloc_funcs.reboot_physical);
670
671 /* Now that we know the physical address of the function
672 * we can make the MMU allow jumping to it.
673 */
674 srmmu_ctx_table = (unsigned int *)srmmu_get_ctable_ptr();
675
676 srmmu_ctx_table = (unsigned int *)SPARC_BYPASS_READ(srmmu_ctx_table);
677
678 /* get physical address of kernel's context table (assume ptd) */
679 srmmu_ctx_table = (unsigned int *)
680 (((unsigned int)srmmu_ctx_table & 0xfffffffc) << 4);
681
682 /* enable access to physical address of MMU shutdown function */
683 SPARC_BYPASS_WRITE(&srmmu_ctx_table
684 [((unsigned int)reboot_physical) >> 24],
685 (((unsigned int)reboot_physical & 0xff000000) >> 4) |
686 0x1e);
687
688 /* flush TLB cache */
689 leon_flush_tlb_all();
690
691 /* flash instruction & data cache */
692 sparc_icache_flush_all();
693 sparc_dcache_flush_all();
694
695 /* jump to physical address function
696 * so that when the MMU is disabled
697 * we can continue to execute
698 */
699 reboot_physical(arg);
700}
701
702static void PROM_TEXT leon_reboot_physical(char *bcommand)
703{
704 void __attribute__ ((noreturn)) (*reset) (void);
705
706 /* Turn off MMU */
707 srmmu_set_mmureg(0);
708
709 /* Hardcoded start address */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200710 reset = CONFIG_SYS_MONITOR_BASE;
Daniel Hellstromb3309902008-03-28 10:00:33 +0100711
712 /* flush data cache */
713 sparc_dcache_flush_all();
714
715 /* flush instruction cache */
716 sparc_icache_flush_all();
717
718 /* Jump to start in Flash */
719 reset();
720}
721
722static void PROM_TEXT leon_halt(void)
723{
724 while (1) ;
725}
726
727/* get single char, don't care for blocking*/
728static int PROM_TEXT leon_nbgetchar(void)
729{
730 return -1;
731}
732
733/* put single char, don't care for blocking*/
734static int PROM_TEXT leon_nbputchar(int c)
735{
736 LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS;
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(&leon2->UART_Status_1)
744 & LEON2_UART_STAT_THE)) ;
745
746 /* Send data */
747 SPARC_BYPASS_WRITE(&leon2->UART_Channel_1, c);
748
749 /* Wait for data to be sent */
750 while (!(SPARC_BYPASS_READ(&leon2->UART_Status_1)
751 & LEON2_UART_STAT_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-VILLARD6d0f6bc2008-10-16 15:01:15 +0200765 (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb3309902008-03-28 10:00:33 +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-VILLARD6d0f6bc2008-10-16 15:01:15 +0200780 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb3309902008-03-28 10:00:33 +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-VILLARD6d0f6bc2008-10-16 15:01:15 +0200795 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb3309902008-03-28 10:00:33 +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-VILLARD6d0f6bc2008-10-16 15:01:15 +0200814 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb3309902008-03-28 10:00:33 +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-VILLARD6d0f6bc2008-10-16 15:01:15 +0200830 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb3309902008-03-28 10:00:33 +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-VILLARD6d0f6bc2008-10-16 15:01:15 +0200853 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
Daniel Hellstromb3309902008-03-28 10:00:33 +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-VILLARD6d0f6bc2008-10-16 15:01:15 +0200909 pspi->totphys.num_bytes = CONFIG_SYS_PROM_OFFSET - CONFIG_SYS_SDRAM_BASE;
Daniel Hellstromb3309902008-03-28 10:00:33 +0100910 pspi->avail.num_bytes = pspi->totphys.num_bytes;
911
912#undef nodes
913 pspi->nodes[3].level = -1;
914 pspi->nodes[3].properties = __va(spi.root_properties + 3);
915
916 /* Set Ethernet MAC address from environment */
917 if ((addr_str = getenv("ethaddr")) != NULL) {
918 for (i = 0; i < 6; i++) {
919 pspi->idprom.id_ethaddr[i] = addr_str ?
920 simple_strtoul(addr_str, &end, 16) : 0;
921 if (addr_str) {
922 addr_str = (*end) ? end + 1 : end;
923 }
924 }
925 } else {
926 /* HW Address not found in environment,
927 * Set default HW address
928 */
929 pspi->idprom.id_ethaddr[0] = 0;
930 pspi->idprom.id_ethaddr[1] = 0;
931 pspi->idprom.id_ethaddr[2] = 0;
932 pspi->idprom.id_ethaddr[3] = 0;
933 pspi->idprom.id_ethaddr[4] = 0;
934 pspi->idprom.id_ethaddr[5] = 0;
935 }
936
937 ptr = (unsigned char *)&pspi->idprom;
938 for (i = cksum = 0; i <= 0x0E; i++)
939 cksum ^= *ptr++;
940 pspi->idprom.id_cksum = cksum;
941}
942
943static inline void set_cache(unsigned long regval)
944{
945 asm volatile ("sta %0, [%%g0] %1\n\t":: "r" (regval), "i"(2):"memory");
946}
947
948extern unsigned short bss_start, bss_end;
949
950/* mark as section .img.main.text, to be referenced in linker script */
951int prom_init(void)
952{
953 struct leon_prom_info *pspi = (void *)
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200954 ((((unsigned int)&spi) & PROM_SIZE_MASK) + CONFIG_SYS_PROM_OFFSET);
Daniel Hellstromb3309902008-03-28 10:00:33 +0100955
956 /* disable mmu */
957 srmmu_set_mmureg(0x00000000);
958 __asm__ __volatile__("flush\n\t");
959
960 /* init prom info struct */
961 leon_prom_init(pspi);
962
963 kernel_arg_promvec = &pspi->romvec;
964#ifdef PRINT_ROM_VEC
965 printf("Kernel rom vec: 0x%lx\n", (unsigned int)(&pspi->romvec));
966#endif
967 return 0;
968}
969
970/* Copy current kernel boot argument to ROMvec */
971void prepare_bootargs(char *bootargs)
972{
973 struct leon_prom_info *pspi;
974 char *src, *dst;
975 int left;
976
977 /* if no bootargs set, skip copying ==> default bootline */
978 if (bootargs && (*bootargs != '\0')) {
979 pspi = (void *)((((unsigned int)&spi) & PROM_SIZE_MASK) +
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200980 CONFIG_SYS_PROM_OFFSET);
Daniel Hellstromb3309902008-03-28 10:00:33 +0100981 src = bootargs;
982 dst = &pspi->arg[0];
983 left = 255; /* max len */
984 while (*src && left > 0) {
985 *dst++ = *src++;
986 left--;
987 }
988 /* terminate kernel command line string */
989 *dst = 0;
990 }
991}
992
993void srmmu_init_cpu(unsigned int entry)
994{
995 sparc_srmmu_setup *psrmmu_tables = (void *)
996 ((((unsigned int)&srmmu_tables) & PROM_SIZE_MASK) +
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200997 CONFIG_SYS_PROM_OFFSET);
Daniel Hellstromb3309902008-03-28 10:00:33 +0100998
999 /* Make context 0 (kernel's context) point
1000 * to our prepared memory mapping
1001 */
1002#define PTD 1
1003 psrmmu_tables->ctx_table[0] =
1004 ((unsigned int)&psrmmu_tables->pgd_table[0x00]) >> 4 | PTD;
1005
1006 /* Set virtual kernel address 0xf0000000
1007 * to SRAM/SDRAM address.
1008 * Make it READ/WRITE/EXEC to SuperUser
1009 */
1010#define PTE 2
1011#define ACC_SU_ALL 0x1c
1012 psrmmu_tables->pgd_table[0xf0] =
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001013 (CONFIG_SYS_SDRAM_BASE >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb3309902008-03-28 10:00:33 +01001014 psrmmu_tables->pgd_table[0xf1] =
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001015 ((CONFIG_SYS_SDRAM_BASE + 0x1000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb3309902008-03-28 10:00:33 +01001016 psrmmu_tables->pgd_table[0xf2] =
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001017 ((CONFIG_SYS_SDRAM_BASE + 0x2000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb3309902008-03-28 10:00:33 +01001018 psrmmu_tables->pgd_table[0xf3] =
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001019 ((CONFIG_SYS_SDRAM_BASE + 0x3000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb3309902008-03-28 10:00:33 +01001020 psrmmu_tables->pgd_table[0xf4] =
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001021 ((CONFIG_SYS_SDRAM_BASE + 0x4000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb3309902008-03-28 10:00:33 +01001022 psrmmu_tables->pgd_table[0xf5] =
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001023 ((CONFIG_SYS_SDRAM_BASE + 0x5000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb3309902008-03-28 10:00:33 +01001024 psrmmu_tables->pgd_table[0xf6] =
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001025 ((CONFIG_SYS_SDRAM_BASE + 0x6000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb3309902008-03-28 10:00:33 +01001026 psrmmu_tables->pgd_table[0xf7] =
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001027 ((CONFIG_SYS_SDRAM_BASE + 0x7000000) >> 4) | ACC_SU_ALL | PTE;
Daniel Hellstromb3309902008-03-28 10:00:33 +01001028
1029 /* convert rom vec pointer to virtual address */
1030 kernel_arg_promvec = (struct linux_romvec *)
1031 (((unsigned int)kernel_arg_promvec & 0x0fffffff) | 0xf0000000);
1032
1033 /* Set Context pointer to point to context table
1034 * 256 contexts supported.
1035 */
1036 srmmu_set_ctable_ptr((unsigned int)&psrmmu_tables->ctx_table[0]);
1037
1038 /* Set kernel's context, context zero */
1039 srmmu_set_context(0);
1040
1041 /* Invalidate all Cache */
1042 __asm__ __volatile__("flush\n\t");
1043
1044 srmmu_set_mmureg(0x00000001);
1045 leon_flush_tlb_all();
1046 leon_flush_cache_all();
1047}