1 /* 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 */
40 extern struct linux_romvec *kernel_arg_promvec;
41 extern 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 
47 ambapp_dev_gptimer *gptimer;
48 
49 /* for __va */
50 extern int __prom_start;
51 #define PAGE_OFFSET 0xf0000000
52 #define phys_base CONFIG_SYS_SDRAM_BASE
53 #define PROM_OFFS 8192
54 #define PROM_SIZE_MASK (PROM_OFFS-1)
55 #define __va(x) ( \
56 	(void *)( ((unsigned long)(x))-PROM_OFFS+ \
57 	(CONFIG_SYS_PROM_OFFSET-phys_base)+PAGE_OFFSET-TEXT_BASE ) \
58 	)
59 #define __phy(x) ((void *)(((unsigned long)(x))-PROM_OFFS+CONFIG_SYS_PROM_OFFSET-TEXT_BASE))
60 
61 struct property {
62 	char *name;
63 	char *value;
64 	int length;
65 };
66 
67 struct node {
68 	int level;
69 	struct property *properties;
70 };
71 
72 static void leon_reboot(char *bcommand);
73 static void leon_halt(void);
74 static int leon_nbputchar(int c);
75 static int leon_nbgetchar(void);
76 
77 static int no_nextnode(int node);
78 static int no_child(int node);
79 static int no_proplen(int node, char *name);
80 static int no_getprop(int node, char *name, char *value);
81 static int no_setprop(int node, char *name, char *value, int len);
82 static char *no_nextprop(int node, char *name);
83 
84 static struct property PROM_TEXT *find_property(int node, char *name);
85 static int PROM_TEXT leon_strcmp(const char *s1, const char *s2);
86 static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n);
87 static void PROM_TEXT leon_reboot_physical(char *bcommand);
88 
leon_flush_cache_all(void)89 void __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 
leon_flush_tlb_all(void)95 void __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 
102 typedef struct {
103 	unsigned int ctx_table[256];
104 	unsigned int pgd_table[256];
105 } sparc_srmmu_setup;
106 
107 sparc_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 */
354 struct 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 
362 struct 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 */
429 static 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,
548 	 (char *)CONFIG_SYS_SDRAM_BASE,
549 	 0,
550 	 },
551 	__va(&spi.avail),
552 	{
553 	 NULL,
554 	 (char *)CONFIG_SYS_SDRAM_BASE,
555 	 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
642 extern unsigned short root_flags;
643 extern unsigned short root_dev;
644 extern unsigned short ram_flags;
645 extern unsigned int sparc_ramdisk_image;
646 extern unsigned int sparc_ramdisk_size;
647 extern int root_mountflags;
648 
649 extern 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  */
leon_reboot(char * bcommand)655 static 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 =
662 	    (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
663 
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 
leon_reboot_physical(char * bcommand)707 static 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 */
715 	reset = CONFIG_SYS_MONITOR_BASE;
716 
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 
leon_halt(void)727 static void PROM_TEXT leon_halt(void)
728 {
729 	while (1) ;
730 }
731 
732 /* get single char, don't care for blocking*/
leon_nbgetchar(void)733 static int PROM_TEXT leon_nbgetchar(void)
734 {
735 	return -1;
736 }
737 
738 /* put single char, don't care for blocking*/
leon_nbputchar(int c)739 static int PROM_TEXT leon_nbputchar(int c)
740 {
741 	ambapp_dev_apbuart *uart;
742 
743 	/* get physical address */
744 	struct leon_prom_info *pspi =
745 	    (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
746 
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 
no_nextnode(int node)777 static int PROM_TEXT no_nextnode(int node)
778 {
779 	/* get physical address */
780 	struct leon_prom_info *pspi =
781 	    (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
782 
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 
no_child(int node)792 static int PROM_TEXT no_child(int node)
793 {
794 	/* get physical address */
795 	struct leon_prom_info *pspi = (struct leon_prom_info *)
796 	    (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
797 
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 
find_property(int node,char * name)807 static 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 *)
811 	    (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
812 
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 
no_proplen(int node,char * name)826 static int PROM_TEXT no_proplen(int node, char *name)
827 {
828 	/* get physical address */
829 	struct leon_prom_info *pspi = (struct leon_prom_info *)
830 	    (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
831 
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 
no_getprop(int node,char * name,char * value)842 static 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 *)
846 	    (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
847 
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 
no_setprop(int node,char * name,char * value,int len)860 static int PROM_TEXT no_setprop(int node, char *name, char *value, int len)
861 {
862 	return -1;
863 }
864 
no_nextprop(int node,char * name)865 static char PROM_TEXT *no_nextprop(int node, char *name)
866 {
867 	/* get physical address */
868 	struct leon_prom_info *pspi = (struct leon_prom_info *)
869 	    (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
870 	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 
leon_strcmp(const char * s1,const char * s2)885 static 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 
leon_memcpy(void * dest,const void * src,size_t n)900 static 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 
leon_prom_init(struct leon_prom_info * pspi)914 void 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 */
925 	pspi->totphys.num_bytes = CONFIG_SYS_PROM_OFFSET - CONFIG_SYS_SDRAM_BASE;
926 	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 
set_cache(unsigned long regval)974 static inline void set_cache(unsigned long regval)
975 {
976 	asm volatile ("sta %0, [%%g0] %1\n\t":: "r" (regval), "i"(2):"memory");
977 }
978 
979 extern unsigned short bss_start, bss_end;
980 
981 /* mark as section .img.main.text, to be referenced in linker script */
prom_init(void)982 int prom_init(void)
983 {
984 	struct leon_prom_info *pspi = (void *)
985 	    ((((unsigned int)&spi) & PROM_SIZE_MASK) + CONFIG_SYS_PROM_OFFSET);
986 
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 */
prepare_bootargs(char * bootargs)1002 void 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) +
1011 				CONFIG_SYS_PROM_OFFSET);
1012 		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 
srmmu_init_cpu(unsigned int entry)1024 void srmmu_init_cpu(unsigned int entry)
1025 {
1026 	sparc_srmmu_setup *psrmmu_tables = (void *)
1027 	    ((((unsigned int)&srmmu_tables) & PROM_SIZE_MASK) +
1028 	     CONFIG_SYS_PROM_OFFSET);
1029 
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] =
1044 	    (CONFIG_SYS_SDRAM_BASE >> 4) | ACC_SU_ALL | PTE;
1045 	psrmmu_tables->pgd_table[0xf1] =
1046 	    ((CONFIG_SYS_SDRAM_BASE + 0x1000000) >> 4) | ACC_SU_ALL | PTE;
1047 	psrmmu_tables->pgd_table[0xf2] =
1048 	    ((CONFIG_SYS_SDRAM_BASE + 0x2000000) >> 4) | ACC_SU_ALL | PTE;
1049 	psrmmu_tables->pgd_table[0xf3] =
1050 	    ((CONFIG_SYS_SDRAM_BASE + 0x3000000) >> 4) | ACC_SU_ALL | PTE;
1051 	psrmmu_tables->pgd_table[0xf4] =
1052 	    ((CONFIG_SYS_SDRAM_BASE + 0x4000000) >> 4) | ACC_SU_ALL | PTE;
1053 	psrmmu_tables->pgd_table[0xf5] =
1054 	    ((CONFIG_SYS_SDRAM_BASE + 0x5000000) >> 4) | ACC_SU_ALL | PTE;
1055 	psrmmu_tables->pgd_table[0xf6] =
1056 	    ((CONFIG_SYS_SDRAM_BASE + 0x6000000) >> 4) | ACC_SU_ALL | PTE;
1057 	psrmmu_tables->pgd_table[0xf7] =
1058 	    ((CONFIG_SYS_SDRAM_BASE + 0x7000000) >> 4) | ACC_SU_ALL | PTE;
1059 
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 }
1079