xref: /openbmc/linux/arch/xtensa/kernel/setup.c (revision c4ee0af3)
1 /*
2  * arch/xtensa/kernel/setup.c
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License.  See the file "COPYING" in the main directory of this archive
6  * for more details.
7  *
8  * Copyright (C) 1995  Linus Torvalds
9  * Copyright (C) 2001 - 2005  Tensilica Inc.
10  *
11  * Chris Zankel	<chris@zankel.net>
12  * Joe Taylor	<joe@tensilica.com, joetylr@yahoo.com>
13  * Kevin Chea
14  * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
15  */
16 
17 #include <linux/errno.h>
18 #include <linux/init.h>
19 #include <linux/mm.h>
20 #include <linux/proc_fs.h>
21 #include <linux/screen_info.h>
22 #include <linux/bootmem.h>
23 #include <linux/kernel.h>
24 #include <linux/of_fdt.h>
25 #include <linux/of_platform.h>
26 
27 #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
28 # include <linux/console.h>
29 #endif
30 
31 #ifdef CONFIG_RTC
32 # include <linux/timex.h>
33 #endif
34 
35 #ifdef CONFIG_PROC_FS
36 # include <linux/seq_file.h>
37 #endif
38 
39 #include <asm/bootparam.h>
40 #include <asm/pgtable.h>
41 #include <asm/processor.h>
42 #include <asm/timex.h>
43 #include <asm/platform.h>
44 #include <asm/page.h>
45 #include <asm/setup.h>
46 #include <asm/param.h>
47 #include <asm/traps.h>
48 
49 #include <platform/hardware.h>
50 
51 #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
52 struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16};
53 #endif
54 
55 #ifdef CONFIG_BLK_DEV_FD
56 extern struct fd_ops no_fd_ops;
57 struct fd_ops *fd_ops;
58 #endif
59 
60 extern struct rtc_ops no_rtc_ops;
61 struct rtc_ops *rtc_ops;
62 
63 #ifdef CONFIG_BLK_DEV_INITRD
64 extern unsigned long initrd_start;
65 extern unsigned long initrd_end;
66 int initrd_is_mapped = 0;
67 extern int initrd_below_start_ok;
68 #endif
69 
70 #ifdef CONFIG_OF
71 extern u32 __dtb_start[];
72 void *dtb_start = __dtb_start;
73 #endif
74 
75 unsigned char aux_device_present;
76 extern unsigned long loops_per_jiffy;
77 
78 /* Command line specified as configuration option. */
79 
80 static char __initdata command_line[COMMAND_LINE_SIZE];
81 
82 #ifdef CONFIG_CMDLINE_BOOL
83 static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
84 #endif
85 
86 sysmem_info_t __initdata sysmem;
87 
88 #ifdef CONFIG_MMU
89 extern void init_mmu(void);
90 #else
91 static inline void init_mmu(void) { }
92 #endif
93 
94 extern int mem_reserve(unsigned long, unsigned long, int);
95 extern void bootmem_init(void);
96 extern void zones_init(void);
97 
98 /*
99  * Boot parameter parsing.
100  *
101  * The Xtensa port uses a list of variable-sized tags to pass data to
102  * the kernel. The first tag must be a BP_TAG_FIRST tag for the list
103  * to be recognised. The list is terminated with a zero-sized
104  * BP_TAG_LAST tag.
105  */
106 
107 typedef struct tagtable {
108 	u32 tag;
109 	int (*parse)(const bp_tag_t*);
110 } tagtable_t;
111 
112 #define __tagtable(tag, fn) static tagtable_t __tagtable_##fn 		\
113 	__attribute__((used, section(".taglist"))) = { tag, fn }
114 
115 /* parse current tag */
116 
117 static int __init add_sysmem_bank(unsigned long type, unsigned long start,
118 		unsigned long end)
119 {
120 	if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
121 		printk(KERN_WARNING
122 				"Ignoring memory bank 0x%08lx size %ldKB\n",
123 				start, end - start);
124 		return -EINVAL;
125 	}
126 	sysmem.bank[sysmem.nr_banks].type  = type;
127 	sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(start);
128 	sysmem.bank[sysmem.nr_banks].end   = end & PAGE_MASK;
129 	sysmem.nr_banks++;
130 
131 	return 0;
132 }
133 
134 static int __init parse_tag_mem(const bp_tag_t *tag)
135 {
136 	meminfo_t *mi = (meminfo_t *)(tag->data);
137 
138 	if (mi->type != MEMORY_TYPE_CONVENTIONAL)
139 		return -1;
140 
141 	return add_sysmem_bank(mi->type, mi->start, mi->end);
142 }
143 
144 __tagtable(BP_TAG_MEMORY, parse_tag_mem);
145 
146 #ifdef CONFIG_BLK_DEV_INITRD
147 
148 static int __init parse_tag_initrd(const bp_tag_t* tag)
149 {
150 	meminfo_t* mi;
151 	mi = (meminfo_t*)(tag->data);
152 	initrd_start = (unsigned long)__va(mi->start);
153 	initrd_end = (unsigned long)__va(mi->end);
154 
155 	return 0;
156 }
157 
158 __tagtable(BP_TAG_INITRD, parse_tag_initrd);
159 
160 #ifdef CONFIG_OF
161 
162 static int __init parse_tag_fdt(const bp_tag_t *tag)
163 {
164 	dtb_start = __va(tag->data[0]);
165 	return 0;
166 }
167 
168 __tagtable(BP_TAG_FDT, parse_tag_fdt);
169 
170 #endif /* CONFIG_OF */
171 
172 #endif /* CONFIG_BLK_DEV_INITRD */
173 
174 static int __init parse_tag_cmdline(const bp_tag_t* tag)
175 {
176 	strlcpy(command_line, (char *)(tag->data), COMMAND_LINE_SIZE);
177 	return 0;
178 }
179 
180 __tagtable(BP_TAG_COMMAND_LINE, parse_tag_cmdline);
181 
182 static int __init parse_bootparam(const bp_tag_t* tag)
183 {
184 	extern tagtable_t __tagtable_begin, __tagtable_end;
185 	tagtable_t *t;
186 
187 	/* Boot parameters must start with a BP_TAG_FIRST tag. */
188 
189 	if (tag->id != BP_TAG_FIRST) {
190 		printk(KERN_WARNING "Invalid boot parameters!\n");
191 		return 0;
192 	}
193 
194 	tag = (bp_tag_t*)((unsigned long)tag + sizeof(bp_tag_t) + tag->size);
195 
196 	/* Parse all tags. */
197 
198 	while (tag != NULL && tag->id != BP_TAG_LAST) {
199 	 	for (t = &__tagtable_begin; t < &__tagtable_end; t++) {
200 			if (tag->id == t->tag) {
201 				t->parse(tag);
202 				break;
203 			}
204 		}
205 		if (t == &__tagtable_end)
206 			printk(KERN_WARNING "Ignoring tag "
207 			       "0x%08x\n", tag->id);
208 		tag = (bp_tag_t*)((unsigned long)(tag + 1) + tag->size);
209 	}
210 
211 	return 0;
212 }
213 
214 #ifdef CONFIG_OF
215 bool __initdata dt_memory_scan = false;
216 
217 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
218 {
219 	if (!dt_memory_scan)
220 		return;
221 
222 	size &= PAGE_MASK;
223 	add_sysmem_bank(MEMORY_TYPE_CONVENTIONAL, base, base + size);
224 }
225 
226 void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
227 {
228 	return __alloc_bootmem(size, align, 0);
229 }
230 
231 void __init early_init_devtree(void *params)
232 {
233 	if (sysmem.nr_banks == 0)
234 		dt_memory_scan = true;
235 
236 	early_init_dt_scan(params);
237 
238 	if (!command_line[0])
239 		strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
240 }
241 
242 static int __init xtensa_device_probe(void)
243 {
244 	of_platform_populate(NULL, NULL, NULL, NULL);
245 	return 0;
246 }
247 
248 device_initcall(xtensa_device_probe);
249 
250 #endif /* CONFIG_OF */
251 
252 /*
253  * Initialize architecture. (Early stage)
254  */
255 
256 void __init init_arch(bp_tag_t *bp_start)
257 {
258 	sysmem.nr_banks = 0;
259 
260 	/* Parse boot parameters */
261 
262 	if (bp_start)
263 		parse_bootparam(bp_start);
264 
265 #ifdef CONFIG_OF
266 	early_init_devtree(dtb_start);
267 #endif
268 
269 	if (sysmem.nr_banks == 0) {
270 		sysmem.nr_banks = 1;
271 		sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START;
272 		sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START
273 				     + PLATFORM_DEFAULT_MEM_SIZE;
274 	}
275 
276 #ifdef CONFIG_CMDLINE_BOOL
277 	if (!command_line[0])
278 		strlcpy(command_line, default_command_line, COMMAND_LINE_SIZE);
279 #endif
280 
281 	/* Early hook for platforms */
282 
283 	platform_init(bp_start);
284 
285 	/* Initialize MMU. */
286 
287 	init_mmu();
288 }
289 
290 /*
291  * Initialize system. Setup memory and reserve regions.
292  */
293 
294 extern char _end;
295 extern char _stext;
296 extern char _WindowVectors_text_start;
297 extern char _WindowVectors_text_end;
298 extern char _DebugInterruptVector_literal_start;
299 extern char _DebugInterruptVector_text_end;
300 extern char _KernelExceptionVector_literal_start;
301 extern char _KernelExceptionVector_text_end;
302 extern char _UserExceptionVector_literal_start;
303 extern char _UserExceptionVector_text_end;
304 extern char _DoubleExceptionVector_literal_start;
305 extern char _DoubleExceptionVector_text_end;
306 #if XCHAL_EXCM_LEVEL >= 2
307 extern char _Level2InterruptVector_text_start;
308 extern char _Level2InterruptVector_text_end;
309 #endif
310 #if XCHAL_EXCM_LEVEL >= 3
311 extern char _Level3InterruptVector_text_start;
312 extern char _Level3InterruptVector_text_end;
313 #endif
314 #if XCHAL_EXCM_LEVEL >= 4
315 extern char _Level4InterruptVector_text_start;
316 extern char _Level4InterruptVector_text_end;
317 #endif
318 #if XCHAL_EXCM_LEVEL >= 5
319 extern char _Level5InterruptVector_text_start;
320 extern char _Level5InterruptVector_text_end;
321 #endif
322 #if XCHAL_EXCM_LEVEL >= 6
323 extern char _Level6InterruptVector_text_start;
324 extern char _Level6InterruptVector_text_end;
325 #endif
326 
327 
328 
329 #ifdef CONFIG_S32C1I_SELFTEST
330 #if XCHAL_HAVE_S32C1I
331 
332 static int __initdata rcw_word, rcw_probe_pc, rcw_exc;
333 
334 /*
335  * Basic atomic compare-and-swap, that records PC of S32C1I for probing.
336  *
337  * If *v == cmp, set *v = set.  Return previous *v.
338  */
339 static inline int probed_compare_swap(int *v, int cmp, int set)
340 {
341 	int tmp;
342 
343 	__asm__ __volatile__(
344 			"	movi	%1, 1f\n"
345 			"	s32i	%1, %4, 0\n"
346 			"	wsr	%2, scompare1\n"
347 			"1:	s32c1i	%0, %3, 0\n"
348 			: "=a" (set), "=&a" (tmp)
349 			: "a" (cmp), "a" (v), "a" (&rcw_probe_pc), "0" (set)
350 			: "memory"
351 			);
352 	return set;
353 }
354 
355 /* Handle probed exception */
356 
357 void __init do_probed_exception(struct pt_regs *regs, unsigned long exccause)
358 {
359 	if (regs->pc == rcw_probe_pc) {	/* exception on s32c1i ? */
360 		regs->pc += 3;		/* skip the s32c1i instruction */
361 		rcw_exc = exccause;
362 	} else {
363 		do_unhandled(regs, exccause);
364 	}
365 }
366 
367 /* Simple test of S32C1I (soc bringup assist) */
368 
369 void __init check_s32c1i(void)
370 {
371 	int n, cause1, cause2;
372 	void *handbus, *handdata, *handaddr; /* temporarily saved handlers */
373 
374 	rcw_probe_pc = 0;
375 	handbus  = trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR,
376 			do_probed_exception);
377 	handdata = trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR,
378 			do_probed_exception);
379 	handaddr = trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR,
380 			do_probed_exception);
381 
382 	/* First try an S32C1I that does not store: */
383 	rcw_exc = 0;
384 	rcw_word = 1;
385 	n = probed_compare_swap(&rcw_word, 0, 2);
386 	cause1 = rcw_exc;
387 
388 	/* took exception? */
389 	if (cause1 != 0) {
390 		/* unclean exception? */
391 		if (n != 2 || rcw_word != 1)
392 			panic("S32C1I exception error");
393 	} else if (rcw_word != 1 || n != 1) {
394 		panic("S32C1I compare error");
395 	}
396 
397 	/* Then an S32C1I that stores: */
398 	rcw_exc = 0;
399 	rcw_word = 0x1234567;
400 	n = probed_compare_swap(&rcw_word, 0x1234567, 0xabcde);
401 	cause2 = rcw_exc;
402 
403 	if (cause2 != 0) {
404 		/* unclean exception? */
405 		if (n != 0xabcde || rcw_word != 0x1234567)
406 			panic("S32C1I exception error (b)");
407 	} else if (rcw_word != 0xabcde || n != 0x1234567) {
408 		panic("S32C1I store error");
409 	}
410 
411 	/* Verify consistency of exceptions: */
412 	if (cause1 || cause2) {
413 		pr_warn("S32C1I took exception %d, %d\n", cause1, cause2);
414 		/* If emulation of S32C1I upon bus error gets implemented,
415 		   we can get rid of this panic for single core (not SMP) */
416 		panic("S32C1I exceptions not currently supported");
417 	}
418 	if (cause1 != cause2)
419 		panic("inconsistent S32C1I exceptions");
420 
421 	trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR, handbus);
422 	trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR, handdata);
423 	trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR, handaddr);
424 }
425 
426 #else /* XCHAL_HAVE_S32C1I */
427 
428 /* This condition should not occur with a commercially deployed processor.
429    Display reminder for early engr test or demo chips / FPGA bitstreams */
430 void __init check_s32c1i(void)
431 {
432 	pr_warn("Processor configuration lacks atomic compare-and-swap support!\n");
433 }
434 
435 #endif /* XCHAL_HAVE_S32C1I */
436 #else /* CONFIG_S32C1I_SELFTEST */
437 
438 void __init check_s32c1i(void)
439 {
440 }
441 
442 #endif /* CONFIG_S32C1I_SELFTEST */
443 
444 
445 void __init setup_arch(char **cmdline_p)
446 {
447 	strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
448 	*cmdline_p = command_line;
449 
450 	check_s32c1i();
451 
452 	/* Reserve some memory regions */
453 
454 #ifdef CONFIG_BLK_DEV_INITRD
455 	if (initrd_start < initrd_end) {
456 		initrd_is_mapped = mem_reserve(__pa(initrd_start),
457 					       __pa(initrd_end), 0);
458 		initrd_below_start_ok = 1;
459 	} else {
460 		initrd_start = 0;
461 	}
462 #endif
463 
464 	mem_reserve(__pa(&_stext),__pa(&_end), 1);
465 
466 	mem_reserve(__pa(&_WindowVectors_text_start),
467 		    __pa(&_WindowVectors_text_end), 0);
468 
469 	mem_reserve(__pa(&_DebugInterruptVector_literal_start),
470 		    __pa(&_DebugInterruptVector_text_end), 0);
471 
472 	mem_reserve(__pa(&_KernelExceptionVector_literal_start),
473 		    __pa(&_KernelExceptionVector_text_end), 0);
474 
475 	mem_reserve(__pa(&_UserExceptionVector_literal_start),
476 		    __pa(&_UserExceptionVector_text_end), 0);
477 
478 	mem_reserve(__pa(&_DoubleExceptionVector_literal_start),
479 		    __pa(&_DoubleExceptionVector_text_end), 0);
480 
481 #if XCHAL_EXCM_LEVEL >= 2
482 	mem_reserve(__pa(&_Level2InterruptVector_text_start),
483 		    __pa(&_Level2InterruptVector_text_end), 0);
484 #endif
485 #if XCHAL_EXCM_LEVEL >= 3
486 	mem_reserve(__pa(&_Level3InterruptVector_text_start),
487 		    __pa(&_Level3InterruptVector_text_end), 0);
488 #endif
489 #if XCHAL_EXCM_LEVEL >= 4
490 	mem_reserve(__pa(&_Level4InterruptVector_text_start),
491 		    __pa(&_Level4InterruptVector_text_end), 0);
492 #endif
493 #if XCHAL_EXCM_LEVEL >= 5
494 	mem_reserve(__pa(&_Level5InterruptVector_text_start),
495 		    __pa(&_Level5InterruptVector_text_end), 0);
496 #endif
497 #if XCHAL_EXCM_LEVEL >= 6
498 	mem_reserve(__pa(&_Level6InterruptVector_text_start),
499 		    __pa(&_Level6InterruptVector_text_end), 0);
500 #endif
501 
502 	bootmem_init();
503 
504 	unflatten_and_copy_device_tree();
505 
506 	platform_setup(cmdline_p);
507 
508 	paging_init();
509 	zones_init();
510 
511 #ifdef CONFIG_VT
512 # if defined(CONFIG_VGA_CONSOLE)
513 	conswitchp = &vga_con;
514 # elif defined(CONFIG_DUMMY_CONSOLE)
515 	conswitchp = &dummy_con;
516 # endif
517 #endif
518 
519 #ifdef CONFIG_PCI
520 	platform_pcibios_init();
521 #endif
522 }
523 
524 void machine_restart(char * cmd)
525 {
526 	platform_restart();
527 }
528 
529 void machine_halt(void)
530 {
531 	platform_halt();
532 	while (1);
533 }
534 
535 void machine_power_off(void)
536 {
537 	platform_power_off();
538 	while (1);
539 }
540 #ifdef CONFIG_PROC_FS
541 
542 /*
543  * Display some core information through /proc/cpuinfo.
544  */
545 
546 static int
547 c_show(struct seq_file *f, void *slot)
548 {
549 	/* high-level stuff */
550 	seq_printf(f,"processor\t: 0\n"
551 		     "vendor_id\t: Tensilica\n"
552 		     "model\t\t: Xtensa " XCHAL_HW_VERSION_NAME "\n"
553 		     "core ID\t\t: " XCHAL_CORE_ID "\n"
554 		     "build ID\t: 0x%x\n"
555 		     "byte order\t: %s\n"
556 		     "cpu MHz\t\t: %lu.%02lu\n"
557 		     "bogomips\t: %lu.%02lu\n",
558 		     XCHAL_BUILD_UNIQUE_ID,
559 		     XCHAL_HAVE_BE ?  "big" : "little",
560 		     ccount_freq/1000000,
561 		     (ccount_freq/10000) % 100,
562 		     loops_per_jiffy/(500000/HZ),
563 		     (loops_per_jiffy/(5000/HZ)) % 100);
564 
565 	seq_printf(f,"flags\t\t: "
566 #if XCHAL_HAVE_NMI
567 		     "nmi "
568 #endif
569 #if XCHAL_HAVE_DEBUG
570 		     "debug "
571 # if XCHAL_HAVE_OCD
572 		     "ocd "
573 # endif
574 #endif
575 #if XCHAL_HAVE_DENSITY
576 	    	     "density "
577 #endif
578 #if XCHAL_HAVE_BOOLEANS
579 		     "boolean "
580 #endif
581 #if XCHAL_HAVE_LOOPS
582 		     "loop "
583 #endif
584 #if XCHAL_HAVE_NSA
585 		     "nsa "
586 #endif
587 #if XCHAL_HAVE_MINMAX
588 		     "minmax "
589 #endif
590 #if XCHAL_HAVE_SEXT
591 		     "sext "
592 #endif
593 #if XCHAL_HAVE_CLAMPS
594 		     "clamps "
595 #endif
596 #if XCHAL_HAVE_MAC16
597 		     "mac16 "
598 #endif
599 #if XCHAL_HAVE_MUL16
600 		     "mul16 "
601 #endif
602 #if XCHAL_HAVE_MUL32
603 		     "mul32 "
604 #endif
605 #if XCHAL_HAVE_MUL32_HIGH
606 		     "mul32h "
607 #endif
608 #if XCHAL_HAVE_FP
609 		     "fpu "
610 #endif
611 #if XCHAL_HAVE_S32C1I
612 		     "s32c1i "
613 #endif
614 		     "\n");
615 
616 	/* Registers. */
617 	seq_printf(f,"physical aregs\t: %d\n"
618 		     "misc regs\t: %d\n"
619 		     "ibreak\t\t: %d\n"
620 		     "dbreak\t\t: %d\n",
621 		     XCHAL_NUM_AREGS,
622 		     XCHAL_NUM_MISC_REGS,
623 		     XCHAL_NUM_IBREAK,
624 		     XCHAL_NUM_DBREAK);
625 
626 
627 	/* Interrupt. */
628 	seq_printf(f,"num ints\t: %d\n"
629 		     "ext ints\t: %d\n"
630 		     "int levels\t: %d\n"
631 		     "timers\t\t: %d\n"
632 		     "debug level\t: %d\n",
633 		     XCHAL_NUM_INTERRUPTS,
634 		     XCHAL_NUM_EXTINTERRUPTS,
635 		     XCHAL_NUM_INTLEVELS,
636 		     XCHAL_NUM_TIMERS,
637 		     XCHAL_DEBUGLEVEL);
638 
639 	/* Cache */
640 	seq_printf(f,"icache line size: %d\n"
641 		     "icache ways\t: %d\n"
642 		     "icache size\t: %d\n"
643 		     "icache flags\t: "
644 #if XCHAL_ICACHE_LINE_LOCKABLE
645 		     "lock "
646 #endif
647 		     "\n"
648 		     "dcache line size: %d\n"
649 		     "dcache ways\t: %d\n"
650 		     "dcache size\t: %d\n"
651 		     "dcache flags\t: "
652 #if XCHAL_DCACHE_IS_WRITEBACK
653 		     "writeback "
654 #endif
655 #if XCHAL_DCACHE_LINE_LOCKABLE
656 		     "lock "
657 #endif
658 		     "\n",
659 		     XCHAL_ICACHE_LINESIZE,
660 		     XCHAL_ICACHE_WAYS,
661 		     XCHAL_ICACHE_SIZE,
662 		     XCHAL_DCACHE_LINESIZE,
663 		     XCHAL_DCACHE_WAYS,
664 		     XCHAL_DCACHE_SIZE);
665 
666 	return 0;
667 }
668 
669 /*
670  * We show only CPU #0 info.
671  */
672 static void *
673 c_start(struct seq_file *f, loff_t *pos)
674 {
675 	return (void *) ((*pos == 0) ? (void *)1 : NULL);
676 }
677 
678 static void *
679 c_next(struct seq_file *f, void *v, loff_t *pos)
680 {
681 	return NULL;
682 }
683 
684 static void
685 c_stop(struct seq_file *f, void *v)
686 {
687 }
688 
689 const struct seq_operations cpuinfo_op =
690 {
691 	start:  c_start,
692 	next:   c_next,
693 	stop:   c_stop,
694 	show:   c_show
695 };
696 
697 #endif /* CONFIG_PROC_FS */
698