xref: /linux-6.15/arch/xtensa/kernel/setup.c (revision 99e487db)
15a0015d6SChris Zankel /*
2f30c2269SUwe Zeisberger  * arch/xtensa/kernel/setup.c
35a0015d6SChris Zankel  *
45a0015d6SChris Zankel  * This file is subject to the terms and conditions of the GNU General Public
55a0015d6SChris Zankel  * License.  See the file "COPYING" in the main directory of this archive
65a0015d6SChris Zankel  * for more details.
75a0015d6SChris Zankel  *
85a0015d6SChris Zankel  * Copyright (C) 1995  Linus Torvalds
95a0015d6SChris Zankel  * Copyright (C) 2001 - 2005  Tensilica Inc.
100e46c111SMax Filippov  * Copyright (C) 2014 - 2016  Cadence Design Systems Inc.
115a0015d6SChris Zankel  *
125a0015d6SChris Zankel  * Chris Zankel	<[email protected]>
135a0015d6SChris Zankel  * Joe Taylor	<[email protected], [email protected]>
145a0015d6SChris Zankel  * Kevin Chea
155a0015d6SChris Zankel  * Marc Gauthier<[email protected]> <[email protected]>
165a0015d6SChris Zankel  */
175a0015d6SChris Zankel 
185a0015d6SChris Zankel #include <linux/errno.h>
195a0015d6SChris Zankel #include <linux/init.h>
2027ac792cSAndrea Righi #include <linux/mm.h>
215a0015d6SChris Zankel #include <linux/proc_fs.h>
225a0015d6SChris Zankel #include <linux/kernel.h>
23f615136cSMax Filippov #include <linux/percpu.h>
2411976fe2SMax Filippov #include <linux/reboot.h>
25f615136cSMax Filippov #include <linux/cpu.h>
26d02014b2SGuenter Roeck #include <linux/of.h>
27da844a81SMax Filippov #include <linux/of_fdt.h>
28da844a81SMax Filippov 
295a0015d6SChris Zankel #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
305a0015d6SChris Zankel # include <linux/console.h>
315a0015d6SChris Zankel #endif
325a0015d6SChris Zankel 
335a0015d6SChris Zankel #ifdef CONFIG_PROC_FS
345a0015d6SChris Zankel # include <linux/seq_file.h>
355a0015d6SChris Zankel #endif
365a0015d6SChris Zankel 
375a0015d6SChris Zankel #include <asm/bootparam.h>
38c633544aSMax Filippov #include <asm/kasan.h>
39c8f3a7dcSMax Filippov #include <asm/mmu_context.h>
405a0015d6SChris Zankel #include <asm/page.h>
41de4f6e5bSChris Zankel #include <asm/param.h>
42bd47cdb7SMax Filippov #include <asm/platform.h>
43bd47cdb7SMax Filippov #include <asm/processor.h>
44bd47cdb7SMax Filippov #include <asm/sections.h>
45bd47cdb7SMax Filippov #include <asm/setup.h>
46f615136cSMax Filippov #include <asm/smp.h>
479ba067f9SMax Filippov #include <asm/sysmem.h>
48bd47cdb7SMax Filippov #include <asm/timex.h>
4967e88622SMax Filippov #include <asm/traps.h>
505a0015d6SChris Zankel 
515a0015d6SChris Zankel #ifdef CONFIG_BLK_DEV_INITRD
5229eb45a9SRob Herring extern unsigned long initrd_start;
5329eb45a9SRob Herring extern unsigned long initrd_end;
545a0015d6SChris Zankel extern int initrd_below_start_ok;
555a0015d6SChris Zankel #endif
565a0015d6SChris Zankel 
57d67ed251SRandy Dunlap #ifdef CONFIG_USE_OF
58*99e487dbSMasahiro Yamada static void *dtb_start __initdata = __dtb_start;
59da844a81SMax Filippov #endif
60da844a81SMax Filippov 
615a0015d6SChris Zankel extern unsigned long loops_per_jiffy;
625a0015d6SChris Zankel 
635a0015d6SChris Zankel /* Command line specified as configuration option. */
645a0015d6SChris Zankel 
65d3e9cceaSAlon Bar-Lev static char __initdata command_line[COMMAND_LINE_SIZE];
665a0015d6SChris Zankel 
675a0015d6SChris Zankel #ifdef CONFIG_CMDLINE_BOOL
685a0015d6SChris Zankel static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
695a0015d6SChris Zankel #endif
705a0015d6SChris Zankel 
71baac1d36SMax Filippov #ifdef CONFIG_PARSE_BOOTPARAM
725a0015d6SChris Zankel /*
735a0015d6SChris Zankel  * Boot parameter parsing.
745a0015d6SChris Zankel  *
755a0015d6SChris Zankel  * The Xtensa port uses a list of variable-sized tags to pass data to
765a0015d6SChris Zankel  * the kernel. The first tag must be a BP_TAG_FIRST tag for the list
775a0015d6SChris Zankel  * to be recognised. The list is terminated with a zero-sized
785a0015d6SChris Zankel  * BP_TAG_LAST tag.
795a0015d6SChris Zankel  */
805a0015d6SChris Zankel 
815a0015d6SChris Zankel typedef struct tagtable {
825a0015d6SChris Zankel 	u32 tag;
835a0015d6SChris Zankel 	int (*parse)(const bp_tag_t*);
845a0015d6SChris Zankel } tagtable_t;
855a0015d6SChris Zankel 
865a0015d6SChris Zankel #define __tagtable(tag, fn) static tagtable_t __tagtable_##fn 		\
8733def849SJoe Perches 	__section(".taglist") __attribute__((used)) = { tag, fn }
885a0015d6SChris Zankel 
895a0015d6SChris Zankel /* parse current tag */
905a0015d6SChris Zankel 
parse_tag_mem(const bp_tag_t * tag)915a0015d6SChris Zankel static int __init parse_tag_mem(const bp_tag_t *tag)
925a0015d6SChris Zankel {
939ba067f9SMax Filippov 	struct bp_meminfo *mi = (struct bp_meminfo *)(tag->data);
945a0015d6SChris Zankel 
955a0015d6SChris Zankel 	if (mi->type != MEMORY_TYPE_CONVENTIONAL)
965a0015d6SChris Zankel 		return -1;
975a0015d6SChris Zankel 
980e46c111SMax Filippov 	return memblock_add(mi->start, mi->end - mi->start);
995a0015d6SChris Zankel }
1005a0015d6SChris Zankel 
1015a0015d6SChris Zankel __tagtable(BP_TAG_MEMORY, parse_tag_mem);
1025a0015d6SChris Zankel 
1035a0015d6SChris Zankel #ifdef CONFIG_BLK_DEV_INITRD
1045a0015d6SChris Zankel 
parse_tag_initrd(const bp_tag_t * tag)1055a0015d6SChris Zankel static int __init parse_tag_initrd(const bp_tag_t* tag)
1065a0015d6SChris Zankel {
1079ba067f9SMax Filippov 	struct bp_meminfo *mi = (struct bp_meminfo *)(tag->data);
1089ba067f9SMax Filippov 
10929eb45a9SRob Herring 	initrd_start = (unsigned long)__va(mi->start);
11029eb45a9SRob Herring 	initrd_end = (unsigned long)__va(mi->end);
1115a0015d6SChris Zankel 
1125a0015d6SChris Zankel 	return 0;
1135a0015d6SChris Zankel }
1145a0015d6SChris Zankel 
1155a0015d6SChris Zankel __tagtable(BP_TAG_INITRD, parse_tag_initrd);
1165a0015d6SChris Zankel 
1174ab18701SMax Filippov #endif /* CONFIG_BLK_DEV_INITRD */
1184ab18701SMax Filippov 
119d67ed251SRandy Dunlap #ifdef CONFIG_USE_OF
120da844a81SMax Filippov 
parse_tag_fdt(const bp_tag_t * tag)121da844a81SMax Filippov static int __init parse_tag_fdt(const bp_tag_t *tag)
122da844a81SMax Filippov {
123c5a771d0SMax Filippov 	dtb_start = __va(tag->data[0]);
124da844a81SMax Filippov 	return 0;
125da844a81SMax Filippov }
126da844a81SMax Filippov 
127da844a81SMax Filippov __tagtable(BP_TAG_FDT, parse_tag_fdt);
128da844a81SMax Filippov 
129d67ed251SRandy Dunlap #endif /* CONFIG_USE_OF */
130da844a81SMax Filippov 
parse_tag_cmdline(const bp_tag_t * tag)1315a0015d6SChris Zankel static int __init parse_tag_cmdline(const bp_tag_t* tag)
1325a0015d6SChris Zankel {
1339ddef266SJason Wang 	strscpy(command_line, (char *)(tag->data), COMMAND_LINE_SIZE);
1345a0015d6SChris Zankel 	return 0;
1355a0015d6SChris Zankel }
1365a0015d6SChris Zankel 
1375a0015d6SChris Zankel __tagtable(BP_TAG_COMMAND_LINE, parse_tag_cmdline);
1385a0015d6SChris Zankel 
parse_bootparam(const bp_tag_t * tag)1395a0015d6SChris Zankel static int __init parse_bootparam(const bp_tag_t* tag)
1405a0015d6SChris Zankel {
1415a0015d6SChris Zankel 	extern tagtable_t __tagtable_begin, __tagtable_end;
1425a0015d6SChris Zankel 	tagtable_t *t;
1435a0015d6SChris Zankel 
1445a0015d6SChris Zankel 	/* Boot parameters must start with a BP_TAG_FIRST tag. */
1455a0015d6SChris Zankel 
1465a0015d6SChris Zankel 	if (tag->id != BP_TAG_FIRST) {
147c130d3beSMax Filippov 		pr_warn("Invalid boot parameters!\n");
1485a0015d6SChris Zankel 		return 0;
1495a0015d6SChris Zankel 	}
1505a0015d6SChris Zankel 
1515a0015d6SChris Zankel 	tag = (bp_tag_t*)((unsigned long)tag + sizeof(bp_tag_t) + tag->size);
1525a0015d6SChris Zankel 
1535a0015d6SChris Zankel 	/* Parse all tags. */
1545a0015d6SChris Zankel 
1555a0015d6SChris Zankel 	while (tag != NULL && tag->id != BP_TAG_LAST) {
1565a0015d6SChris Zankel 		for (t = &__tagtable_begin; t < &__tagtable_end; t++) {
1575a0015d6SChris Zankel 			if (tag->id == t->tag) {
1585a0015d6SChris Zankel 				t->parse(tag);
1595a0015d6SChris Zankel 				break;
1605a0015d6SChris Zankel 			}
1615a0015d6SChris Zankel 		}
1625a0015d6SChris Zankel 		if (t == &__tagtable_end)
163c130d3beSMax Filippov 			pr_warn("Ignoring tag 0x%08x\n", tag->id);
1645a0015d6SChris Zankel 		tag = (bp_tag_t*)((unsigned long)(tag + 1) + tag->size);
1655a0015d6SChris Zankel 	}
1665a0015d6SChris Zankel 
1675a0015d6SChris Zankel 	return 0;
1685a0015d6SChris Zankel }
169baac1d36SMax Filippov #else
parse_bootparam(const bp_tag_t * tag)170baac1d36SMax Filippov static int __init parse_bootparam(const bp_tag_t *tag)
171baac1d36SMax Filippov {
172baac1d36SMax Filippov 	pr_info("Ignoring boot parameters at %p\n", tag);
173baac1d36SMax Filippov 	return 0;
174baac1d36SMax Filippov }
175baac1d36SMax Filippov #endif
1765a0015d6SChris Zankel 
177d67ed251SRandy Dunlap #ifdef CONFIG_USE_OF
178da844a81SMax Filippov 
179260c64bbSMax Filippov #if !XCHAL_HAVE_PTP_MMU || XCHAL_HAVE_SPANNING_WAY
1806cb97111SBaruch Siach unsigned long xtensa_kio_paddr = XCHAL_KIO_DEFAULT_PADDR;
1816cb97111SBaruch Siach EXPORT_SYMBOL(xtensa_kio_paddr);
1826cb97111SBaruch Siach 
xtensa_dt_io_area(unsigned long node,const char * uname,int depth,void * data)1836cb97111SBaruch Siach static int __init xtensa_dt_io_area(unsigned long node, const char *uname,
1846cb97111SBaruch Siach 		int depth, void *data)
1856cb97111SBaruch Siach {
1866cb97111SBaruch Siach 	const __be32 *ranges;
1879d0c4dfeSRob Herring 	int len;
1886cb97111SBaruch Siach 
1896cb97111SBaruch Siach 	if (depth > 1)
1906cb97111SBaruch Siach 		return 0;
1916cb97111SBaruch Siach 
1926cb97111SBaruch Siach 	if (!of_flat_dt_is_compatible(node, "simple-bus"))
1936cb97111SBaruch Siach 		return 0;
1946cb97111SBaruch Siach 
1956cb97111SBaruch Siach 	ranges = of_get_flat_dt_prop(node, "ranges", &len);
1966cb97111SBaruch Siach 	if (!ranges)
1976cb97111SBaruch Siach 		return 1;
1986cb97111SBaruch Siach 	if (len == 0)
1996cb97111SBaruch Siach 		return 1;
2006cb97111SBaruch Siach 
2016cb97111SBaruch Siach 	xtensa_kio_paddr = of_read_ulong(ranges+1, 1);
2026cb97111SBaruch Siach 	/* round down to nearest 256MB boundary */
2036cb97111SBaruch Siach 	xtensa_kio_paddr &= 0xf0000000;
2046cb97111SBaruch Siach 
205c2edb35aSMax Filippov 	init_kio();
206c2edb35aSMax Filippov 
2076cb97111SBaruch Siach 	return 1;
2086cb97111SBaruch Siach }
2096cb97111SBaruch Siach #else
xtensa_dt_io_area(unsigned long node,const char * uname,int depth,void * data)2106cb97111SBaruch Siach static int __init xtensa_dt_io_area(unsigned long node, const char *uname,
2116cb97111SBaruch Siach 		int depth, void *data)
2126cb97111SBaruch Siach {
2136cb97111SBaruch Siach 	return 1;
2146cb97111SBaruch Siach }
2156cb97111SBaruch Siach #endif
2166cb97111SBaruch Siach 
early_init_devtree(void * params)217da844a81SMax Filippov void __init early_init_devtree(void *params)
218da844a81SMax Filippov {
2197745fc1fSRob Herring 	early_init_dt_scan(params, __pa(params));
2206cb97111SBaruch Siach 	of_scan_flat_dt(xtensa_dt_io_area, NULL);
2217745fc1fSRob Herring 
2227745fc1fSRob Herring 	if (!command_line[0])
2239ddef266SJason Wang 		strscpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
224da844a81SMax Filippov }
225da844a81SMax Filippov 
226d67ed251SRandy Dunlap #endif /* CONFIG_USE_OF */
227da844a81SMax Filippov 
2285a0015d6SChris Zankel /*
2295a0015d6SChris Zankel  * Initialize architecture. (Early stage)
2305a0015d6SChris Zankel  */
2315a0015d6SChris Zankel 
init_arch(bp_tag_t * bp_start)2325a0015d6SChris Zankel void __init init_arch(bp_tag_t *bp_start)
2335a0015d6SChris Zankel {
23467e88622SMax Filippov 	/* Initialize basic exception handling if configuration may need it */
23567e88622SMax Filippov 
236f29cf776SMax Filippov 	if (IS_ENABLED(CONFIG_KASAN) ||
237f29cf776SMax Filippov 	    IS_ENABLED(CONFIG_XTENSA_LOAD_STORE))
23867e88622SMax Filippov 		early_trap_init();
23967e88622SMax Filippov 
240c2edb35aSMax Filippov 	/* Initialize MMU. */
241c2edb35aSMax Filippov 
242c2edb35aSMax Filippov 	init_mmu();
243c2edb35aSMax Filippov 
244c633544aSMax Filippov 	/* Initialize initial KASAN shadow map */
245c633544aSMax Filippov 
246c633544aSMax Filippov 	kasan_early_init();
247c633544aSMax Filippov 
2485a0015d6SChris Zankel 	/* Parse boot parameters */
2495a0015d6SChris Zankel 
2505a0015d6SChris Zankel 	if (bp_start)
2515a0015d6SChris Zankel 		parse_bootparam(bp_start);
2525a0015d6SChris Zankel 
253d67ed251SRandy Dunlap #ifdef CONFIG_USE_OF
254da844a81SMax Filippov 	early_init_devtree(dtb_start);
255da844a81SMax Filippov #endif
256da844a81SMax Filippov 
257da844a81SMax Filippov #ifdef CONFIG_CMDLINE_BOOL
258da844a81SMax Filippov 	if (!command_line[0])
2599ddef266SJason Wang 		strscpy(command_line, default_command_line, COMMAND_LINE_SIZE);
260da844a81SMax Filippov #endif
261da844a81SMax Filippov 
2625a0015d6SChris Zankel 	/* Early hook for platforms */
2635a0015d6SChris Zankel 
2645a0015d6SChris Zankel 	platform_init(bp_start);
2655a0015d6SChris Zankel }
2665a0015d6SChris Zankel 
2675a0015d6SChris Zankel /*
2685a0015d6SChris Zankel  * Initialize system. Setup memory and reserve regions.
2695a0015d6SChris Zankel  */
2705a0015d6SChris Zankel 
mem_reserve(unsigned long start,unsigned long end)271adefd051SGuenter Roeck static inline int __init_memblock mem_reserve(unsigned long start,
272adefd051SGuenter Roeck 					      unsigned long end)
2730e46c111SMax Filippov {
2740e46c111SMax Filippov 	return memblock_reserve(start, end - start);
2750e46c111SMax Filippov }
27600273125SMax Filippov 
setup_arch(char ** cmdline_p)2775a0015d6SChris Zankel void __init setup_arch(char **cmdline_p)
2785a0015d6SChris Zankel {
279aa6476f7SMax Filippov 	pr_info("config ID: %08x:%08x\n",
280cad6fadeSMax Filippov 		xtensa_get_sr(SREG_EPC), xtensa_get_sr(SREG_EXCSAVE));
281cad6fadeSMax Filippov 	if (xtensa_get_sr(SREG_EPC) != XCHAL_HW_CONFIGID0 ||
282cad6fadeSMax Filippov 	    xtensa_get_sr(SREG_EXCSAVE) != XCHAL_HW_CONFIGID1)
283aa6476f7SMax Filippov 		pr_info("built for config ID: %08x:%08x\n",
284aa6476f7SMax Filippov 			XCHAL_HW_CONFIGID0, XCHAL_HW_CONFIGID1);
285aa6476f7SMax Filippov 
2865a0015d6SChris Zankel 	*cmdline_p = command_line;
287fbe22d28SMax Filippov 	platform_setup(cmdline_p);
2889ddef266SJason Wang 	strscpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE);
2895a0015d6SChris Zankel 
2905a0015d6SChris Zankel 	/* Reserve some memory regions */
2915a0015d6SChris Zankel 
2925a0015d6SChris Zankel #ifdef CONFIG_BLK_DEV_INITRD
293f348f5c2SMike Rapoport 	if (initrd_start < initrd_end &&
294f348f5c2SMike Rapoport 	    !mem_reserve(__pa(initrd_start), __pa(initrd_end)))
2955a0015d6SChris Zankel 		initrd_below_start_ok = 1;
296f348f5c2SMike Rapoport 	else
2975a0015d6SChris Zankel 		initrd_start = 0;
2985a0015d6SChris Zankel #endif
2995a0015d6SChris Zankel 
30018244362SMasami Hiramatsu 	mem_reserve(__pa(_stext), __pa(_end));
3017af710d9SMax Filippov #ifdef CONFIG_XIP_KERNEL
30203ce34cfSMax Filippov #ifdef CONFIG_VECTORS_ADDR
30303ce34cfSMax Filippov 	mem_reserve(__pa(_xip_text_start), __pa(_xip_text_end));
30403ce34cfSMax Filippov #endif
3057af710d9SMax Filippov 	mem_reserve(__pa(_xip_start), __pa(_xip_end));
3067af710d9SMax Filippov #endif
3075a0015d6SChris Zankel 
3085e4417f9SMax Filippov #ifdef CONFIG_VECTORS_ADDR
309da0a4e5cSMax Filippov #ifdef SUPPORT_WINDOWED
310bd47cdb7SMax Filippov 	mem_reserve(__pa(_WindowVectors_text_start),
311bd47cdb7SMax Filippov 		    __pa(_WindowVectors_text_end));
312da0a4e5cSMax Filippov #endif
3135a0015d6SChris Zankel 
314bd47cdb7SMax Filippov 	mem_reserve(__pa(_DebugInterruptVector_text_start),
315bd47cdb7SMax Filippov 		    __pa(_DebugInterruptVector_text_end));
3165a0015d6SChris Zankel 
317bd47cdb7SMax Filippov 	mem_reserve(__pa(_KernelExceptionVector_text_start),
318bd47cdb7SMax Filippov 		    __pa(_KernelExceptionVector_text_end));
3195a0015d6SChris Zankel 
320bd47cdb7SMax Filippov 	mem_reserve(__pa(_UserExceptionVector_text_start),
321bd47cdb7SMax Filippov 		    __pa(_UserExceptionVector_text_end));
3225a0015d6SChris Zankel 
323bd47cdb7SMax Filippov 	mem_reserve(__pa(_DoubleExceptionVector_text_start),
324bd47cdb7SMax Filippov 		    __pa(_DoubleExceptionVector_text_end));
3255a0015d6SChris Zankel 
326bd47cdb7SMax Filippov 	mem_reserve(__pa(_exception_text_start),
327bd47cdb7SMax Filippov 		    __pa(_exception_text_end));
3282d1c645cSMarc Gauthier #if XCHAL_EXCM_LEVEL >= 2
329bd47cdb7SMax Filippov 	mem_reserve(__pa(_Level2InterruptVector_text_start),
330bd47cdb7SMax Filippov 		    __pa(_Level2InterruptVector_text_end));
3312d1c645cSMarc Gauthier #endif
3322d1c645cSMarc Gauthier #if XCHAL_EXCM_LEVEL >= 3
333bd47cdb7SMax Filippov 	mem_reserve(__pa(_Level3InterruptVector_text_start),
334bd47cdb7SMax Filippov 		    __pa(_Level3InterruptVector_text_end));
3352d1c645cSMarc Gauthier #endif
3362d1c645cSMarc Gauthier #if XCHAL_EXCM_LEVEL >= 4
337bd47cdb7SMax Filippov 	mem_reserve(__pa(_Level4InterruptVector_text_start),
338bd47cdb7SMax Filippov 		    __pa(_Level4InterruptVector_text_end));
3392d1c645cSMarc Gauthier #endif
3402d1c645cSMarc Gauthier #if XCHAL_EXCM_LEVEL >= 5
341bd47cdb7SMax Filippov 	mem_reserve(__pa(_Level5InterruptVector_text_start),
342bd47cdb7SMax Filippov 		    __pa(_Level5InterruptVector_text_end));
3432d1c645cSMarc Gauthier #endif
3442d1c645cSMarc Gauthier #if XCHAL_EXCM_LEVEL >= 6
345bd47cdb7SMax Filippov 	mem_reserve(__pa(_Level6InterruptVector_text_start),
346bd47cdb7SMax Filippov 		    __pa(_Level6InterruptVector_text_end));
3472d1c645cSMarc Gauthier #endif
3482d1c645cSMarc Gauthier 
3495e4417f9SMax Filippov #endif /* CONFIG_VECTORS_ADDR */
350b46dcfa3SMax Filippov 
35189b184f9SMax Filippov #ifdef CONFIG_SECONDARY_RESET_VECTOR
352bd47cdb7SMax Filippov 	mem_reserve(__pa(_SecondaryResetVector_text_start),
353bd47cdb7SMax Filippov 		    __pa(_SecondaryResetVector_text_end));
354ab45fb14SMax Filippov #endif
35506bd2824SMax Filippov 	parse_early_param();
3565a0015d6SChris Zankel 	bootmem_init();
357c633544aSMax Filippov 	kasan_init();
3583104021cSRob Herring 	unflatten_and_copy_device_tree();
3595a0015d6SChris Zankel 
360f615136cSMax Filippov #ifdef CONFIG_SMP
361f615136cSMax Filippov 	smp_init_cpus();
362f615136cSMax Filippov #endif
363f615136cSMax Filippov 
3645a0015d6SChris Zankel 	paging_init();
365e5083a63SJohannes Weiner 	zones_init();
3665a0015d6SChris Zankel 
3675a0015d6SChris Zankel #ifdef CONFIG_VT
3685a0015d6SChris Zankel # if defined(CONFIG_VGA_CONSOLE)
3695a0015d6SChris Zankel 	conswitchp = &vga_con;
3705a0015d6SChris Zankel # endif
3715a0015d6SChris Zankel #endif
3725a0015d6SChris Zankel }
3735a0015d6SChris Zankel 
374f615136cSMax Filippov static DEFINE_PER_CPU(struct cpu, cpu_data);
375f615136cSMax Filippov 
topology_init(void)376f615136cSMax Filippov static int __init topology_init(void)
377f615136cSMax Filippov {
378f615136cSMax Filippov 	int i;
379f615136cSMax Filippov 
380f615136cSMax Filippov 	for_each_possible_cpu(i) {
381f615136cSMax Filippov 		struct cpu *cpu = &per_cpu(cpu_data, i);
38249b424feSMax Filippov 		cpu->hotpluggable = !!i;
383f615136cSMax Filippov 		register_cpu(cpu, i);
384f615136cSMax Filippov 	}
385f615136cSMax Filippov 
386f615136cSMax Filippov 	return 0;
387f615136cSMax Filippov }
388f615136cSMax Filippov subsys_initcall(topology_init);
389f615136cSMax Filippov 
cpu_reset(void)3904f205687SMax Filippov void cpu_reset(void)
3914f205687SMax Filippov {
3924b3e6f2eSMax Filippov #if XCHAL_HAVE_PTP_MMU && IS_ENABLED(CONFIG_MMU)
393bf15f86bSMax Filippov 	local_irq_disable();
394bf15f86bSMax Filippov 	/*
395bf15f86bSMax Filippov 	 * We have full MMU: all autoload ways, ways 7, 8 and 9 of DTLB must
396bf15f86bSMax Filippov 	 * be flushed.
397bf15f86bSMax Filippov 	 * Way 4 is not currently used by linux.
398bf15f86bSMax Filippov 	 * Ways 5 and 6 shall not be touched on MMUv2 as they are hardwired.
399bf15f86bSMax Filippov 	 * Way 5 shall be flushed and way 6 shall be set to identity mapping
400bf15f86bSMax Filippov 	 * on MMUv3.
401bf15f86bSMax Filippov 	 */
402bf15f86bSMax Filippov 	local_flush_tlb_all();
403bf15f86bSMax Filippov 	invalidate_page_directory();
404bf15f86bSMax Filippov #if XCHAL_HAVE_SPANNING_WAY
405bf15f86bSMax Filippov 	/* MMU v3 */
406bf15f86bSMax Filippov 	{
407bf15f86bSMax Filippov 		unsigned long vaddr = (unsigned long)cpu_reset;
408bf15f86bSMax Filippov 		unsigned long paddr = __pa(vaddr);
409bf15f86bSMax Filippov 		unsigned long tmpaddr = vaddr + SZ_512M;
410bf15f86bSMax Filippov 		unsigned long tmp0, tmp1, tmp2, tmp3;
411bf15f86bSMax Filippov 
412bf15f86bSMax Filippov 		/*
413bf15f86bSMax Filippov 		 * Find a place for the temporary mapping. It must not be
414bf15f86bSMax Filippov 		 * in the same 512MB region with vaddr or paddr, otherwise
415bf15f86bSMax Filippov 		 * there may be multihit exception either on entry to the
416bf15f86bSMax Filippov 		 * temporary mapping, or on entry to the identity mapping.
417bf15f86bSMax Filippov 		 * (512MB is the biggest page size supported by TLB.)
418bf15f86bSMax Filippov 		 */
419bf15f86bSMax Filippov 		while (((tmpaddr ^ paddr) & -SZ_512M) == 0)
420bf15f86bSMax Filippov 			tmpaddr += SZ_512M;
421bf15f86bSMax Filippov 
422bf15f86bSMax Filippov 		/* Invalidate mapping in the selected temporary area */
42360e22cffSMax Filippov 		if (itlb_probe(tmpaddr) & BIT(ITLB_HIT_BIT))
424bf15f86bSMax Filippov 			invalidate_itlb_entry(itlb_probe(tmpaddr));
42560e22cffSMax Filippov 		if (itlb_probe(tmpaddr + PAGE_SIZE) & BIT(ITLB_HIT_BIT))
426bf15f86bSMax Filippov 			invalidate_itlb_entry(itlb_probe(tmpaddr + PAGE_SIZE));
427bf15f86bSMax Filippov 
428bf15f86bSMax Filippov 		/*
429bf15f86bSMax Filippov 		 * Map two consecutive pages starting at the physical address
430bf15f86bSMax Filippov 		 * of this function to the temporary mapping area.
431bf15f86bSMax Filippov 		 */
432bf15f86bSMax Filippov 		write_itlb_entry(__pte((paddr & PAGE_MASK) |
433bf15f86bSMax Filippov 				       _PAGE_HW_VALID |
434bf15f86bSMax Filippov 				       _PAGE_HW_EXEC |
435bf15f86bSMax Filippov 				       _PAGE_CA_BYPASS),
436bf15f86bSMax Filippov 				 tmpaddr & PAGE_MASK);
437bf15f86bSMax Filippov 		write_itlb_entry(__pte(((paddr & PAGE_MASK) + PAGE_SIZE) |
438bf15f86bSMax Filippov 				       _PAGE_HW_VALID |
439bf15f86bSMax Filippov 				       _PAGE_HW_EXEC |
440bf15f86bSMax Filippov 				       _PAGE_CA_BYPASS),
441bf15f86bSMax Filippov 				 (tmpaddr & PAGE_MASK) + PAGE_SIZE);
442bf15f86bSMax Filippov 
443bf15f86bSMax Filippov 		/* Reinitialize TLB */
444bf15f86bSMax Filippov 		__asm__ __volatile__ ("movi	%0, 1f\n\t"
445bf15f86bSMax Filippov 				      "movi	%3, 2f\n\t"
446bf15f86bSMax Filippov 				      "add	%0, %0, %4\n\t"
447bf15f86bSMax Filippov 				      "add	%3, %3, %5\n\t"
448bf15f86bSMax Filippov 				      "jx	%0\n"
449bf15f86bSMax Filippov 				      /*
450bf15f86bSMax Filippov 				       * No literal, data or stack access
451bf15f86bSMax Filippov 				       * below this point
452bf15f86bSMax Filippov 				       */
453bf15f86bSMax Filippov 				      "1:\n\t"
454bf15f86bSMax Filippov 				      /* Initialize *tlbcfg */
455bf15f86bSMax Filippov 				      "movi	%0, 0\n\t"
456bf15f86bSMax Filippov 				      "wsr	%0, itlbcfg\n\t"
457bf15f86bSMax Filippov 				      "wsr	%0, dtlbcfg\n\t"
458bf15f86bSMax Filippov 				      /* Invalidate TLB way 5 */
459bf15f86bSMax Filippov 				      "movi	%0, 4\n\t"
460bf15f86bSMax Filippov 				      "movi	%1, 5\n"
461bf15f86bSMax Filippov 				      "1:\n\t"
462bf15f86bSMax Filippov 				      "iitlb	%1\n\t"
463bf15f86bSMax Filippov 				      "idtlb	%1\n\t"
464bf15f86bSMax Filippov 				      "add	%1, %1, %6\n\t"
465bf15f86bSMax Filippov 				      "addi	%0, %0, -1\n\t"
466bf15f86bSMax Filippov 				      "bnez	%0, 1b\n\t"
467bf15f86bSMax Filippov 				      /* Initialize TLB way 6 */
468bf15f86bSMax Filippov 				      "movi	%0, 7\n\t"
469bf15f86bSMax Filippov 				      "addi	%1, %9, 3\n\t"
470bf15f86bSMax Filippov 				      "addi	%2, %9, 6\n"
471bf15f86bSMax Filippov 				      "1:\n\t"
472bf15f86bSMax Filippov 				      "witlb	%1, %2\n\t"
473bf15f86bSMax Filippov 				      "wdtlb	%1, %2\n\t"
474bf15f86bSMax Filippov 				      "add	%1, %1, %7\n\t"
475bf15f86bSMax Filippov 				      "add	%2, %2, %7\n\t"
476bf15f86bSMax Filippov 				      "addi	%0, %0, -1\n\t"
477bf15f86bSMax Filippov 				      "bnez	%0, 1b\n\t"
478cd8869f4SMax Filippov 				      "isync\n\t"
479bf15f86bSMax Filippov 				      /* Jump to identity mapping */
480bf15f86bSMax Filippov 				      "jx	%3\n"
481bf15f86bSMax Filippov 				      "2:\n\t"
482bf15f86bSMax Filippov 				      /* Complete way 6 initialization */
483bf15f86bSMax Filippov 				      "witlb	%1, %2\n\t"
484bf15f86bSMax Filippov 				      "wdtlb	%1, %2\n\t"
485bf15f86bSMax Filippov 				      /* Invalidate temporary mapping */
486bf15f86bSMax Filippov 				      "sub	%0, %9, %7\n\t"
487bf15f86bSMax Filippov 				      "iitlb	%0\n\t"
488bf15f86bSMax Filippov 				      "add	%0, %0, %8\n\t"
489bf15f86bSMax Filippov 				      "iitlb	%0"
490bf15f86bSMax Filippov 				      : "=&a"(tmp0), "=&a"(tmp1), "=&a"(tmp2),
491bf15f86bSMax Filippov 					"=&a"(tmp3)
492bf15f86bSMax Filippov 				      : "a"(tmpaddr - vaddr),
493bf15f86bSMax Filippov 					"a"(paddr - vaddr),
494bf15f86bSMax Filippov 					"a"(SZ_128M), "a"(SZ_512M),
495bf15f86bSMax Filippov 					"a"(PAGE_SIZE),
496bf15f86bSMax Filippov 					"a"((tmpaddr + SZ_512M) & PAGE_MASK)
497bf15f86bSMax Filippov 				      : "memory");
498bf15f86bSMax Filippov 	}
499bf15f86bSMax Filippov #endif
500bf15f86bSMax Filippov #endif
501ea951c34SMax Filippov 	__asm__ __volatile__ ("movi	a2, 0\n\t"
5024f205687SMax Filippov 			      "wsr	a2, icountlevel\n\t"
5034f205687SMax Filippov 			      "movi	a2, 0\n\t"
5044f205687SMax Filippov 			      "wsr	a2, icount\n\t"
5054f205687SMax Filippov #if XCHAL_NUM_IBREAK > 0
5064f205687SMax Filippov 			      "wsr	a2, ibreakenable\n\t"
5074f205687SMax Filippov #endif
5084f205687SMax Filippov #if XCHAL_HAVE_LOOPS
5094f205687SMax Filippov 			      "wsr	a2, lcount\n\t"
5104f205687SMax Filippov #endif
5114f205687SMax Filippov 			      "movi	a2, 0x1f\n\t"
5124f205687SMax Filippov 			      "wsr	a2, ps\n\t"
5134f205687SMax Filippov 			      "isync\n\t"
5144f205687SMax Filippov 			      "jx	%0\n\t"
5154f205687SMax Filippov 			      :
5164f205687SMax Filippov 			      : "a" (XCHAL_RESET_VECTOR_VADDR)
5174f205687SMax Filippov 			      : "a2");
5184f205687SMax Filippov 	for (;;)
5194f205687SMax Filippov 		;
5204f205687SMax Filippov }
5214f205687SMax Filippov 
machine_restart(char * cmd)5225a0015d6SChris Zankel void machine_restart(char * cmd)
5235a0015d6SChris Zankel {
52411976fe2SMax Filippov 	local_irq_disable();
52511976fe2SMax Filippov 	smp_send_stop();
52611976fe2SMax Filippov 	do_kernel_restart(cmd);
52711976fe2SMax Filippov 	pr_err("Reboot failed -- System halted\n");
52811976fe2SMax Filippov 	while (1)
52911976fe2SMax Filippov 		cpu_relax();
5305a0015d6SChris Zankel }
5315a0015d6SChris Zankel 
machine_halt(void)5325a0015d6SChris Zankel void machine_halt(void)
5335a0015d6SChris Zankel {
5347561dfbfSMax Filippov 	local_irq_disable();
5357561dfbfSMax Filippov 	smp_send_stop();
5367561dfbfSMax Filippov 	do_kernel_power_off();
5377561dfbfSMax Filippov 	while (1)
5387561dfbfSMax Filippov 		cpu_relax();
5395a0015d6SChris Zankel }
5405a0015d6SChris Zankel 
machine_power_off(void)5415a0015d6SChris Zankel void machine_power_off(void)
5425a0015d6SChris Zankel {
5437561dfbfSMax Filippov 	local_irq_disable();
5447561dfbfSMax Filippov 	smp_send_stop();
5457561dfbfSMax Filippov 	do_kernel_power_off();
5467561dfbfSMax Filippov 	while (1)
5477561dfbfSMax Filippov 		cpu_relax();
5485a0015d6SChris Zankel }
5495a0015d6SChris Zankel #ifdef CONFIG_PROC_FS
5505a0015d6SChris Zankel 
5515a0015d6SChris Zankel /*
5525a0015d6SChris Zankel  * Display some core information through /proc/cpuinfo.
5535a0015d6SChris Zankel  */
5545a0015d6SChris Zankel 
5555a0015d6SChris Zankel static int
c_show(struct seq_file * f,void * slot)5565a0015d6SChris Zankel c_show(struct seq_file *f, void *slot)
5575a0015d6SChris Zankel {
5585a0015d6SChris Zankel 	/* high-level stuff */
559f615136cSMax Filippov 	seq_printf(f, "CPU count\t: %u\n"
56062518994STejun Heo 		      "CPU list\t: %*pbl\n"
5615a0015d6SChris Zankel 		      "vendor_id\t: Tensilica\n"
562173d6681SChris Zankel 		      "model\t\t: Xtensa " XCHAL_HW_VERSION_NAME "\n"
5635a0015d6SChris Zankel 		      "core ID\t\t: " XCHAL_CORE_ID "\n"
5645a0015d6SChris Zankel 		      "build ID\t: 0x%x\n"
565aa6476f7SMax Filippov 		      "config ID\t: %08x:%08x\n"
5665a0015d6SChris Zankel 		      "byte order\t: %s\n"
5675a0015d6SChris Zankel 		      "cpu MHz\t\t: %lu.%02lu\n"
5685a0015d6SChris Zankel 		      "bogomips\t: %lu.%02lu\n",
569f615136cSMax Filippov 		      num_online_cpus(),
57062518994STejun Heo 		      cpumask_pr_args(cpu_online_mask),
5715a0015d6SChris Zankel 		      XCHAL_BUILD_UNIQUE_ID,
572cad6fadeSMax Filippov 		      xtensa_get_sr(SREG_EPC), xtensa_get_sr(SREG_EXCSAVE),
5735a0015d6SChris Zankel 		      XCHAL_HAVE_BE ?  "big" : "little",
5748d5e1d8eSBaruch Siach 		      ccount_freq/1000000,
5758d5e1d8eSBaruch Siach 		      (ccount_freq/10000) % 100,
5765a0015d6SChris Zankel 		      loops_per_jiffy/(500000/HZ),
5775a0015d6SChris Zankel 		      (loops_per_jiffy/(5000/HZ)) % 100);
578c32537d4SMarkus Elfring 	seq_puts(f, "flags\t\t: "
5795a0015d6SChris Zankel #if XCHAL_HAVE_NMI
5805a0015d6SChris Zankel 		     "nmi "
5815a0015d6SChris Zankel #endif
5825a0015d6SChris Zankel #if XCHAL_HAVE_DEBUG
5835a0015d6SChris Zankel 		     "debug "
5845a0015d6SChris Zankel # if XCHAL_HAVE_OCD
5855a0015d6SChris Zankel 		     "ocd "
5865a0015d6SChris Zankel # endif
587e6807b44SMax Filippov #if XCHAL_HAVE_TRAX
588e6807b44SMax Filippov 		     "trax "
589e6807b44SMax Filippov #endif
590e6807b44SMax Filippov #if XCHAL_NUM_PERF_COUNTERS
591e6807b44SMax Filippov 		     "perf "
592e6807b44SMax Filippov #endif
5935a0015d6SChris Zankel #endif
5945a0015d6SChris Zankel #if XCHAL_HAVE_DENSITY
5955a0015d6SChris Zankel 	    	     "density "
5965a0015d6SChris Zankel #endif
5975a0015d6SChris Zankel #if XCHAL_HAVE_BOOLEANS
5985a0015d6SChris Zankel 		     "boolean "
5995a0015d6SChris Zankel #endif
6005a0015d6SChris Zankel #if XCHAL_HAVE_LOOPS
6015a0015d6SChris Zankel 		     "loop "
6025a0015d6SChris Zankel #endif
6035a0015d6SChris Zankel #if XCHAL_HAVE_NSA
6045a0015d6SChris Zankel 		     "nsa "
6055a0015d6SChris Zankel #endif
6065a0015d6SChris Zankel #if XCHAL_HAVE_MINMAX
6075a0015d6SChris Zankel 		     "minmax "
6085a0015d6SChris Zankel #endif
6095a0015d6SChris Zankel #if XCHAL_HAVE_SEXT
6105a0015d6SChris Zankel 		     "sext "
6115a0015d6SChris Zankel #endif
6125a0015d6SChris Zankel #if XCHAL_HAVE_CLAMPS
6135a0015d6SChris Zankel 		     "clamps "
6145a0015d6SChris Zankel #endif
6155a0015d6SChris Zankel #if XCHAL_HAVE_MAC16
6165a0015d6SChris Zankel 		     "mac16 "
6175a0015d6SChris Zankel #endif
6185a0015d6SChris Zankel #if XCHAL_HAVE_MUL16
6195a0015d6SChris Zankel 		     "mul16 "
6205a0015d6SChris Zankel #endif
6215a0015d6SChris Zankel #if XCHAL_HAVE_MUL32
6225a0015d6SChris Zankel 		     "mul32 "
6235a0015d6SChris Zankel #endif
6245a0015d6SChris Zankel #if XCHAL_HAVE_MUL32_HIGH
6255a0015d6SChris Zankel 		     "mul32h "
6265a0015d6SChris Zankel #endif
6275a0015d6SChris Zankel #if XCHAL_HAVE_FP
6285a0015d6SChris Zankel 		     "fpu "
6295a0015d6SChris Zankel #endif
6302f6ea6a7SMax Filippov #if XCHAL_HAVE_S32C1I
6312f6ea6a7SMax Filippov 		     "s32c1i "
6322f6ea6a7SMax Filippov #endif
633f7c34874SMax Filippov #if XCHAL_HAVE_EXCLUSIVE
634f7c34874SMax Filippov 		     "exclusive "
635f7c34874SMax Filippov #endif
6365a0015d6SChris Zankel 		     "\n");
6375a0015d6SChris Zankel 
6385a0015d6SChris Zankel 	/* Registers. */
6395a0015d6SChris Zankel 	seq_printf(f,"physical aregs\t: %d\n"
6405a0015d6SChris Zankel 		     "misc regs\t: %d\n"
6415a0015d6SChris Zankel 		     "ibreak\t\t: %d\n"
642e6807b44SMax Filippov 		     "dbreak\t\t: %d\n"
643e6807b44SMax Filippov 		     "perf counters\t: %d\n",
6445a0015d6SChris Zankel 		     XCHAL_NUM_AREGS,
6455a0015d6SChris Zankel 		     XCHAL_NUM_MISC_REGS,
6465a0015d6SChris Zankel 		     XCHAL_NUM_IBREAK,
647e6807b44SMax Filippov 		     XCHAL_NUM_DBREAK,
648e6807b44SMax Filippov 		     XCHAL_NUM_PERF_COUNTERS);
6495a0015d6SChris Zankel 
6505a0015d6SChris Zankel 
6515a0015d6SChris Zankel 	/* Interrupt. */
6525a0015d6SChris Zankel 	seq_printf(f,"num ints\t: %d\n"
6535a0015d6SChris Zankel 		     "ext ints\t: %d\n"
6545a0015d6SChris Zankel 		     "int levels\t: %d\n"
6555a0015d6SChris Zankel 		     "timers\t\t: %d\n"
6565a0015d6SChris Zankel 		     "debug level\t: %d\n",
6575a0015d6SChris Zankel 		     XCHAL_NUM_INTERRUPTS,
6585a0015d6SChris Zankel 		     XCHAL_NUM_EXTINTERRUPTS,
6595a0015d6SChris Zankel 		     XCHAL_NUM_INTLEVELS,
6605a0015d6SChris Zankel 		     XCHAL_NUM_TIMERS,
6615a0015d6SChris Zankel 		     XCHAL_DEBUGLEVEL);
6625a0015d6SChris Zankel 
6635a0015d6SChris Zankel 	/* Cache */
6645a0015d6SChris Zankel 	seq_printf(f,"icache line size: %d\n"
6655a0015d6SChris Zankel 		     "icache ways\t: %d\n"
6665a0015d6SChris Zankel 		     "icache size\t: %d\n"
6675a0015d6SChris Zankel 		     "icache flags\t: "
6685a0015d6SChris Zankel #if XCHAL_ICACHE_LINE_LOCKABLE
6695a0015d6SChris Zankel 		     "lock "
6705a0015d6SChris Zankel #endif
6715a0015d6SChris Zankel 		     "\n"
6725a0015d6SChris Zankel 		     "dcache line size: %d\n"
6735a0015d6SChris Zankel 		     "dcache ways\t: %d\n"
6745a0015d6SChris Zankel 		     "dcache size\t: %d\n"
6755a0015d6SChris Zankel 		     "dcache flags\t: "
6765a0015d6SChris Zankel #if XCHAL_DCACHE_IS_WRITEBACK
6775a0015d6SChris Zankel 		     "writeback "
6785a0015d6SChris Zankel #endif
6795a0015d6SChris Zankel #if XCHAL_DCACHE_LINE_LOCKABLE
6805a0015d6SChris Zankel 		     "lock "
6815a0015d6SChris Zankel #endif
6825a0015d6SChris Zankel 		     "\n",
6835a0015d6SChris Zankel 		     XCHAL_ICACHE_LINESIZE,
6845a0015d6SChris Zankel 		     XCHAL_ICACHE_WAYS,
6855a0015d6SChris Zankel 		     XCHAL_ICACHE_SIZE,
6865a0015d6SChris Zankel 		     XCHAL_DCACHE_LINESIZE,
6875a0015d6SChris Zankel 		     XCHAL_DCACHE_WAYS,
6885a0015d6SChris Zankel 		     XCHAL_DCACHE_SIZE);
6895a0015d6SChris Zankel 
6905a0015d6SChris Zankel 	return 0;
6915a0015d6SChris Zankel }
6925a0015d6SChris Zankel 
6935a0015d6SChris Zankel /*
6945a0015d6SChris Zankel  * We show only CPU #0 info.
6955a0015d6SChris Zankel  */
6965a0015d6SChris Zankel static void *
c_start(struct seq_file * f,loff_t * pos)6975a0015d6SChris Zankel c_start(struct seq_file *f, loff_t *pos)
6985a0015d6SChris Zankel {
699f615136cSMax Filippov 	return (*pos == 0) ? (void *)1 : NULL;
7005a0015d6SChris Zankel }
7015a0015d6SChris Zankel 
7025a0015d6SChris Zankel static void *
c_next(struct seq_file * f,void * v,loff_t * pos)7035a0015d6SChris Zankel c_next(struct seq_file *f, void *v, loff_t *pos)
7045a0015d6SChris Zankel {
7050d5ab144SMax Filippov 	++*pos;
7060d5ab144SMax Filippov 	return c_start(f, pos);
7075a0015d6SChris Zankel }
7085a0015d6SChris Zankel 
7095a0015d6SChris Zankel static void
c_stop(struct seq_file * f,void * v)7105a0015d6SChris Zankel c_stop(struct seq_file *f, void *v)
7115a0015d6SChris Zankel {
7125a0015d6SChris Zankel }
7135a0015d6SChris Zankel 
71403a44825SJan Engelhardt const struct seq_operations cpuinfo_op =
7155a0015d6SChris Zankel {
716f615136cSMax Filippov 	.start	= c_start,
717f615136cSMax Filippov 	.next	= c_next,
718f615136cSMax Filippov 	.stop	= c_stop,
719f615136cSMax Filippov 	.show	= c_show,
7205a0015d6SChris Zankel };
7215a0015d6SChris Zankel 
7225a0015d6SChris Zankel #endif /* CONFIG_PROC_FS */
723