xref: /openbmc/linux/arch/arm/kernel/setup.c (revision 254cdf8e)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/arch/arm/kernel/setup.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  Copyright (C) 1995-2001 Russell King
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
71da177e4SLinus Torvalds  * it under the terms of the GNU General Public License version 2 as
81da177e4SLinus Torvalds  * published by the Free Software Foundation.
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds #include <linux/module.h>
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/stddef.h>
131da177e4SLinus Torvalds #include <linux/ioport.h>
141da177e4SLinus Torvalds #include <linux/delay.h>
151da177e4SLinus Torvalds #include <linux/utsname.h>
161da177e4SLinus Torvalds #include <linux/initrd.h>
171da177e4SLinus Torvalds #include <linux/console.h>
181da177e4SLinus Torvalds #include <linux/bootmem.h>
191da177e4SLinus Torvalds #include <linux/seq_file.h>
20894673eeSJon Smirl #include <linux/screen_info.h>
211da177e4SLinus Torvalds #include <linux/init.h>
223c57fb43SMika Westerberg #include <linux/kexec.h>
2393c02ab4SGrant Likely #include <linux/of_fdt.h>
24cea0bb1bSMika Westerberg #include <linux/crash_dump.h>
251da177e4SLinus Torvalds #include <linux/root_dev.h>
261da177e4SLinus Torvalds #include <linux/cpu.h>
271da177e4SLinus Torvalds #include <linux/interrupt.h>
287bbb7940SRussell King #include <linux/smp.h>
294e950f6fSAlexey Dobriyan #include <linux/fs.h>
30e119bfffSRussell King #include <linux/proc_fs.h>
312778f620SRussell King #include <linux/memblock.h>
321da177e4SLinus Torvalds 
33b86040a5SCatalin Marinas #include <asm/unified.h>
341da177e4SLinus Torvalds #include <asm/cpu.h>
350ba8b9b2SRussell King #include <asm/cputype.h>
361da177e4SLinus Torvalds #include <asm/elf.h>
371da177e4SLinus Torvalds #include <asm/procinfo.h>
3837efe642SRussell King #include <asm/sections.h>
391da177e4SLinus Torvalds #include <asm/setup.h>
40f00ec48fSRussell King #include <asm/smp_plat.h>
411da177e4SLinus Torvalds #include <asm/mach-types.h>
421da177e4SLinus Torvalds #include <asm/cacheflush.h>
4346097c7dSRussell King #include <asm/cachetype.h>
441da177e4SLinus Torvalds #include <asm/tlbflush.h>
451da177e4SLinus Torvalds 
4693c02ab4SGrant Likely #include <asm/prom.h>
471da177e4SLinus Torvalds #include <asm/mach/arch.h>
481da177e4SLinus Torvalds #include <asm/mach/irq.h>
491da177e4SLinus Torvalds #include <asm/mach/time.h>
505cbad0ebSJason Wessel #include <asm/traps.h>
51bff595c1SCatalin Marinas #include <asm/unwind.h>
521da177e4SLinus Torvalds 
5373a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
540fc1c832SBen Dooks #include "compat.h"
5573a65b3fSUwe Kleine-König #endif
564cd9d6f7SRichard Purdie #include "atags.h"
57bc581770SLinus Walleij #include "tcm.h"
580fc1c832SBen Dooks 
591da177e4SLinus Torvalds #ifndef MEM_SIZE
601da177e4SLinus Torvalds #define MEM_SIZE	(16*1024*1024)
611da177e4SLinus Torvalds #endif
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
641da177e4SLinus Torvalds char fpe_type[8];
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds static int __init fpe_setup(char *line)
671da177e4SLinus Torvalds {
681da177e4SLinus Torvalds 	memcpy(fpe_type, line, 8);
691da177e4SLinus Torvalds 	return 1;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds __setup("fpe=", fpe_setup);
731da177e4SLinus Torvalds #endif
741da177e4SLinus Torvalds 
754b5f32ceSNicolas Pitre extern void paging_init(struct machine_desc *desc);
761da177e4SLinus Torvalds extern void reboot_setup(char *str);
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds unsigned int processor_id;
79c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id);
800385ebc0SRussell King unsigned int __machine_arch_type __read_mostly;
811da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type);
820385ebc0SRussell King unsigned int cacheid __read_mostly;
83c0e95878SRussell King EXPORT_SYMBOL(cacheid);
841da177e4SLinus Torvalds 
859d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata;
869d20fdd5SBill Gatliff 
871da177e4SLinus Torvalds unsigned int system_rev;
881da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev);
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds unsigned int system_serial_low;
911da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low);
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds unsigned int system_serial_high;
941da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high);
951da177e4SLinus Torvalds 
960385ebc0SRussell King unsigned int elf_hwcap __read_mostly;
971da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap);
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds #ifdef MULTI_CPU
1010385ebc0SRussell King struct processor processor __read_mostly;
1021da177e4SLinus Torvalds #endif
1031da177e4SLinus Torvalds #ifdef MULTI_TLB
1040385ebc0SRussell King struct cpu_tlb_fns cpu_tlb __read_mostly;
1051da177e4SLinus Torvalds #endif
1061da177e4SLinus Torvalds #ifdef MULTI_USER
1070385ebc0SRussell King struct cpu_user_fns cpu_user __read_mostly;
1081da177e4SLinus Torvalds #endif
1091da177e4SLinus Torvalds #ifdef MULTI_CACHE
1100385ebc0SRussell King struct cpu_cache_fns cpu_cache __read_mostly;
1111da177e4SLinus Torvalds #endif
112953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE
1130385ebc0SRussell King struct outer_cache_fns outer_cache __read_mostly;
1146c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache);
115953233dcSCatalin Marinas #endif
1161da177e4SLinus Torvalds 
117ccea7a19SRussell King struct stack {
118ccea7a19SRussell King 	u32 irq[3];
119ccea7a19SRussell King 	u32 abt[3];
120ccea7a19SRussell King 	u32 und[3];
121ccea7a19SRussell King } ____cacheline_aligned;
122ccea7a19SRussell King 
123ccea7a19SRussell King static struct stack stacks[NR_CPUS];
124ccea7a19SRussell King 
1251da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE];
1261da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform);
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds static const char *cpu_name;
1291da177e4SLinus Torvalds static const char *machine_name;
13048ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE];
1318ff1443cSRussell King struct machine_desc *machine_desc __initdata;
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
1341da177e4SLinus Torvalds static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
1351da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l)
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds /*
1401da177e4SLinus Torvalds  * Standard memory resources
1411da177e4SLinus Torvalds  */
1421da177e4SLinus Torvalds static struct resource mem_res[] = {
143740e518eSGreg Kroah-Hartman 	{
144740e518eSGreg Kroah-Hartman 		.name = "Video RAM",
145740e518eSGreg Kroah-Hartman 		.start = 0,
146740e518eSGreg Kroah-Hartman 		.end = 0,
147740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
148740e518eSGreg Kroah-Hartman 	},
149740e518eSGreg Kroah-Hartman 	{
150740e518eSGreg Kroah-Hartman 		.name = "Kernel text",
151740e518eSGreg Kroah-Hartman 		.start = 0,
152740e518eSGreg Kroah-Hartman 		.end = 0,
153740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
154740e518eSGreg Kroah-Hartman 	},
155740e518eSGreg Kroah-Hartman 	{
156740e518eSGreg Kroah-Hartman 		.name = "Kernel data",
157740e518eSGreg Kroah-Hartman 		.start = 0,
158740e518eSGreg Kroah-Hartman 		.end = 0,
159740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
160740e518eSGreg Kroah-Hartman 	}
1611da177e4SLinus Torvalds };
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds #define video_ram   mem_res[0]
1641da177e4SLinus Torvalds #define kernel_code mem_res[1]
1651da177e4SLinus Torvalds #define kernel_data mem_res[2]
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds static struct resource io_res[] = {
168740e518eSGreg Kroah-Hartman 	{
169740e518eSGreg Kroah-Hartman 		.name = "reserved",
170740e518eSGreg Kroah-Hartman 		.start = 0x3bc,
171740e518eSGreg Kroah-Hartman 		.end = 0x3be,
172740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
173740e518eSGreg Kroah-Hartman 	},
174740e518eSGreg Kroah-Hartman 	{
175740e518eSGreg Kroah-Hartman 		.name = "reserved",
176740e518eSGreg Kroah-Hartman 		.start = 0x378,
177740e518eSGreg Kroah-Hartman 		.end = 0x37f,
178740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
179740e518eSGreg Kroah-Hartman 	},
180740e518eSGreg Kroah-Hartman 	{
181740e518eSGreg Kroah-Hartman 		.name = "reserved",
182740e518eSGreg Kroah-Hartman 		.start = 0x278,
183740e518eSGreg Kroah-Hartman 		.end = 0x27f,
184740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
185740e518eSGreg Kroah-Hartman 	}
1861da177e4SLinus Torvalds };
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds #define lp0 io_res[0]
1891da177e4SLinus Torvalds #define lp1 io_res[1]
1901da177e4SLinus Torvalds #define lp2 io_res[2]
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds static const char *proc_arch[] = {
1931da177e4SLinus Torvalds 	"undefined/unknown",
1941da177e4SLinus Torvalds 	"3",
1951da177e4SLinus Torvalds 	"4",
1961da177e4SLinus Torvalds 	"4T",
1971da177e4SLinus Torvalds 	"5",
1981da177e4SLinus Torvalds 	"5T",
1991da177e4SLinus Torvalds 	"5TE",
2001da177e4SLinus Torvalds 	"5TEJ",
2011da177e4SLinus Torvalds 	"6TEJ",
2026b090a25SCatalin Marinas 	"7",
2031da177e4SLinus Torvalds 	"?(11)",
2041da177e4SLinus Torvalds 	"?(12)",
2051da177e4SLinus Torvalds 	"?(13)",
2061da177e4SLinus Torvalds 	"?(14)",
2071da177e4SLinus Torvalds 	"?(15)",
2081da177e4SLinus Torvalds 	"?(16)",
2091da177e4SLinus Torvalds 	"?(17)",
2101da177e4SLinus Torvalds };
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds int cpu_architecture(void)
2131da177e4SLinus Torvalds {
2141da177e4SLinus Torvalds 	int cpu_arch;
2151da177e4SLinus Torvalds 
2160ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0) {
2171da177e4SLinus Torvalds 		cpu_arch = CPU_ARCH_UNKNOWN;
2180ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
2190ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
2200ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
2210ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() >> 16) & 7;
2221da177e4SLinus Torvalds 		if (cpu_arch)
2231da177e4SLinus Torvalds 			cpu_arch += CPU_ARCH_ARMv3;
2240ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
225180005c4SCatalin Marinas 		unsigned int mmfr0;
226180005c4SCatalin Marinas 
227180005c4SCatalin Marinas 		/* Revised CPUID format. Read the Memory Model Feature
228180005c4SCatalin Marinas 		 * Register 0 and check for VMSAv7 or PMSAv7 */
229180005c4SCatalin Marinas 		asm("mrc	p15, 0, %0, c0, c1, 4"
230180005c4SCatalin Marinas 		    : "=r" (mmfr0));
231315cfe78SCatalin Marinas 		if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
232315cfe78SCatalin Marinas 		    (mmfr0 & 0x000000f0) >= 0x00000030)
233180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv7;
234180005c4SCatalin Marinas 		else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
235180005c4SCatalin Marinas 			 (mmfr0 & 0x000000f0) == 0x00000020)
236180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv6;
237180005c4SCatalin Marinas 		else
238180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_UNKNOWN;
239180005c4SCatalin Marinas 	} else
240180005c4SCatalin Marinas 		cpu_arch = CPU_ARCH_UNKNOWN;
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds 	return cpu_arch;
2431da177e4SLinus Torvalds }
2441da177e4SLinus Torvalds 
2458925ec4cSWill Deacon static int cpu_has_aliasing_icache(unsigned int arch)
2468925ec4cSWill Deacon {
2478925ec4cSWill Deacon 	int aliasing_icache;
2488925ec4cSWill Deacon 	unsigned int id_reg, num_sets, line_size;
2498925ec4cSWill Deacon 
2508925ec4cSWill Deacon 	/* arch specifies the register format */
2518925ec4cSWill Deacon 	switch (arch) {
2528925ec4cSWill Deacon 	case CPU_ARCH_ARMv7:
2535fb31a96SLinus Walleij 		asm("mcr	p15, 2, %0, c0, c0, 0 @ set CSSELR"
2545fb31a96SLinus Walleij 		    : /* No output operands */
2558925ec4cSWill Deacon 		    : "r" (1));
2565fb31a96SLinus Walleij 		isb();
2575fb31a96SLinus Walleij 		asm("mrc	p15, 1, %0, c0, c0, 0 @ read CCSIDR"
2585fb31a96SLinus Walleij 		    : "=r" (id_reg));
2598925ec4cSWill Deacon 		line_size = 4 << ((id_reg & 0x7) + 2);
2608925ec4cSWill Deacon 		num_sets = ((id_reg >> 13) & 0x7fff) + 1;
2618925ec4cSWill Deacon 		aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
2628925ec4cSWill Deacon 		break;
2638925ec4cSWill Deacon 	case CPU_ARCH_ARMv6:
2648925ec4cSWill Deacon 		aliasing_icache = read_cpuid_cachetype() & (1 << 11);
2658925ec4cSWill Deacon 		break;
2668925ec4cSWill Deacon 	default:
2678925ec4cSWill Deacon 		/* I-cache aliases will be handled by D-cache aliasing code */
2688925ec4cSWill Deacon 		aliasing_icache = 0;
2698925ec4cSWill Deacon 	}
2708925ec4cSWill Deacon 
2718925ec4cSWill Deacon 	return aliasing_icache;
2728925ec4cSWill Deacon }
2738925ec4cSWill Deacon 
274c0e95878SRussell King static void __init cacheid_init(void)
275c0e95878SRussell King {
276c0e95878SRussell King 	unsigned int cachetype = read_cpuid_cachetype();
277c0e95878SRussell King 	unsigned int arch = cpu_architecture();
278c0e95878SRussell King 
279b57ee99fSCatalin Marinas 	if (arch >= CPU_ARCH_ARMv6) {
280b57ee99fSCatalin Marinas 		if ((cachetype & (7 << 29)) == 4 << 29) {
281b57ee99fSCatalin Marinas 			/* ARMv7 register format */
282c0e95878SRussell King 			cacheid = CACHEID_VIPT_NONALIASING;
283c0e95878SRussell King 			if ((cachetype & (3 << 14)) == 1 << 14)
284c0e95878SRussell King 				cacheid |= CACHEID_ASID_TAGGED;
2858925ec4cSWill Deacon 			else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7))
2868925ec4cSWill Deacon 				cacheid |= CACHEID_VIPT_I_ALIASING;
2878925ec4cSWill Deacon 		} else if (cachetype & (1 << 23)) {
288c0e95878SRussell King 			cacheid = CACHEID_VIPT_ALIASING;
2898925ec4cSWill Deacon 		} else {
290c0e95878SRussell King 			cacheid = CACHEID_VIPT_NONALIASING;
2918925ec4cSWill Deacon 			if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6))
2928925ec4cSWill Deacon 				cacheid |= CACHEID_VIPT_I_ALIASING;
2938925ec4cSWill Deacon 		}
294c0e95878SRussell King 	} else {
295c0e95878SRussell King 		cacheid = CACHEID_VIVT;
296c0e95878SRussell King 	}
2972b4ae1f1SRussell King 
2982b4ae1f1SRussell King 	printk("CPU: %s data cache, %s instruction cache\n",
2992b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3002b4ae1f1SRussell King 		cache_is_vipt_aliasing() ? "VIPT aliasing" :
3012b4ae1f1SRussell King 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown",
3022b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3032b4ae1f1SRussell King 		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
3048925ec4cSWill Deacon 		icache_is_vipt_aliasing() ? "VIPT aliasing" :
3052b4ae1f1SRussell King 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
306c0e95878SRussell King }
307c0e95878SRussell King 
3081da177e4SLinus Torvalds /*
3091da177e4SLinus Torvalds  * These functions re-use the assembly code in head.S, which
3101da177e4SLinus Torvalds  * already provide the required functionality.
3111da177e4SLinus Torvalds  */
3120f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int);
3136fc31d54SRussell King 
31493c02ab4SGrant Likely void __init early_print(const char *str, ...)
3156fc31d54SRussell King {
3166fc31d54SRussell King 	extern void printascii(const char *);
3176fc31d54SRussell King 	char buf[256];
3186fc31d54SRussell King 	va_list ap;
3196fc31d54SRussell King 
3206fc31d54SRussell King 	va_start(ap, str);
3216fc31d54SRussell King 	vsnprintf(buf, sizeof(buf), str, ap);
3226fc31d54SRussell King 	va_end(ap);
3236fc31d54SRussell King 
3246fc31d54SRussell King #ifdef CONFIG_DEBUG_LL
3256fc31d54SRussell King 	printascii(buf);
3266fc31d54SRussell King #endif
3276fc31d54SRussell King 	printk("%s", buf);
3286fc31d54SRussell King }
3296fc31d54SRussell King 
330f159f4edSTony Lindgren static void __init feat_v6_fixup(void)
331f159f4edSTony Lindgren {
332f159f4edSTony Lindgren 	int id = read_cpuid_id();
333f159f4edSTony Lindgren 
334f159f4edSTony Lindgren 	if ((id & 0xff0f0000) != 0x41070000)
335f159f4edSTony Lindgren 		return;
336f159f4edSTony Lindgren 
337f159f4edSTony Lindgren 	/*
338f159f4edSTony Lindgren 	 * HWCAP_TLS is available only on 1136 r1p0 and later,
339f159f4edSTony Lindgren 	 * see also kuser_get_tls_init.
340f159f4edSTony Lindgren 	 */
341f159f4edSTony Lindgren 	if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0))
342f159f4edSTony Lindgren 		elf_hwcap &= ~HWCAP_TLS;
343f159f4edSTony Lindgren }
344f159f4edSTony Lindgren 
3451da177e4SLinus Torvalds static void __init setup_processor(void)
3461da177e4SLinus Torvalds {
3471da177e4SLinus Torvalds 	struct proc_info_list *list;
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 	/*
3501da177e4SLinus Torvalds 	 * locate processor in the list of supported processor
3511da177e4SLinus Torvalds 	 * types.  The linker builds this table for us from the
3521da177e4SLinus Torvalds 	 * entries in arch/arm/mm/proc-*.S
3531da177e4SLinus Torvalds 	 */
3540ba8b9b2SRussell King 	list = lookup_processor_type(read_cpuid_id());
3551da177e4SLinus Torvalds 	if (!list) {
3561da177e4SLinus Torvalds 		printk("CPU configuration botched (ID %08x), unable "
3570ba8b9b2SRussell King 		       "to continue.\n", read_cpuid_id());
3581da177e4SLinus Torvalds 		while (1);
3591da177e4SLinus Torvalds 	}
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds 	cpu_name = list->cpu_name;
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds #ifdef MULTI_CPU
3641da177e4SLinus Torvalds 	processor = *list->proc;
3651da177e4SLinus Torvalds #endif
3661da177e4SLinus Torvalds #ifdef MULTI_TLB
3671da177e4SLinus Torvalds 	cpu_tlb = *list->tlb;
3681da177e4SLinus Torvalds #endif
3691da177e4SLinus Torvalds #ifdef MULTI_USER
3701da177e4SLinus Torvalds 	cpu_user = *list->user;
3711da177e4SLinus Torvalds #endif
3721da177e4SLinus Torvalds #ifdef MULTI_CACHE
3731da177e4SLinus Torvalds 	cpu_cache = *list->cache;
3741da177e4SLinus Torvalds #endif
3751da177e4SLinus Torvalds 
3764e19025bSRussell King 	printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
3770ba8b9b2SRussell King 	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
378264edb35SRussell King 	       proc_arch[cpu_architecture()], cr_alignment);
3791da177e4SLinus Torvalds 
38096b644bdSSerge E. Hallyn 	sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
3811da177e4SLinus Torvalds 	sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
3821da177e4SLinus Torvalds 	elf_hwcap = list->elf_hwcap;
383adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB
384adeff422SCatalin Marinas 	elf_hwcap &= ~HWCAP_THUMB;
385adeff422SCatalin Marinas #endif
3861da177e4SLinus Torvalds 
387f159f4edSTony Lindgren 	feat_v6_fixup();
388f159f4edSTony Lindgren 
389c0e95878SRussell King 	cacheid_init();
3901da177e4SLinus Torvalds 	cpu_proc_init();
3911da177e4SLinus Torvalds }
3921da177e4SLinus Torvalds 
393ccea7a19SRussell King /*
394ccea7a19SRussell King  * cpu_init - initialise one CPU.
395ccea7a19SRussell King  *
39690f1e084SRussell King  * cpu_init sets up the per-CPU stacks.
397ccea7a19SRussell King  */
39836c5ed23SRussell King void cpu_init(void)
399ccea7a19SRussell King {
400ccea7a19SRussell King 	unsigned int cpu = smp_processor_id();
401ccea7a19SRussell King 	struct stack *stk = &stacks[cpu];
402ccea7a19SRussell King 
403ccea7a19SRussell King 	if (cpu >= NR_CPUS) {
404ccea7a19SRussell King 		printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
405ccea7a19SRussell King 		BUG();
406ccea7a19SRussell King 	}
407ccea7a19SRussell King 
408ccea7a19SRussell King 	/*
409b86040a5SCatalin Marinas 	 * Define the placement constraint for the inline asm directive below.
410b86040a5SCatalin Marinas 	 * In Thumb-2, msr with an immediate value is not allowed.
411b86040a5SCatalin Marinas 	 */
412b86040a5SCatalin Marinas #ifdef CONFIG_THUMB2_KERNEL
413b86040a5SCatalin Marinas #define PLC	"r"
414b86040a5SCatalin Marinas #else
415b86040a5SCatalin Marinas #define PLC	"I"
416b86040a5SCatalin Marinas #endif
417b86040a5SCatalin Marinas 
418b86040a5SCatalin Marinas 	/*
419ccea7a19SRussell King 	 * setup stacks for re-entrant exception handlers
420ccea7a19SRussell King 	 */
421ccea7a19SRussell King 	__asm__ (
422ccea7a19SRussell King 	"msr	cpsr_c, %1\n\t"
423b86040a5SCatalin Marinas 	"add	r14, %0, %2\n\t"
424b86040a5SCatalin Marinas 	"mov	sp, r14\n\t"
425ccea7a19SRussell King 	"msr	cpsr_c, %3\n\t"
426b86040a5SCatalin Marinas 	"add	r14, %0, %4\n\t"
427b86040a5SCatalin Marinas 	"mov	sp, r14\n\t"
428ccea7a19SRussell King 	"msr	cpsr_c, %5\n\t"
429b86040a5SCatalin Marinas 	"add	r14, %0, %6\n\t"
430b86040a5SCatalin Marinas 	"mov	sp, r14\n\t"
431ccea7a19SRussell King 	"msr	cpsr_c, %7"
432ccea7a19SRussell King 	    :
433ccea7a19SRussell King 	    : "r" (stk),
434b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
435ccea7a19SRussell King 	      "I" (offsetof(struct stack, irq[0])),
436b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
437ccea7a19SRussell King 	      "I" (offsetof(struct stack, abt[0])),
438b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
439ccea7a19SRussell King 	      "I" (offsetof(struct stack, und[0])),
440b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
441aaaa3f9eSCatalin Marinas 	    : "r14");
442ccea7a19SRussell King }
443ccea7a19SRussell King 
44493c02ab4SGrant Likely void __init dump_machine_table(void)
4451da177e4SLinus Torvalds {
446dce72dd0SNicolas Pitre 	struct machine_desc *p;
4471da177e4SLinus Torvalds 
4486291319dSGrant Likely 	early_print("Available machine support:\n\nID (hex)\tNAME\n");
4496291319dSGrant Likely 	for_each_machine_desc(p)
450dce72dd0SNicolas Pitre 		early_print("%08x\t%s\n", p->nr, p->name);
451dce72dd0SNicolas Pitre 
452dce72dd0SNicolas Pitre 	early_print("\nPlease check your kernel config and/or bootloader.\n");
453dce72dd0SNicolas Pitre 
454dce72dd0SNicolas Pitre 	while (true)
455dce72dd0SNicolas Pitre 		/* can't use cpu_relax() here as it may require MMU setup */;
4561da177e4SLinus Torvalds }
4571da177e4SLinus Torvalds 
4589eb8f674SGrant Likely int __init arm_add_memory(phys_addr_t start, unsigned long size)
4593a669411SRussell King {
4604b5f32ceSNicolas Pitre 	struct membank *bank = &meminfo.bank[meminfo.nr_banks];
4614b5f32ceSNicolas Pitre 
4624b5f32ceSNicolas Pitre 	if (meminfo.nr_banks >= NR_BANKS) {
4634b5f32ceSNicolas Pitre 		printk(KERN_CRIT "NR_BANKS too low, "
46429a38193SWill Deacon 			"ignoring memory at 0x%08llx\n", (long long)start);
4654b5f32ceSNicolas Pitre 		return -EINVAL;
4664b5f32ceSNicolas Pitre 	}
46705f96ef1SRussell King 
4683a669411SRussell King 	/*
4693a669411SRussell King 	 * Ensure that start/size are aligned to a page boundary.
4703a669411SRussell King 	 * Size is appropriately rounded down, start is rounded up.
4713a669411SRussell King 	 */
4723a669411SRussell King 	size -= start & ~PAGE_MASK;
47305f96ef1SRussell King 	bank->start = PAGE_ALIGN(start);
47405f96ef1SRussell King 	bank->size  = size & PAGE_MASK;
4754b5f32ceSNicolas Pitre 
4764b5f32ceSNicolas Pitre 	/*
4774b5f32ceSNicolas Pitre 	 * Check whether this memory region has non-zero size or
4784b5f32ceSNicolas Pitre 	 * invalid node number.
4794b5f32ceSNicolas Pitre 	 */
480be370302SRussell King 	if (bank->size == 0)
4814b5f32ceSNicolas Pitre 		return -EINVAL;
4824b5f32ceSNicolas Pitre 
4834b5f32ceSNicolas Pitre 	meminfo.nr_banks++;
4844b5f32ceSNicolas Pitre 	return 0;
4853a669411SRussell King }
4863a669411SRussell King 
4871da177e4SLinus Torvalds /*
4881da177e4SLinus Torvalds  * Pick out the memory size.  We look for mem=size@start,
4891da177e4SLinus Torvalds  * where start and size are "size[KkMm]"
4901da177e4SLinus Torvalds  */
4912b0d8c25SJeremy Kerr static int __init early_mem(char *p)
4921da177e4SLinus Torvalds {
4931da177e4SLinus Torvalds 	static int usermem __initdata = 0;
494f60892d3SWill Deacon 	unsigned long size;
495f60892d3SWill Deacon 	phys_addr_t start;
4962b0d8c25SJeremy Kerr 	char *endp;
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds 	/*
4991da177e4SLinus Torvalds 	 * If the user specifies memory size, we
5001da177e4SLinus Torvalds 	 * blow away any automatically generated
5011da177e4SLinus Torvalds 	 * size.
5021da177e4SLinus Torvalds 	 */
5031da177e4SLinus Torvalds 	if (usermem == 0) {
5041da177e4SLinus Torvalds 		usermem = 1;
5051da177e4SLinus Torvalds 		meminfo.nr_banks = 0;
5061da177e4SLinus Torvalds 	}
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds 	start = PHYS_OFFSET;
5092b0d8c25SJeremy Kerr 	size  = memparse(p, &endp);
5102b0d8c25SJeremy Kerr 	if (*endp == '@')
5112b0d8c25SJeremy Kerr 		start = memparse(endp + 1, NULL);
5121da177e4SLinus Torvalds 
5131c97b73eSAndrew Morton 	arm_add_memory(start, size);
5141da177e4SLinus Torvalds 
5152b0d8c25SJeremy Kerr 	return 0;
5161da177e4SLinus Torvalds }
5172b0d8c25SJeremy Kerr early_param("mem", early_mem);
5181da177e4SLinus Torvalds 
5191da177e4SLinus Torvalds static void __init
5201da177e4SLinus Torvalds setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
5211da177e4SLinus Torvalds {
5221da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_RAM
5231da177e4SLinus Torvalds 	extern int rd_size, rd_image_start, rd_prompt, rd_doload;
5241da177e4SLinus Torvalds 
5251da177e4SLinus Torvalds 	rd_image_start = image_start;
5261da177e4SLinus Torvalds 	rd_prompt = prompt;
5271da177e4SLinus Torvalds 	rd_doload = doload;
5281da177e4SLinus Torvalds 
5291da177e4SLinus Torvalds 	if (rd_sz)
5301da177e4SLinus Torvalds 		rd_size = rd_sz;
5311da177e4SLinus Torvalds #endif
5321da177e4SLinus Torvalds }
5331da177e4SLinus Torvalds 
53411b9369cSDima Zavin static void __init request_standard_resources(struct machine_desc *mdesc)
5351da177e4SLinus Torvalds {
53611b9369cSDima Zavin 	struct memblock_region *region;
5371da177e4SLinus Torvalds 	struct resource *res;
5381da177e4SLinus Torvalds 
53937efe642SRussell King 	kernel_code.start   = virt_to_phys(_text);
54037efe642SRussell King 	kernel_code.end     = virt_to_phys(_etext - 1);
541842eab40SRussell King 	kernel_data.start   = virt_to_phys(_sdata);
54237efe642SRussell King 	kernel_data.end     = virt_to_phys(_end - 1);
5431da177e4SLinus Torvalds 
54411b9369cSDima Zavin 	for_each_memblock(memory, region) {
5451da177e4SLinus Torvalds 		res = alloc_bootmem_low(sizeof(*res));
5461da177e4SLinus Torvalds 		res->name  = "System RAM";
54711b9369cSDima Zavin 		res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
54811b9369cSDima Zavin 		res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
5491da177e4SLinus Torvalds 		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
5501da177e4SLinus Torvalds 
5511da177e4SLinus Torvalds 		request_resource(&iomem_resource, res);
5521da177e4SLinus Torvalds 
5531da177e4SLinus Torvalds 		if (kernel_code.start >= res->start &&
5541da177e4SLinus Torvalds 		    kernel_code.end <= res->end)
5551da177e4SLinus Torvalds 			request_resource(res, &kernel_code);
5561da177e4SLinus Torvalds 		if (kernel_data.start >= res->start &&
5571da177e4SLinus Torvalds 		    kernel_data.end <= res->end)
5581da177e4SLinus Torvalds 			request_resource(res, &kernel_data);
5591da177e4SLinus Torvalds 	}
5601da177e4SLinus Torvalds 
5611da177e4SLinus Torvalds 	if (mdesc->video_start) {
5621da177e4SLinus Torvalds 		video_ram.start = mdesc->video_start;
5631da177e4SLinus Torvalds 		video_ram.end   = mdesc->video_end;
5641da177e4SLinus Torvalds 		request_resource(&iomem_resource, &video_ram);
5651da177e4SLinus Torvalds 	}
5661da177e4SLinus Torvalds 
5671da177e4SLinus Torvalds 	/*
5681da177e4SLinus Torvalds 	 * Some machines don't have the possibility of ever
5691da177e4SLinus Torvalds 	 * possessing lp0, lp1 or lp2
5701da177e4SLinus Torvalds 	 */
5711da177e4SLinus Torvalds 	if (mdesc->reserve_lp0)
5721da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp0);
5731da177e4SLinus Torvalds 	if (mdesc->reserve_lp1)
5741da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp1);
5751da177e4SLinus Torvalds 	if (mdesc->reserve_lp2)
5761da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp2);
5771da177e4SLinus Torvalds }
5781da177e4SLinus Torvalds 
5791da177e4SLinus Torvalds /*
5801da177e4SLinus Torvalds  *  Tag parsing.
5811da177e4SLinus Torvalds  *
5821da177e4SLinus Torvalds  * This is the new way of passing data to the kernel at boot time.  Rather
5831da177e4SLinus Torvalds  * than passing a fixed inflexible structure to the kernel, we pass a list
5841da177e4SLinus Torvalds  * of variable-sized tags to the kernel.  The first tag must be a ATAG_CORE
5851da177e4SLinus Torvalds  * tag for the list to be recognised (to distinguish the tagged list from
5861da177e4SLinus Torvalds  * a param_struct).  The list is terminated with a zero-length tag (this tag
5871da177e4SLinus Torvalds  * is not parsed in any way).
5881da177e4SLinus Torvalds  */
5891da177e4SLinus Torvalds static int __init parse_tag_core(const struct tag *tag)
5901da177e4SLinus Torvalds {
5911da177e4SLinus Torvalds 	if (tag->hdr.size > 2) {
5921da177e4SLinus Torvalds 		if ((tag->u.core.flags & 1) == 0)
5931da177e4SLinus Torvalds 			root_mountflags &= ~MS_RDONLY;
5941da177e4SLinus Torvalds 		ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
5951da177e4SLinus Torvalds 	}
5961da177e4SLinus Torvalds 	return 0;
5971da177e4SLinus Torvalds }
5981da177e4SLinus Torvalds 
5991da177e4SLinus Torvalds __tagtable(ATAG_CORE, parse_tag_core);
6001da177e4SLinus Torvalds 
6011da177e4SLinus Torvalds static int __init parse_tag_mem32(const struct tag *tag)
6021da177e4SLinus Torvalds {
6034b5f32ceSNicolas Pitre 	return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
6041da177e4SLinus Torvalds }
6051da177e4SLinus Torvalds 
6061da177e4SLinus Torvalds __tagtable(ATAG_MEM, parse_tag_mem32);
6071da177e4SLinus Torvalds 
6081da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
6091da177e4SLinus Torvalds struct screen_info screen_info = {
6101da177e4SLinus Torvalds  .orig_video_lines	= 30,
6111da177e4SLinus Torvalds  .orig_video_cols	= 80,
6121da177e4SLinus Torvalds  .orig_video_mode	= 0,
6131da177e4SLinus Torvalds  .orig_video_ega_bx	= 0,
6141da177e4SLinus Torvalds  .orig_video_isVGA	= 1,
6151da177e4SLinus Torvalds  .orig_video_points	= 8
6161da177e4SLinus Torvalds };
6171da177e4SLinus Torvalds 
6181da177e4SLinus Torvalds static int __init parse_tag_videotext(const struct tag *tag)
6191da177e4SLinus Torvalds {
6201da177e4SLinus Torvalds 	screen_info.orig_x            = tag->u.videotext.x;
6211da177e4SLinus Torvalds 	screen_info.orig_y            = tag->u.videotext.y;
6221da177e4SLinus Torvalds 	screen_info.orig_video_page   = tag->u.videotext.video_page;
6231da177e4SLinus Torvalds 	screen_info.orig_video_mode   = tag->u.videotext.video_mode;
6241da177e4SLinus Torvalds 	screen_info.orig_video_cols   = tag->u.videotext.video_cols;
6251da177e4SLinus Torvalds 	screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
6261da177e4SLinus Torvalds 	screen_info.orig_video_lines  = tag->u.videotext.video_lines;
6271da177e4SLinus Torvalds 	screen_info.orig_video_isVGA  = tag->u.videotext.video_isvga;
6281da177e4SLinus Torvalds 	screen_info.orig_video_points = tag->u.videotext.video_points;
6291da177e4SLinus Torvalds 	return 0;
6301da177e4SLinus Torvalds }
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
6331da177e4SLinus Torvalds #endif
6341da177e4SLinus Torvalds 
6351da177e4SLinus Torvalds static int __init parse_tag_ramdisk(const struct tag *tag)
6361da177e4SLinus Torvalds {
6371da177e4SLinus Torvalds 	setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
6381da177e4SLinus Torvalds 		      (tag->u.ramdisk.flags & 2) == 0,
6391da177e4SLinus Torvalds 		      tag->u.ramdisk.start, tag->u.ramdisk.size);
6401da177e4SLinus Torvalds 	return 0;
6411da177e4SLinus Torvalds }
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds static int __init parse_tag_serialnr(const struct tag *tag)
6461da177e4SLinus Torvalds {
6471da177e4SLinus Torvalds 	system_serial_low = tag->u.serialnr.low;
6481da177e4SLinus Torvalds 	system_serial_high = tag->u.serialnr.high;
6491da177e4SLinus Torvalds 	return 0;
6501da177e4SLinus Torvalds }
6511da177e4SLinus Torvalds 
6521da177e4SLinus Torvalds __tagtable(ATAG_SERIAL, parse_tag_serialnr);
6531da177e4SLinus Torvalds 
6541da177e4SLinus Torvalds static int __init parse_tag_revision(const struct tag *tag)
6551da177e4SLinus Torvalds {
6561da177e4SLinus Torvalds 	system_rev = tag->u.revision.rev;
6571da177e4SLinus Torvalds 	return 0;
6581da177e4SLinus Torvalds }
6591da177e4SLinus Torvalds 
6601da177e4SLinus Torvalds __tagtable(ATAG_REVISION, parse_tag_revision);
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds static int __init parse_tag_cmdline(const struct tag *tag)
6631da177e4SLinus Torvalds {
6644394c124SVictor Boivie #if defined(CONFIG_CMDLINE_EXTEND)
6654394c124SVictor Boivie 	strlcat(default_command_line, " ", COMMAND_LINE_SIZE);
6664394c124SVictor Boivie 	strlcat(default_command_line, tag->u.cmdline.cmdline,
6674394c124SVictor Boivie 		COMMAND_LINE_SIZE);
6684394c124SVictor Boivie #elif defined(CONFIG_CMDLINE_FORCE)
66922eeb8f6SAlexander Holler 	pr_warning("Ignoring tag cmdline (using the default kernel command line)\n");
6704394c124SVictor Boivie #else
6714394c124SVictor Boivie 	strlcpy(default_command_line, tag->u.cmdline.cmdline,
6724394c124SVictor Boivie 		COMMAND_LINE_SIZE);
6734394c124SVictor Boivie #endif
6741da177e4SLinus Torvalds 	return 0;
6751da177e4SLinus Torvalds }
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
6781da177e4SLinus Torvalds 
6791da177e4SLinus Torvalds /*
6801da177e4SLinus Torvalds  * Scan the tag table for this tag, and call its parse function.
6811da177e4SLinus Torvalds  * The tag table is built by the linker from all the __tagtable
6821da177e4SLinus Torvalds  * declarations.
6831da177e4SLinus Torvalds  */
6841da177e4SLinus Torvalds static int __init parse_tag(const struct tag *tag)
6851da177e4SLinus Torvalds {
6861da177e4SLinus Torvalds 	extern struct tagtable __tagtable_begin, __tagtable_end;
6871da177e4SLinus Torvalds 	struct tagtable *t;
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds 	for (t = &__tagtable_begin; t < &__tagtable_end; t++)
6901da177e4SLinus Torvalds 		if (tag->hdr.tag == t->tag) {
6911da177e4SLinus Torvalds 			t->parse(tag);
6921da177e4SLinus Torvalds 			break;
6931da177e4SLinus Torvalds 		}
6941da177e4SLinus Torvalds 
6951da177e4SLinus Torvalds 	return t < &__tagtable_end;
6961da177e4SLinus Torvalds }
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds /*
6991da177e4SLinus Torvalds  * Parse all tags in the list, checking both the global and architecture
7001da177e4SLinus Torvalds  * specific tag tables.
7011da177e4SLinus Torvalds  */
7021da177e4SLinus Torvalds static void __init parse_tags(const struct tag *t)
7031da177e4SLinus Torvalds {
7041da177e4SLinus Torvalds 	for (; t->hdr.size; t = tag_next(t))
7051da177e4SLinus Torvalds 		if (!parse_tag(t))
7061da177e4SLinus Torvalds 			printk(KERN_WARNING
7071da177e4SLinus Torvalds 				"Ignoring unrecognised tag 0x%08x\n",
7081da177e4SLinus Torvalds 				t->hdr.tag);
7091da177e4SLinus Torvalds }
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds /*
7121da177e4SLinus Torvalds  * This holds our defaults.
7131da177e4SLinus Torvalds  */
7141da177e4SLinus Torvalds static struct init_tags {
7151da177e4SLinus Torvalds 	struct tag_header hdr1;
7161da177e4SLinus Torvalds 	struct tag_core   core;
7171da177e4SLinus Torvalds 	struct tag_header hdr2;
7181da177e4SLinus Torvalds 	struct tag_mem32  mem;
7191da177e4SLinus Torvalds 	struct tag_header hdr3;
7201da177e4SLinus Torvalds } init_tags __initdata = {
7211da177e4SLinus Torvalds 	{ tag_size(tag_core), ATAG_CORE },
7221da177e4SLinus Torvalds 	{ 1, PAGE_SIZE, 0xff },
7231da177e4SLinus Torvalds 	{ tag_size(tag_mem32), ATAG_MEM },
724b75c178aSRussell King 	{ MEM_SIZE },
7251da177e4SLinus Torvalds 	{ 0, ATAG_NONE }
7261da177e4SLinus Torvalds };
7271da177e4SLinus Torvalds 
7281da177e4SLinus Torvalds static int __init customize_machine(void)
7291da177e4SLinus Torvalds {
7301da177e4SLinus Torvalds 	/* customizes platform devices, or adds new ones */
7318ff1443cSRussell King 	if (machine_desc->init_machine)
7328ff1443cSRussell King 		machine_desc->init_machine();
7331da177e4SLinus Torvalds 	return 0;
7341da177e4SLinus Torvalds }
7351da177e4SLinus Torvalds arch_initcall(customize_machine);
7361da177e4SLinus Torvalds 
7373c57fb43SMika Westerberg #ifdef CONFIG_KEXEC
7383c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void)
7393c57fb43SMika Westerberg {
7403c57fb43SMika Westerberg 	unsigned long total;
7413c57fb43SMika Westerberg 
7423c57fb43SMika Westerberg 	total = max_low_pfn - min_low_pfn;
7433c57fb43SMika Westerberg 	return total << PAGE_SHIFT;
7443c57fb43SMika Westerberg }
7453c57fb43SMika Westerberg 
7463c57fb43SMika Westerberg /**
7473c57fb43SMika Westerberg  * reserve_crashkernel() - reserves memory are for crash kernel
7483c57fb43SMika Westerberg  *
7493c57fb43SMika Westerberg  * This function reserves memory area given in "crashkernel=" kernel command
7503c57fb43SMika Westerberg  * line parameter. The memory reserved is used by a dump capture kernel when
7513c57fb43SMika Westerberg  * primary kernel is crashing.
7523c57fb43SMika Westerberg  */
7533c57fb43SMika Westerberg static void __init reserve_crashkernel(void)
7543c57fb43SMika Westerberg {
7553c57fb43SMika Westerberg 	unsigned long long crash_size, crash_base;
7563c57fb43SMika Westerberg 	unsigned long long total_mem;
7573c57fb43SMika Westerberg 	int ret;
7583c57fb43SMika Westerberg 
7593c57fb43SMika Westerberg 	total_mem = get_total_mem();
7603c57fb43SMika Westerberg 	ret = parse_crashkernel(boot_command_line, total_mem,
7613c57fb43SMika Westerberg 				&crash_size, &crash_base);
7623c57fb43SMika Westerberg 	if (ret)
7633c57fb43SMika Westerberg 		return;
7643c57fb43SMika Westerberg 
7653c57fb43SMika Westerberg 	ret = reserve_bootmem(crash_base, crash_size, BOOTMEM_EXCLUSIVE);
7663c57fb43SMika Westerberg 	if (ret < 0) {
7673c57fb43SMika Westerberg 		printk(KERN_WARNING "crashkernel reservation failed - "
7683c57fb43SMika Westerberg 		       "memory is in use (0x%lx)\n", (unsigned long)crash_base);
7693c57fb43SMika Westerberg 		return;
7703c57fb43SMika Westerberg 	}
7713c57fb43SMika Westerberg 
7723c57fb43SMika Westerberg 	printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
7733c57fb43SMika Westerberg 	       "for crashkernel (System RAM: %ldMB)\n",
7743c57fb43SMika Westerberg 	       (unsigned long)(crash_size >> 20),
7753c57fb43SMika Westerberg 	       (unsigned long)(crash_base >> 20),
7763c57fb43SMika Westerberg 	       (unsigned long)(total_mem >> 20));
7773c57fb43SMika Westerberg 
7783c57fb43SMika Westerberg 	crashk_res.start = crash_base;
7793c57fb43SMika Westerberg 	crashk_res.end = crash_base + crash_size - 1;
7803c57fb43SMika Westerberg 	insert_resource(&iomem_resource, &crashk_res);
7813c57fb43SMika Westerberg }
7823c57fb43SMika Westerberg #else
7833c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {}
7843c57fb43SMika Westerberg #endif /* CONFIG_KEXEC */
7853c57fb43SMika Westerberg 
78673a65b3fSUwe Kleine-König static void __init squash_mem_tags(struct tag *tag)
78773a65b3fSUwe Kleine-König {
78873a65b3fSUwe Kleine-König 	for (; tag->hdr.size; tag = tag_next(tag))
78973a65b3fSUwe Kleine-König 		if (tag->hdr.tag == ATAG_MEM)
79073a65b3fSUwe Kleine-König 			tag->hdr.tag = ATAG_NONE;
79173a65b3fSUwe Kleine-König }
79273a65b3fSUwe Kleine-König 
7936291319dSGrant Likely static struct machine_desc * __init setup_machine_tags(unsigned int nr)
7941da177e4SLinus Torvalds {
7951da177e4SLinus Torvalds 	struct tag *tags = (struct tag *)&init_tags;
7966291319dSGrant Likely 	struct machine_desc *mdesc = NULL, *p;
7971da177e4SLinus Torvalds 	char *from = default_command_line;
7981da177e4SLinus Torvalds 
799b75c178aSRussell King 	init_tags.mem.start = PHYS_OFFSET;
800b75c178aSRussell King 
8016291319dSGrant Likely 	/*
8026291319dSGrant Likely 	 * locate machine in the list of supported machines.
8036291319dSGrant Likely 	 */
8046291319dSGrant Likely 	for_each_machine_desc(p)
8056291319dSGrant Likely 		if (nr == p->nr) {
8066291319dSGrant Likely 			printk("Machine: %s\n", p->name);
8076291319dSGrant Likely 			mdesc = p;
8086291319dSGrant Likely 			break;
8096291319dSGrant Likely 		}
810bff595c1SCatalin Marinas 
8116291319dSGrant Likely 	if (!mdesc) {
8126291319dSGrant Likely 		early_print("\nError: unrecognized/unsupported machine ID"
8136291319dSGrant Likely 			" (r1 = 0x%08x).\n\n", nr);
8146291319dSGrant Likely 		dump_machine_table(); /* does not return */
8156291319dSGrant Likely 	}
8161da177e4SLinus Torvalds 
8179d20fdd5SBill Gatliff 	if (__atags_pointer)
8189d20fdd5SBill Gatliff 		tags = phys_to_virt(__atags_pointer);
8193572bea8SNicolas Pitre 	else if (mdesc->boot_params) {
8203572bea8SNicolas Pitre #ifdef CONFIG_MMU
8213572bea8SNicolas Pitre 		/*
8223572bea8SNicolas Pitre 		 * We still are executing with a minimal MMU mapping created
8233572bea8SNicolas Pitre 		 * with the presumption that the machine default for this
8243572bea8SNicolas Pitre 		 * is located in the first MB of RAM.  Anything else will
8253572bea8SNicolas Pitre 		 * fault and silently hang the kernel at this point.
8263572bea8SNicolas Pitre 		 */
8273572bea8SNicolas Pitre 		if (mdesc->boot_params < PHYS_OFFSET ||
8283572bea8SNicolas Pitre 		    mdesc->boot_params >= PHYS_OFFSET + SZ_1M) {
8293572bea8SNicolas Pitre 			printk(KERN_WARNING
8303572bea8SNicolas Pitre 			       "Default boot params at physical 0x%08lx out of reach\n",
8313572bea8SNicolas Pitre 			       mdesc->boot_params);
8323572bea8SNicolas Pitre 		} else
8333572bea8SNicolas Pitre #endif
8343572bea8SNicolas Pitre 		{
835f9bd6ea4SRussell King 			tags = phys_to_virt(mdesc->boot_params);
8363572bea8SNicolas Pitre 		}
8373572bea8SNicolas Pitre 	}
8381da177e4SLinus Torvalds 
83973a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
8401da177e4SLinus Torvalds 	/*
8411da177e4SLinus Torvalds 	 * If we have the old style parameters, convert them to
8421da177e4SLinus Torvalds 	 * a tag list.
8431da177e4SLinus Torvalds 	 */
8441da177e4SLinus Torvalds 	if (tags->hdr.tag != ATAG_CORE)
8451da177e4SLinus Torvalds 		convert_to_tag_list(tags);
84673a65b3fSUwe Kleine-König #endif
84793c02ab4SGrant Likely 
84893c02ab4SGrant Likely 	if (tags->hdr.tag != ATAG_CORE) {
84993c02ab4SGrant Likely #if defined(CONFIG_OF)
85093c02ab4SGrant Likely 		/*
85193c02ab4SGrant Likely 		 * If CONFIG_OF is set, then assume this is a reasonably
85293c02ab4SGrant Likely 		 * modern system that should pass boot parameters
85393c02ab4SGrant Likely 		 */
85493c02ab4SGrant Likely 		early_print("Warning: Neither atags nor dtb found\n");
85593c02ab4SGrant Likely #endif
8561da177e4SLinus Torvalds 		tags = (struct tag *)&init_tags;
85793c02ab4SGrant Likely 	}
8581da177e4SLinus Torvalds 
8591da177e4SLinus Torvalds 	if (mdesc->fixup)
8601da177e4SLinus Torvalds 		mdesc->fixup(mdesc, tags, &from, &meminfo);
8611da177e4SLinus Torvalds 
8621da177e4SLinus Torvalds 	if (tags->hdr.tag == ATAG_CORE) {
8631da177e4SLinus Torvalds 		if (meminfo.nr_banks != 0)
8641da177e4SLinus Torvalds 			squash_mem_tags(tags);
8654cd9d6f7SRichard Purdie 		save_atags(tags);
8661da177e4SLinus Torvalds 		parse_tags(tags);
8671da177e4SLinus Torvalds 	}
8681da177e4SLinus Torvalds 
8696291319dSGrant Likely 	/* parse_early_param needs a boot_command_line */
8706291319dSGrant Likely 	strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
8716291319dSGrant Likely 
8726291319dSGrant Likely 	return mdesc;
8736291319dSGrant Likely }
8746291319dSGrant Likely 
8756291319dSGrant Likely 
8766291319dSGrant Likely void __init setup_arch(char **cmdline_p)
8776291319dSGrant Likely {
8786291319dSGrant Likely 	struct machine_desc *mdesc;
8796291319dSGrant Likely 
8806291319dSGrant Likely 	unwind_init();
8816291319dSGrant Likely 
8826291319dSGrant Likely 	setup_processor();
88393c02ab4SGrant Likely 	mdesc = setup_machine_fdt(__atags_pointer);
88493c02ab4SGrant Likely 	if (!mdesc)
8856291319dSGrant Likely 		mdesc = setup_machine_tags(machine_arch_type);
8866291319dSGrant Likely 	machine_desc = mdesc;
8876291319dSGrant Likely 	machine_name = mdesc->name;
8886291319dSGrant Likely 
8896291319dSGrant Likely 	if (mdesc->soft_reboot)
8906291319dSGrant Likely 		reboot_setup("s");
8916291319dSGrant Likely 
89237efe642SRussell King 	init_mm.start_code = (unsigned long) _text;
89337efe642SRussell King 	init_mm.end_code   = (unsigned long) _etext;
89437efe642SRussell King 	init_mm.end_data   = (unsigned long) _edata;
89537efe642SRussell King 	init_mm.brk	   = (unsigned long) _end;
8961da177e4SLinus Torvalds 
89748ab7e09SJeremy Kerr 	/* populate cmd_line too for later use, preserving boot_command_line */
89848ab7e09SJeremy Kerr 	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
89948ab7e09SJeremy Kerr 	*cmdline_p = cmd_line;
9002b0d8c25SJeremy Kerr 
9012b0d8c25SJeremy Kerr 	parse_early_param();
9022b0d8c25SJeremy Kerr 
9038d717a52SRussell King 	arm_memblock_init(&meminfo, mdesc);
9042778f620SRussell King 
9054b5f32ceSNicolas Pitre 	paging_init(mdesc);
90611b9369cSDima Zavin 	request_standard_resources(mdesc);
9071da177e4SLinus Torvalds 
90893c02ab4SGrant Likely 	unflatten_device_tree();
90993c02ab4SGrant Likely 
9107bbb7940SRussell King #ifdef CONFIG_SMP
911f00ec48fSRussell King 	if (is_smp())
9127bbb7940SRussell King 		smp_init_cpus();
9137bbb7940SRussell King #endif
9143c57fb43SMika Westerberg 	reserve_crashkernel();
9157bbb7940SRussell King 
916ccea7a19SRussell King 	cpu_init();
917bc581770SLinus Walleij 	tcm_init();
918ccea7a19SRussell King 
91952108641Seric miao #ifdef CONFIG_MULTI_IRQ_HANDLER
92052108641Seric miao 	handle_arch_irq = mdesc->handle_irq;
92152108641Seric miao #endif
9221da177e4SLinus Torvalds 
9231da177e4SLinus Torvalds #ifdef CONFIG_VT
9241da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
9251da177e4SLinus Torvalds 	conswitchp = &vga_con;
9261da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE)
9271da177e4SLinus Torvalds 	conswitchp = &dummy_con;
9281da177e4SLinus Torvalds #endif
9291da177e4SLinus Torvalds #endif
9305cbad0ebSJason Wessel 	early_trap_init();
931dec12e62SRussell King 
932dec12e62SRussell King 	if (mdesc->init_early)
933dec12e62SRussell King 		mdesc->init_early();
9341da177e4SLinus Torvalds }
9351da177e4SLinus Torvalds 
9361da177e4SLinus Torvalds 
9371da177e4SLinus Torvalds static int __init topology_init(void)
9381da177e4SLinus Torvalds {
9391da177e4SLinus Torvalds 	int cpu;
9401da177e4SLinus Torvalds 
94166fb8bd2SRussell King 	for_each_possible_cpu(cpu) {
94266fb8bd2SRussell King 		struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
94366fb8bd2SRussell King 		cpuinfo->cpu.hotpluggable = 1;
94466fb8bd2SRussell King 		register_cpu(&cpuinfo->cpu, cpu);
94566fb8bd2SRussell King 	}
9461da177e4SLinus Torvalds 
9471da177e4SLinus Torvalds 	return 0;
9481da177e4SLinus Torvalds }
9491da177e4SLinus Torvalds subsys_initcall(topology_init);
9501da177e4SLinus Torvalds 
951e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU
952e119bfffSRussell King static int __init proc_cpu_init(void)
953e119bfffSRussell King {
954e119bfffSRussell King 	struct proc_dir_entry *res;
955e119bfffSRussell King 
956e119bfffSRussell King 	res = proc_mkdir("cpu", NULL);
957e119bfffSRussell King 	if (!res)
958e119bfffSRussell King 		return -ENOMEM;
959e119bfffSRussell King 	return 0;
960e119bfffSRussell King }
961e119bfffSRussell King fs_initcall(proc_cpu_init);
962e119bfffSRussell King #endif
963e119bfffSRussell King 
9641da177e4SLinus Torvalds static const char *hwcap_str[] = {
9651da177e4SLinus Torvalds 	"swp",
9661da177e4SLinus Torvalds 	"half",
9671da177e4SLinus Torvalds 	"thumb",
9681da177e4SLinus Torvalds 	"26bit",
9691da177e4SLinus Torvalds 	"fastmult",
9701da177e4SLinus Torvalds 	"fpa",
9711da177e4SLinus Torvalds 	"vfp",
9721da177e4SLinus Torvalds 	"edsp",
9731da177e4SLinus Torvalds 	"java",
9748f7f9435SPaul Gortmaker 	"iwmmxt",
97599e4a6ddSLennert Buytenhek 	"crunch",
9764369ae16SCatalin Marinas 	"thumbee",
9772bedbdf4SCatalin Marinas 	"neon",
9787279dc3eSCatalin Marinas 	"vfpv3",
9797279dc3eSCatalin Marinas 	"vfpv3d16",
980254cdf8eSWill Deacon 	"tls",
981254cdf8eSWill Deacon 	"vfpv4",
982254cdf8eSWill Deacon 	"idiva",
983254cdf8eSWill Deacon 	"idivt",
9841da177e4SLinus Torvalds 	NULL
9851da177e4SLinus Torvalds };
9861da177e4SLinus Torvalds 
9871da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v)
9881da177e4SLinus Torvalds {
9891da177e4SLinus Torvalds 	int i;
9901da177e4SLinus Torvalds 
9911da177e4SLinus Torvalds 	seq_printf(m, "Processor\t: %s rev %d (%s)\n",
9920ba8b9b2SRussell King 		   cpu_name, read_cpuid_id() & 15, elf_platform);
9931da177e4SLinus Torvalds 
9941da177e4SLinus Torvalds #if defined(CONFIG_SMP)
9951da177e4SLinus Torvalds 	for_each_online_cpu(i) {
99615559722SRussell King 		/*
99715559722SRussell King 		 * glibc reads /proc/cpuinfo to determine the number of
99815559722SRussell King 		 * online processors, looking for lines beginning with
99915559722SRussell King 		 * "processor".  Give glibc what it expects.
100015559722SRussell King 		 */
100115559722SRussell King 		seq_printf(m, "processor\t: %d\n", i);
10021da177e4SLinus Torvalds 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
10031da177e4SLinus Torvalds 			   per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
10041da177e4SLinus Torvalds 			   (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
10051da177e4SLinus Torvalds 	}
10061da177e4SLinus Torvalds #else /* CONFIG_SMP */
10071da177e4SLinus Torvalds 	seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
10081da177e4SLinus Torvalds 		   loops_per_jiffy / (500000/HZ),
10091da177e4SLinus Torvalds 		   (loops_per_jiffy / (5000/HZ)) % 100);
10101da177e4SLinus Torvalds #endif
10111da177e4SLinus Torvalds 
10121da177e4SLinus Torvalds 	/* dump out the processor features */
10131da177e4SLinus Torvalds 	seq_puts(m, "Features\t: ");
10141da177e4SLinus Torvalds 
10151da177e4SLinus Torvalds 	for (i = 0; hwcap_str[i]; i++)
10161da177e4SLinus Torvalds 		if (elf_hwcap & (1 << i))
10171da177e4SLinus Torvalds 			seq_printf(m, "%s ", hwcap_str[i]);
10181da177e4SLinus Torvalds 
10190ba8b9b2SRussell King 	seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
10201da177e4SLinus Torvalds 	seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
10211da177e4SLinus Torvalds 
10220ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0x00000000) {
10231da177e4SLinus Torvalds 		/* pre-ARM7 */
10240ba8b9b2SRussell King 		seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4);
10251da177e4SLinus Torvalds 	} else {
10260ba8b9b2SRussell King 		if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
10271da177e4SLinus Torvalds 			/* ARM7 */
10281da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%02x\n",
10290ba8b9b2SRussell King 				   (read_cpuid_id() >> 16) & 127);
10301da177e4SLinus Torvalds 		} else {
10311da177e4SLinus Torvalds 			/* post-ARM7 */
10321da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%x\n",
10330ba8b9b2SRussell King 				   (read_cpuid_id() >> 20) & 15);
10341da177e4SLinus Torvalds 		}
10351da177e4SLinus Torvalds 		seq_printf(m, "CPU part\t: 0x%03x\n",
10360ba8b9b2SRussell King 			   (read_cpuid_id() >> 4) & 0xfff);
10371da177e4SLinus Torvalds 	}
10380ba8b9b2SRussell King 	seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
10391da177e4SLinus Torvalds 
10401da177e4SLinus Torvalds 	seq_puts(m, "\n");
10411da177e4SLinus Torvalds 
10421da177e4SLinus Torvalds 	seq_printf(m, "Hardware\t: %s\n", machine_name);
10431da177e4SLinus Torvalds 	seq_printf(m, "Revision\t: %04x\n", system_rev);
10441da177e4SLinus Torvalds 	seq_printf(m, "Serial\t\t: %08x%08x\n",
10451da177e4SLinus Torvalds 		   system_serial_high, system_serial_low);
10461da177e4SLinus Torvalds 
10471da177e4SLinus Torvalds 	return 0;
10481da177e4SLinus Torvalds }
10491da177e4SLinus Torvalds 
10501da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
10511da177e4SLinus Torvalds {
10521da177e4SLinus Torvalds 	return *pos < 1 ? (void *)1 : NULL;
10531da177e4SLinus Torvalds }
10541da177e4SLinus Torvalds 
10551da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
10561da177e4SLinus Torvalds {
10571da177e4SLinus Torvalds 	++*pos;
10581da177e4SLinus Torvalds 	return NULL;
10591da177e4SLinus Torvalds }
10601da177e4SLinus Torvalds 
10611da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
10621da177e4SLinus Torvalds {
10631da177e4SLinus Torvalds }
10641da177e4SLinus Torvalds 
10652ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = {
10661da177e4SLinus Torvalds 	.start	= c_start,
10671da177e4SLinus Torvalds 	.next	= c_next,
10681da177e4SLinus Torvalds 	.stop	= c_stop,
10691da177e4SLinus Torvalds 	.show	= c_show
10701da177e4SLinus Torvalds };
1071