Commit | Line | Data |
---|---|---|
5a0015d6 | 1 | /* |
f30c2269 | 2 | * arch/xtensa/kernel/setup.c |
5a0015d6 CZ |
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. | |
0e46c111 | 10 | * Copyright (C) 2014 - 2016 Cadence Design Systems Inc. |
5a0015d6 CZ |
11 | * |
12 | * Chris Zankel <chris@zankel.net> | |
13 | * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> | |
14 | * Kevin Chea | |
15 | * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca> | |
16 | */ | |
17 | ||
5a0015d6 CZ |
18 | #include <linux/errno.h> |
19 | #include <linux/init.h> | |
27ac792c | 20 | #include <linux/mm.h> |
5a0015d6 | 21 | #include <linux/proc_fs.h> |
894673ee | 22 | #include <linux/screen_info.h> |
5a0015d6 CZ |
23 | #include <linux/bootmem.h> |
24 | #include <linux/kernel.h> | |
f615136c MF |
25 | #include <linux/percpu.h> |
26 | #include <linux/cpu.h> | |
d02014b2 | 27 | #include <linux/of.h> |
da844a81 | 28 | #include <linux/of_fdt.h> |
da844a81 | 29 | |
5a0015d6 CZ |
30 | #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) |
31 | # include <linux/console.h> | |
32 | #endif | |
33 | ||
5a0015d6 CZ |
34 | #ifdef CONFIG_PROC_FS |
35 | # include <linux/seq_file.h> | |
36 | #endif | |
37 | ||
5a0015d6 | 38 | #include <asm/bootparam.h> |
c8f3a7dc | 39 | #include <asm/mmu_context.h> |
5a0015d6 CZ |
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> | |
de4f6e5b | 46 | #include <asm/param.h> |
f615136c | 47 | #include <asm/smp.h> |
9ba067f9 | 48 | #include <asm/sysmem.h> |
5a0015d6 | 49 | |
5a891ed5 AD |
50 | #include <platform/hardware.h> |
51 | ||
5a0015d6 | 52 | #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) |
03eae3ac MF |
53 | struct screen_info screen_info = { |
54 | .orig_x = 0, | |
55 | .orig_y = 24, | |
56 | .orig_video_cols = 80, | |
57 | .orig_video_lines = 24, | |
58 | .orig_video_isVGA = 1, | |
59 | .orig_video_points = 16, | |
60 | }; | |
5a0015d6 CZ |
61 | #endif |
62 | ||
5a0015d6 | 63 | #ifdef CONFIG_BLK_DEV_INITRD |
29eb45a9 RH |
64 | extern unsigned long initrd_start; |
65 | extern unsigned long initrd_end; | |
5a0015d6 CZ |
66 | int initrd_is_mapped = 0; |
67 | extern int initrd_below_start_ok; | |
68 | #endif | |
69 | ||
da844a81 | 70 | #ifdef CONFIG_OF |
da844a81 MF |
71 | void *dtb_start = __dtb_start; |
72 | #endif | |
73 | ||
5a0015d6 CZ |
74 | extern unsigned long loops_per_jiffy; |
75 | ||
76 | /* Command line specified as configuration option. */ | |
77 | ||
d3e9ccea | 78 | static char __initdata command_line[COMMAND_LINE_SIZE]; |
5a0015d6 CZ |
79 | |
80 | #ifdef CONFIG_CMDLINE_BOOL | |
81 | static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; | |
82 | #endif | |
83 | ||
5a0015d6 CZ |
84 | /* |
85 | * Boot parameter parsing. | |
86 | * | |
87 | * The Xtensa port uses a list of variable-sized tags to pass data to | |
88 | * the kernel. The first tag must be a BP_TAG_FIRST tag for the list | |
89 | * to be recognised. The list is terminated with a zero-sized | |
90 | * BP_TAG_LAST tag. | |
91 | */ | |
92 | ||
93 | typedef struct tagtable { | |
94 | u32 tag; | |
95 | int (*parse)(const bp_tag_t*); | |
96 | } tagtable_t; | |
97 | ||
98 | #define __tagtable(tag, fn) static tagtable_t __tagtable_##fn \ | |
f4349b6e | 99 | __attribute__((used, section(".taglist"))) = { tag, fn } |
5a0015d6 CZ |
100 | |
101 | /* parse current tag */ | |
102 | ||
da844a81 MF |
103 | static int __init parse_tag_mem(const bp_tag_t *tag) |
104 | { | |
9ba067f9 | 105 | struct bp_meminfo *mi = (struct bp_meminfo *)(tag->data); |
da844a81 MF |
106 | |
107 | if (mi->type != MEMORY_TYPE_CONVENTIONAL) | |
108 | return -1; | |
109 | ||
0e46c111 | 110 | return memblock_add(mi->start, mi->end - mi->start); |
da844a81 MF |
111 | } |
112 | ||
5a0015d6 CZ |
113 | __tagtable(BP_TAG_MEMORY, parse_tag_mem); |
114 | ||
115 | #ifdef CONFIG_BLK_DEV_INITRD | |
116 | ||
117 | static int __init parse_tag_initrd(const bp_tag_t* tag) | |
118 | { | |
9ba067f9 MF |
119 | struct bp_meminfo *mi = (struct bp_meminfo *)(tag->data); |
120 | ||
29eb45a9 RH |
121 | initrd_start = (unsigned long)__va(mi->start); |
122 | initrd_end = (unsigned long)__va(mi->end); | |
5a0015d6 CZ |
123 | |
124 | return 0; | |
125 | } | |
126 | ||
127 | __tagtable(BP_TAG_INITRD, parse_tag_initrd); | |
128 | ||
da844a81 MF |
129 | #ifdef CONFIG_OF |
130 | ||
131 | static int __init parse_tag_fdt(const bp_tag_t *tag) | |
132 | { | |
c5a771d0 | 133 | dtb_start = __va(tag->data[0]); |
da844a81 MF |
134 | return 0; |
135 | } | |
136 | ||
137 | __tagtable(BP_TAG_FDT, parse_tag_fdt); | |
138 | ||
da844a81 MF |
139 | #endif /* CONFIG_OF */ |
140 | ||
5a0015d6 CZ |
141 | #endif /* CONFIG_BLK_DEV_INITRD */ |
142 | ||
143 | static int __init parse_tag_cmdline(const bp_tag_t* tag) | |
144 | { | |
da844a81 | 145 | strlcpy(command_line, (char *)(tag->data), COMMAND_LINE_SIZE); |
5a0015d6 CZ |
146 | return 0; |
147 | } | |
148 | ||
149 | __tagtable(BP_TAG_COMMAND_LINE, parse_tag_cmdline); | |
150 | ||
151 | static int __init parse_bootparam(const bp_tag_t* tag) | |
152 | { | |
153 | extern tagtable_t __tagtable_begin, __tagtable_end; | |
154 | tagtable_t *t; | |
155 | ||
156 | /* Boot parameters must start with a BP_TAG_FIRST tag. */ | |
157 | ||
158 | if (tag->id != BP_TAG_FIRST) { | |
159 | printk(KERN_WARNING "Invalid boot parameters!\n"); | |
160 | return 0; | |
161 | } | |
162 | ||
163 | tag = (bp_tag_t*)((unsigned long)tag + sizeof(bp_tag_t) + tag->size); | |
164 | ||
165 | /* Parse all tags. */ | |
166 | ||
167 | while (tag != NULL && tag->id != BP_TAG_LAST) { | |
168 | for (t = &__tagtable_begin; t < &__tagtable_end; t++) { | |
169 | if (tag->id == t->tag) { | |
170 | t->parse(tag); | |
171 | break; | |
172 | } | |
173 | } | |
174 | if (t == &__tagtable_end) | |
175 | printk(KERN_WARNING "Ignoring tag " | |
176 | "0x%08x\n", tag->id); | |
177 | tag = (bp_tag_t*)((unsigned long)(tag + 1) + tag->size); | |
178 | } | |
179 | ||
180 | return 0; | |
181 | } | |
182 | ||
da844a81 MF |
183 | #ifdef CONFIG_OF |
184 | ||
260c64bb | 185 | #if !XCHAL_HAVE_PTP_MMU || XCHAL_HAVE_SPANNING_WAY |
6cb97111 BS |
186 | unsigned long xtensa_kio_paddr = XCHAL_KIO_DEFAULT_PADDR; |
187 | EXPORT_SYMBOL(xtensa_kio_paddr); | |
188 | ||
189 | static int __init xtensa_dt_io_area(unsigned long node, const char *uname, | |
190 | int depth, void *data) | |
191 | { | |
192 | const __be32 *ranges; | |
9d0c4dfe | 193 | int len; |
6cb97111 BS |
194 | |
195 | if (depth > 1) | |
196 | return 0; | |
197 | ||
198 | if (!of_flat_dt_is_compatible(node, "simple-bus")) | |
199 | return 0; | |
200 | ||
201 | ranges = of_get_flat_dt_prop(node, "ranges", &len); | |
202 | if (!ranges) | |
203 | return 1; | |
204 | if (len == 0) | |
205 | return 1; | |
206 | ||
207 | xtensa_kio_paddr = of_read_ulong(ranges+1, 1); | |
208 | /* round down to nearest 256MB boundary */ | |
209 | xtensa_kio_paddr &= 0xf0000000; | |
210 | ||
211 | return 1; | |
212 | } | |
213 | #else | |
214 | static int __init xtensa_dt_io_area(unsigned long node, const char *uname, | |
215 | int depth, void *data) | |
216 | { | |
217 | return 1; | |
218 | } | |
219 | #endif | |
220 | ||
da844a81 MF |
221 | void __init early_init_dt_add_memory_arch(u64 base, u64 size) |
222 | { | |
223 | size &= PAGE_MASK; | |
0e46c111 | 224 | memblock_add(base, size); |
da844a81 MF |
225 | } |
226 | ||
227 | void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) | |
228 | { | |
229 | return __alloc_bootmem(size, align, 0); | |
230 | } | |
231 | ||
232 | void __init early_init_devtree(void *params) | |
233 | { | |
7745fc1f | 234 | early_init_dt_scan(params); |
6cb97111 | 235 | of_scan_flat_dt(xtensa_dt_io_area, NULL); |
da844a81 | 236 | |
7745fc1f RH |
237 | if (!command_line[0]) |
238 | strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); | |
da844a81 MF |
239 | } |
240 | ||
da844a81 MF |
241 | #endif /* CONFIG_OF */ |
242 | ||
5a0015d6 CZ |
243 | /* |
244 | * Initialize architecture. (Early stage) | |
245 | */ | |
246 | ||
247 | void __init init_arch(bp_tag_t *bp_start) | |
248 | { | |
5a0015d6 CZ |
249 | /* Parse boot parameters */ |
250 | ||
c4c4594b | 251 | if (bp_start) |
da844a81 MF |
252 | parse_bootparam(bp_start); |
253 | ||
254 | #ifdef CONFIG_OF | |
255 | early_init_devtree(dtb_start); | |
256 | #endif | |
5a0015d6 | 257 | |
da844a81 MF |
258 | #ifdef CONFIG_CMDLINE_BOOL |
259 | if (!command_line[0]) | |
260 | strlcpy(command_line, default_command_line, COMMAND_LINE_SIZE); | |
261 | #endif | |
262 | ||
5a0015d6 CZ |
263 | /* Early hook for platforms */ |
264 | ||
265 | platform_init(bp_start); | |
266 | ||
267 | /* Initialize MMU. */ | |
268 | ||
269 | init_mmu(); | |
270 | } | |
271 | ||
272 | /* | |
273 | * Initialize system. Setup memory and reserve regions. | |
274 | */ | |
275 | ||
276 | extern char _end; | |
277 | extern char _stext; | |
278 | extern char _WindowVectors_text_start; | |
279 | extern char _WindowVectors_text_end; | |
280 | extern char _DebugInterruptVector_literal_start; | |
281 | extern char _DebugInterruptVector_text_end; | |
282 | extern char _KernelExceptionVector_literal_start; | |
283 | extern char _KernelExceptionVector_text_end; | |
284 | extern char _UserExceptionVector_literal_start; | |
285 | extern char _UserExceptionVector_text_end; | |
286 | extern char _DoubleExceptionVector_literal_start; | |
287 | extern char _DoubleExceptionVector_text_end; | |
2d1c645c MG |
288 | #if XCHAL_EXCM_LEVEL >= 2 |
289 | extern char _Level2InterruptVector_text_start; | |
290 | extern char _Level2InterruptVector_text_end; | |
291 | #endif | |
292 | #if XCHAL_EXCM_LEVEL >= 3 | |
293 | extern char _Level3InterruptVector_text_start; | |
294 | extern char _Level3InterruptVector_text_end; | |
295 | #endif | |
296 | #if XCHAL_EXCM_LEVEL >= 4 | |
297 | extern char _Level4InterruptVector_text_start; | |
298 | extern char _Level4InterruptVector_text_end; | |
299 | #endif | |
300 | #if XCHAL_EXCM_LEVEL >= 5 | |
301 | extern char _Level5InterruptVector_text_start; | |
302 | extern char _Level5InterruptVector_text_end; | |
303 | #endif | |
304 | #if XCHAL_EXCM_LEVEL >= 6 | |
305 | extern char _Level6InterruptVector_text_start; | |
306 | extern char _Level6InterruptVector_text_end; | |
307 | #endif | |
ab45fb14 MF |
308 | #ifdef CONFIG_SMP |
309 | extern char _SecondaryResetVector_text_start; | |
310 | extern char _SecondaryResetVector_text_end; | |
311 | #endif | |
5a0015d6 | 312 | |
0e46c111 MF |
313 | static inline int mem_reserve(unsigned long start, unsigned long end) |
314 | { | |
315 | return memblock_reserve(start, end - start); | |
316 | } | |
00273125 | 317 | |
5a0015d6 CZ |
318 | void __init setup_arch(char **cmdline_p) |
319 | { | |
da844a81 | 320 | strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); |
5a0015d6 CZ |
321 | *cmdline_p = command_line; |
322 | ||
323 | /* Reserve some memory regions */ | |
324 | ||
325 | #ifdef CONFIG_BLK_DEV_INITRD | |
326 | if (initrd_start < initrd_end) { | |
327 | initrd_is_mapped = mem_reserve(__pa(initrd_start), | |
0e46c111 | 328 | __pa(initrd_end)) == 0; |
5a0015d6 | 329 | initrd_below_start_ok = 1; |
c4c4594b | 330 | } else { |
5a0015d6 CZ |
331 | initrd_start = 0; |
332 | } | |
333 | #endif | |
334 | ||
0e46c111 | 335 | mem_reserve(__pa(&_stext), __pa(&_end)); |
5a0015d6 CZ |
336 | |
337 | mem_reserve(__pa(&_WindowVectors_text_start), | |
0e46c111 | 338 | __pa(&_WindowVectors_text_end)); |
5a0015d6 CZ |
339 | |
340 | mem_reserve(__pa(&_DebugInterruptVector_literal_start), | |
0e46c111 | 341 | __pa(&_DebugInterruptVector_text_end)); |
5a0015d6 CZ |
342 | |
343 | mem_reserve(__pa(&_KernelExceptionVector_literal_start), | |
0e46c111 | 344 | __pa(&_KernelExceptionVector_text_end)); |
5a0015d6 CZ |
345 | |
346 | mem_reserve(__pa(&_UserExceptionVector_literal_start), | |
0e46c111 | 347 | __pa(&_UserExceptionVector_text_end)); |
5a0015d6 CZ |
348 | |
349 | mem_reserve(__pa(&_DoubleExceptionVector_literal_start), | |
0e46c111 | 350 | __pa(&_DoubleExceptionVector_text_end)); |
5a0015d6 | 351 | |
2d1c645c MG |
352 | #if XCHAL_EXCM_LEVEL >= 2 |
353 | mem_reserve(__pa(&_Level2InterruptVector_text_start), | |
0e46c111 | 354 | __pa(&_Level2InterruptVector_text_end)); |
2d1c645c MG |
355 | #endif |
356 | #if XCHAL_EXCM_LEVEL >= 3 | |
357 | mem_reserve(__pa(&_Level3InterruptVector_text_start), | |
0e46c111 | 358 | __pa(&_Level3InterruptVector_text_end)); |
2d1c645c MG |
359 | #endif |
360 | #if XCHAL_EXCM_LEVEL >= 4 | |
361 | mem_reserve(__pa(&_Level4InterruptVector_text_start), | |
0e46c111 | 362 | __pa(&_Level4InterruptVector_text_end)); |
2d1c645c MG |
363 | #endif |
364 | #if XCHAL_EXCM_LEVEL >= 5 | |
365 | mem_reserve(__pa(&_Level5InterruptVector_text_start), | |
0e46c111 | 366 | __pa(&_Level5InterruptVector_text_end)); |
2d1c645c MG |
367 | #endif |
368 | #if XCHAL_EXCM_LEVEL >= 6 | |
369 | mem_reserve(__pa(&_Level6InterruptVector_text_start), | |
0e46c111 | 370 | __pa(&_Level6InterruptVector_text_end)); |
2d1c645c MG |
371 | #endif |
372 | ||
ab45fb14 MF |
373 | #ifdef CONFIG_SMP |
374 | mem_reserve(__pa(&_SecondaryResetVector_text_start), | |
0e46c111 | 375 | __pa(&_SecondaryResetVector_text_end)); |
ab45fb14 | 376 | #endif |
06bd2824 | 377 | parse_early_param(); |
5a0015d6 CZ |
378 | bootmem_init(); |
379 | ||
3104021c | 380 | unflatten_and_copy_device_tree(); |
5a0015d6 | 381 | |
da844a81 | 382 | platform_setup(cmdline_p); |
5a0015d6 | 383 | |
f615136c MF |
384 | #ifdef CONFIG_SMP |
385 | smp_init_cpus(); | |
386 | #endif | |
387 | ||
5a0015d6 | 388 | paging_init(); |
e5083a63 | 389 | zones_init(); |
5a0015d6 CZ |
390 | |
391 | #ifdef CONFIG_VT | |
392 | # if defined(CONFIG_VGA_CONSOLE) | |
393 | conswitchp = &vga_con; | |
394 | # elif defined(CONFIG_DUMMY_CONSOLE) | |
395 | conswitchp = &dummy_con; | |
396 | # endif | |
397 | #endif | |
398 | ||
288a60cf | 399 | #ifdef CONFIG_PCI |
5a0015d6 CZ |
400 | platform_pcibios_init(); |
401 | #endif | |
402 | } | |
403 | ||
f615136c MF |
404 | static DEFINE_PER_CPU(struct cpu, cpu_data); |
405 | ||
406 | static int __init topology_init(void) | |
407 | { | |
408 | int i; | |
409 | ||
410 | for_each_possible_cpu(i) { | |
411 | struct cpu *cpu = &per_cpu(cpu_data, i); | |
49b424fe | 412 | cpu->hotpluggable = !!i; |
f615136c MF |
413 | register_cpu(cpu, i); |
414 | } | |
415 | ||
416 | return 0; | |
417 | } | |
418 | subsys_initcall(topology_init); | |
419 | ||
4f205687 MF |
420 | void cpu_reset(void) |
421 | { | |
bf15f86b MF |
422 | #if XCHAL_HAVE_PTP_MMU |
423 | local_irq_disable(); | |
424 | /* | |
425 | * We have full MMU: all autoload ways, ways 7, 8 and 9 of DTLB must | |
426 | * be flushed. | |
427 | * Way 4 is not currently used by linux. | |
428 | * Ways 5 and 6 shall not be touched on MMUv2 as they are hardwired. | |
429 | * Way 5 shall be flushed and way 6 shall be set to identity mapping | |
430 | * on MMUv3. | |
431 | */ | |
432 | local_flush_tlb_all(); | |
433 | invalidate_page_directory(); | |
434 | #if XCHAL_HAVE_SPANNING_WAY | |
435 | /* MMU v3 */ | |
436 | { | |
437 | unsigned long vaddr = (unsigned long)cpu_reset; | |
438 | unsigned long paddr = __pa(vaddr); | |
439 | unsigned long tmpaddr = vaddr + SZ_512M; | |
440 | unsigned long tmp0, tmp1, tmp2, tmp3; | |
441 | ||
442 | /* | |
443 | * Find a place for the temporary mapping. It must not be | |
444 | * in the same 512MB region with vaddr or paddr, otherwise | |
445 | * there may be multihit exception either on entry to the | |
446 | * temporary mapping, or on entry to the identity mapping. | |
447 | * (512MB is the biggest page size supported by TLB.) | |
448 | */ | |
449 | while (((tmpaddr ^ paddr) & -SZ_512M) == 0) | |
450 | tmpaddr += SZ_512M; | |
451 | ||
452 | /* Invalidate mapping in the selected temporary area */ | |
453 | if (itlb_probe(tmpaddr) & 0x8) | |
454 | invalidate_itlb_entry(itlb_probe(tmpaddr)); | |
455 | if (itlb_probe(tmpaddr + PAGE_SIZE) & 0x8) | |
456 | invalidate_itlb_entry(itlb_probe(tmpaddr + PAGE_SIZE)); | |
457 | ||
458 | /* | |
459 | * Map two consecutive pages starting at the physical address | |
460 | * of this function to the temporary mapping area. | |
461 | */ | |
462 | write_itlb_entry(__pte((paddr & PAGE_MASK) | | |
463 | _PAGE_HW_VALID | | |
464 | _PAGE_HW_EXEC | | |
465 | _PAGE_CA_BYPASS), | |
466 | tmpaddr & PAGE_MASK); | |
467 | write_itlb_entry(__pte(((paddr & PAGE_MASK) + PAGE_SIZE) | | |
468 | _PAGE_HW_VALID | | |
469 | _PAGE_HW_EXEC | | |
470 | _PAGE_CA_BYPASS), | |
471 | (tmpaddr & PAGE_MASK) + PAGE_SIZE); | |
472 | ||
473 | /* Reinitialize TLB */ | |
474 | __asm__ __volatile__ ("movi %0, 1f\n\t" | |
475 | "movi %3, 2f\n\t" | |
476 | "add %0, %0, %4\n\t" | |
477 | "add %3, %3, %5\n\t" | |
478 | "jx %0\n" | |
479 | /* | |
480 | * No literal, data or stack access | |
481 | * below this point | |
482 | */ | |
483 | "1:\n\t" | |
484 | /* Initialize *tlbcfg */ | |
485 | "movi %0, 0\n\t" | |
486 | "wsr %0, itlbcfg\n\t" | |
487 | "wsr %0, dtlbcfg\n\t" | |
488 | /* Invalidate TLB way 5 */ | |
489 | "movi %0, 4\n\t" | |
490 | "movi %1, 5\n" | |
491 | "1:\n\t" | |
492 | "iitlb %1\n\t" | |
493 | "idtlb %1\n\t" | |
494 | "add %1, %1, %6\n\t" | |
495 | "addi %0, %0, -1\n\t" | |
496 | "bnez %0, 1b\n\t" | |
497 | /* Initialize TLB way 6 */ | |
498 | "movi %0, 7\n\t" | |
499 | "addi %1, %9, 3\n\t" | |
500 | "addi %2, %9, 6\n" | |
501 | "1:\n\t" | |
502 | "witlb %1, %2\n\t" | |
503 | "wdtlb %1, %2\n\t" | |
504 | "add %1, %1, %7\n\t" | |
505 | "add %2, %2, %7\n\t" | |
506 | "addi %0, %0, -1\n\t" | |
507 | "bnez %0, 1b\n\t" | |
508 | /* Jump to identity mapping */ | |
509 | "jx %3\n" | |
510 | "2:\n\t" | |
511 | /* Complete way 6 initialization */ | |
512 | "witlb %1, %2\n\t" | |
513 | "wdtlb %1, %2\n\t" | |
514 | /* Invalidate temporary mapping */ | |
515 | "sub %0, %9, %7\n\t" | |
516 | "iitlb %0\n\t" | |
517 | "add %0, %0, %8\n\t" | |
518 | "iitlb %0" | |
519 | : "=&a"(tmp0), "=&a"(tmp1), "=&a"(tmp2), | |
520 | "=&a"(tmp3) | |
521 | : "a"(tmpaddr - vaddr), | |
522 | "a"(paddr - vaddr), | |
523 | "a"(SZ_128M), "a"(SZ_512M), | |
524 | "a"(PAGE_SIZE), | |
525 | "a"((tmpaddr + SZ_512M) & PAGE_MASK) | |
526 | : "memory"); | |
527 | } | |
528 | #endif | |
529 | #endif | |
ea951c34 | 530 | __asm__ __volatile__ ("movi a2, 0\n\t" |
4f205687 MF |
531 | "wsr a2, icountlevel\n\t" |
532 | "movi a2, 0\n\t" | |
533 | "wsr a2, icount\n\t" | |
534 | #if XCHAL_NUM_IBREAK > 0 | |
535 | "wsr a2, ibreakenable\n\t" | |
536 | #endif | |
537 | #if XCHAL_HAVE_LOOPS | |
538 | "wsr a2, lcount\n\t" | |
539 | #endif | |
540 | "movi a2, 0x1f\n\t" | |
541 | "wsr a2, ps\n\t" | |
542 | "isync\n\t" | |
543 | "jx %0\n\t" | |
544 | : | |
545 | : "a" (XCHAL_RESET_VECTOR_VADDR) | |
546 | : "a2"); | |
547 | for (;;) | |
548 | ; | |
549 | } | |
550 | ||
5a0015d6 CZ |
551 | void machine_restart(char * cmd) |
552 | { | |
553 | platform_restart(); | |
554 | } | |
555 | ||
556 | void machine_halt(void) | |
557 | { | |
558 | platform_halt(); | |
559 | while (1); | |
560 | } | |
561 | ||
562 | void machine_power_off(void) | |
563 | { | |
564 | platform_power_off(); | |
565 | while (1); | |
566 | } | |
567 | #ifdef CONFIG_PROC_FS | |
568 | ||
569 | /* | |
570 | * Display some core information through /proc/cpuinfo. | |
571 | */ | |
572 | ||
573 | static int | |
574 | c_show(struct seq_file *f, void *slot) | |
575 | { | |
576 | /* high-level stuff */ | |
f615136c | 577 | seq_printf(f, "CPU count\t: %u\n" |
62518994 | 578 | "CPU list\t: %*pbl\n" |
f615136c MF |
579 | "vendor_id\t: Tensilica\n" |
580 | "model\t\t: Xtensa " XCHAL_HW_VERSION_NAME "\n" | |
581 | "core ID\t\t: " XCHAL_CORE_ID "\n" | |
582 | "build ID\t: 0x%x\n" | |
583 | "byte order\t: %s\n" | |
584 | "cpu MHz\t\t: %lu.%02lu\n" | |
585 | "bogomips\t: %lu.%02lu\n", | |
586 | num_online_cpus(), | |
62518994 | 587 | cpumask_pr_args(cpu_online_mask), |
f615136c MF |
588 | XCHAL_BUILD_UNIQUE_ID, |
589 | XCHAL_HAVE_BE ? "big" : "little", | |
590 | ccount_freq/1000000, | |
591 | (ccount_freq/10000) % 100, | |
592 | loops_per_jiffy/(500000/HZ), | |
593 | (loops_per_jiffy/(5000/HZ)) % 100); | |
5a0015d6 CZ |
594 | |
595 | seq_printf(f,"flags\t\t: " | |
596 | #if XCHAL_HAVE_NMI | |
597 | "nmi " | |
598 | #endif | |
599 | #if XCHAL_HAVE_DEBUG | |
600 | "debug " | |
601 | # if XCHAL_HAVE_OCD | |
602 | "ocd " | |
603 | # endif | |
604 | #endif | |
605 | #if XCHAL_HAVE_DENSITY | |
606 | "density " | |
607 | #endif | |
608 | #if XCHAL_HAVE_BOOLEANS | |
609 | "boolean " | |
610 | #endif | |
611 | #if XCHAL_HAVE_LOOPS | |
612 | "loop " | |
613 | #endif | |
614 | #if XCHAL_HAVE_NSA | |
615 | "nsa " | |
616 | #endif | |
617 | #if XCHAL_HAVE_MINMAX | |
618 | "minmax " | |
619 | #endif | |
620 | #if XCHAL_HAVE_SEXT | |
621 | "sext " | |
622 | #endif | |
623 | #if XCHAL_HAVE_CLAMPS | |
624 | "clamps " | |
625 | #endif | |
626 | #if XCHAL_HAVE_MAC16 | |
627 | "mac16 " | |
628 | #endif | |
629 | #if XCHAL_HAVE_MUL16 | |
630 | "mul16 " | |
631 | #endif | |
632 | #if XCHAL_HAVE_MUL32 | |
633 | "mul32 " | |
634 | #endif | |
635 | #if XCHAL_HAVE_MUL32_HIGH | |
636 | "mul32h " | |
637 | #endif | |
638 | #if XCHAL_HAVE_FP | |
639 | "fpu " | |
2f6ea6a7 MF |
640 | #endif |
641 | #if XCHAL_HAVE_S32C1I | |
642 | "s32c1i " | |
5a0015d6 CZ |
643 | #endif |
644 | "\n"); | |
645 | ||
646 | /* Registers. */ | |
647 | seq_printf(f,"physical aregs\t: %d\n" | |
648 | "misc regs\t: %d\n" | |
649 | "ibreak\t\t: %d\n" | |
650 | "dbreak\t\t: %d\n", | |
651 | XCHAL_NUM_AREGS, | |
652 | XCHAL_NUM_MISC_REGS, | |
653 | XCHAL_NUM_IBREAK, | |
654 | XCHAL_NUM_DBREAK); | |
655 | ||
656 | ||
657 | /* Interrupt. */ | |
658 | seq_printf(f,"num ints\t: %d\n" | |
659 | "ext ints\t: %d\n" | |
660 | "int levels\t: %d\n" | |
661 | "timers\t\t: %d\n" | |
662 | "debug level\t: %d\n", | |
663 | XCHAL_NUM_INTERRUPTS, | |
664 | XCHAL_NUM_EXTINTERRUPTS, | |
665 | XCHAL_NUM_INTLEVELS, | |
666 | XCHAL_NUM_TIMERS, | |
667 | XCHAL_DEBUGLEVEL); | |
668 | ||
5a0015d6 CZ |
669 | /* Cache */ |
670 | seq_printf(f,"icache line size: %d\n" | |
671 | "icache ways\t: %d\n" | |
672 | "icache size\t: %d\n" | |
673 | "icache flags\t: " | |
674 | #if XCHAL_ICACHE_LINE_LOCKABLE | |
415217ef | 675 | "lock " |
5a0015d6 CZ |
676 | #endif |
677 | "\n" | |
678 | "dcache line size: %d\n" | |
679 | "dcache ways\t: %d\n" | |
680 | "dcache size\t: %d\n" | |
681 | "dcache flags\t: " | |
682 | #if XCHAL_DCACHE_IS_WRITEBACK | |
415217ef | 683 | "writeback " |
5a0015d6 CZ |
684 | #endif |
685 | #if XCHAL_DCACHE_LINE_LOCKABLE | |
415217ef | 686 | "lock " |
5a0015d6 CZ |
687 | #endif |
688 | "\n", | |
689 | XCHAL_ICACHE_LINESIZE, | |
690 | XCHAL_ICACHE_WAYS, | |
691 | XCHAL_ICACHE_SIZE, | |
692 | XCHAL_DCACHE_LINESIZE, | |
693 | XCHAL_DCACHE_WAYS, | |
694 | XCHAL_DCACHE_SIZE); | |
695 | ||
5a0015d6 CZ |
696 | return 0; |
697 | } | |
698 | ||
699 | /* | |
700 | * We show only CPU #0 info. | |
701 | */ | |
702 | static void * | |
703 | c_start(struct seq_file *f, loff_t *pos) | |
704 | { | |
f615136c | 705 | return (*pos == 0) ? (void *)1 : NULL; |
5a0015d6 CZ |
706 | } |
707 | ||
708 | static void * | |
709 | c_next(struct seq_file *f, void *v, loff_t *pos) | |
710 | { | |
711 | return NULL; | |
712 | } | |
713 | ||
714 | static void | |
715 | c_stop(struct seq_file *f, void *v) | |
716 | { | |
717 | } | |
718 | ||
03a44825 | 719 | const struct seq_operations cpuinfo_op = |
5a0015d6 | 720 | { |
f615136c MF |
721 | .start = c_start, |
722 | .next = c_next, | |
723 | .stop = c_stop, | |
724 | .show = c_show, | |
5a0015d6 CZ |
725 | }; |
726 | ||
727 | #endif /* CONFIG_PROC_FS */ |