blob: 97d90840a7fd37602df78eb16ade4f71e090d7c5 [file] [log] [blame]
Catalin Marinas9703d9d2012-03-05 11:49:27 +00001/*
2 * Based on arch/arm/kernel/setup.c
3 *
4 * Copyright (C) 1995-2001 Russell King
5 * Copyright (C) 2012 ARM Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/export.h>
21#include <linux/kernel.h>
22#include <linux/stddef.h>
23#include <linux/ioport.h>
24#include <linux/delay.h>
25#include <linux/utsname.h>
26#include <linux/initrd.h>
27#include <linux/console.h>
28#include <linux/bootmem.h>
29#include <linux/seq_file.h>
30#include <linux/screen_info.h>
31#include <linux/init.h>
32#include <linux/kexec.h>
33#include <linux/crash_dump.h>
34#include <linux/root_dev.h>
Catalin Marinasde79a642013-02-08 12:18:15 +000035#include <linux/clk-provider.h>
Catalin Marinas9703d9d2012-03-05 11:49:27 +000036#include <linux/cpu.h>
37#include <linux/interrupt.h>
38#include <linux/smp.h>
39#include <linux/fs.h>
40#include <linux/proc_fs.h>
41#include <linux/memblock.h>
42#include <linux/of_fdt.h>
Catalin Marinasd6bafb92012-12-07 17:47:17 +000043#include <linux/of_platform.h>
Catalin Marinas9703d9d2012-03-05 11:49:27 +000044
45#include <asm/cputype.h>
46#include <asm/elf.h>
47#include <asm/cputable.h>
Mark Rutlande8765b22013-10-24 20:30:17 +010048#include <asm/cpu_ops.h>
Catalin Marinas9703d9d2012-03-05 11:49:27 +000049#include <asm/sections.h>
50#include <asm/setup.h>
Javi Merino4c7aa002012-08-29 09:47:19 +010051#include <asm/smp_plat.h>
Catalin Marinas9703d9d2012-03-05 11:49:27 +000052#include <asm/cacheflush.h>
53#include <asm/tlbflush.h>
54#include <asm/traps.h>
55#include <asm/memblock.h>
Will Deacone790f1d2012-12-18 17:53:14 +000056#include <asm/psci.h>
Catalin Marinas9703d9d2012-03-05 11:49:27 +000057
58unsigned int processor_id;
59EXPORT_SYMBOL(processor_id);
60
Steve Capper25804e62013-09-18 16:14:28 +010061unsigned long elf_hwcap __read_mostly;
Catalin Marinas9703d9d2012-03-05 11:49:27 +000062EXPORT_SYMBOL_GPL(elf_hwcap);
63
Sudeep KarkadaNagesha46efe542013-08-13 15:57:53 +010064#ifdef CONFIG_COMPAT
65#define COMPAT_ELF_HWCAP_DEFAULT \
66 (COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\
67 COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\
68 COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\
69 COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
70 COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV)
71unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT;
72#endif
73
Catalin Marinas9703d9d2012-03-05 11:49:27 +000074static const char *cpu_name;
75static const char *machine_name;
76phys_addr_t __fdt_pointer __initdata;
77
78/*
79 * Standard memory resources
80 */
81static struct resource mem_res[] = {
82 {
83 .name = "Kernel code",
84 .start = 0,
85 .end = 0,
86 .flags = IORESOURCE_MEM
87 },
88 {
89 .name = "Kernel data",
90 .start = 0,
91 .end = 0,
92 .flags = IORESOURCE_MEM
93 }
94};
95
96#define kernel_code mem_res[0]
97#define kernel_data mem_res[1]
98
99void __init early_print(const char *str, ...)
100{
101 char buf[256];
102 va_list ap;
103
104 va_start(ap, str);
105 vsnprintf(buf, sizeof(buf), str, ap);
106 va_end(ap);
107
108 printk("%s", buf);
109}
110
Will Deacon71586272013-11-05 18:10:47 +0000111void __init smp_setup_processor_id(void)
112{
113 /*
114 * clear __my_cpu_offset on boot CPU to avoid hang caused by
115 * using percpu variable early, for example, lockdep will
116 * access percpu variable inside lock_release
117 */
118 set_my_cpu_offset(0);
119}
120
Sudeep KarkadaNagesha6e15d0e2013-10-21 13:29:42 +0100121bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
122{
123 return phys_id == cpu_logical_map(cpu);
124}
125
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000126static void __init setup_processor(void)
127{
128 struct cpu_info *cpu_info;
129
130 /*
131 * locate processor in the list of supported processor
132 * types. The linker builds this table for us from the
133 * entries in arch/arm/mm/proc.S
134 */
135 cpu_info = lookup_processor_type(read_cpuid_id());
136 if (!cpu_info) {
137 printk("CPU configuration botched (ID %08x), unable to continue.\n",
138 read_cpuid_id());
139 while (1);
140 }
141
142 cpu_name = cpu_info->cpu_name;
143
144 printk("CPU: %s [%08x] revision %d\n",
145 cpu_name, read_cpuid_id(), read_cpuid_id() & 15);
146
Will Deacon94ed1f22013-10-11 14:52:11 +0100147 sprintf(init_utsname()->machine, ELF_PLATFORM);
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000148 elf_hwcap = 0;
149}
150
151static void __init setup_machine_fdt(phys_addr_t dt_phys)
152{
Rob Herringd5189cc2013-08-26 10:14:32 -0500153 if (!dt_phys || !early_init_dt_scan(phys_to_virt(dt_phys))) {
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000154 early_print("\n"
155 "Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n"
Rob Herringd5189cc2013-08-26 10:14:32 -0500156 "The dtb must be 8-byte aligned and passed in the first 512MB of memory\n"
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000157 "\nPlease check your bootloader.\n",
Rob Herringd5189cc2013-08-26 10:14:32 -0500158 dt_phys, phys_to_virt(dt_phys));
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000159
160 while (true)
161 cpu_relax();
162 }
163
Rob Herringf2b99bc2013-08-27 21:44:37 -0500164 machine_name = of_flat_dt_get_machine_name();
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000165}
166
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000167/*
168 * Limit the memory size that was specified via FDT.
169 */
170static int __init early_mem(char *p)
171{
172 phys_addr_t limit;
173
174 if (!p)
175 return 1;
176
177 limit = memparse(p, &p) & PAGE_MASK;
178 pr_notice("Memory limited to %lldMB\n", limit >> 20);
179
180 memblock_enforce_memory_limit(limit);
181
182 return 0;
183}
184early_param("mem", early_mem);
185
186static void __init request_standard_resources(void)
187{
188 struct memblock_region *region;
189 struct resource *res;
190
191 kernel_code.start = virt_to_phys(_text);
192 kernel_code.end = virt_to_phys(_etext - 1);
193 kernel_data.start = virt_to_phys(_sdata);
194 kernel_data.end = virt_to_phys(_end - 1);
195
196 for_each_memblock(memory, region) {
197 res = alloc_bootmem_low(sizeof(*res));
198 res->name = "System RAM";
199 res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
200 res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
201 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
202
203 request_resource(&iomem_resource, res);
204
205 if (kernel_code.start >= res->start &&
206 kernel_code.end <= res->end)
207 request_resource(res, &kernel_code);
208 if (kernel_data.start >= res->start &&
209 kernel_data.end <= res->end)
210 request_resource(res, &kernel_data);
211 }
212}
213
Javi Merino4c7aa002012-08-29 09:47:19 +0100214u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
215
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000216void __init setup_arch(char **cmdline_p)
217{
Catalin Marinasb3bf6aa2013-11-21 14:46:17 +0000218 /*
219 * Unmask asynchronous aborts early to catch possible system errors.
220 */
221 local_async_enable();
222
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000223 setup_processor();
224
225 setup_machine_fdt(__fdt_pointer);
226
227 init_mm.start_code = (unsigned long) _text;
228 init_mm.end_code = (unsigned long) _etext;
229 init_mm.end_data = (unsigned long) _edata;
230 init_mm.brk = (unsigned long) _end;
231
232 *cmdline_p = boot_command_line;
233
234 parse_early_param();
235
236 arm64_memblock_init();
237
238 paging_init();
239 request_standard_resources();
240
241 unflatten_device_tree();
242
Will Deacone790f1d2012-12-18 17:53:14 +0000243 psci_init();
244
Javi Merino4c7aa002012-08-29 09:47:19 +0100245 cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
Mark Rutlande8765b22013-10-24 20:30:17 +0100246 cpu_read_bootcpu_ops();
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000247#ifdef CONFIG_SMP
248 smp_init_cpus();
249#endif
250
251#ifdef CONFIG_VT
252#if defined(CONFIG_VGA_CONSOLE)
253 conswitchp = &vga_con;
254#elif defined(CONFIG_DUMMY_CONSOLE)
255 conswitchp = &dummy_con;
256#endif
257#endif
258}
259
Catalin Marinasc560ecf2013-05-14 10:51:18 +0100260static int __init arm64_device_init(void)
Catalin Marinasde79a642013-02-08 12:18:15 +0000261{
262 of_clk_init(NULL);
Catalin Marinasc560ecf2013-05-14 10:51:18 +0100263 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
Catalin Marinasde79a642013-02-08 12:18:15 +0000264 return 0;
265}
Catalin Marinasc560ecf2013-05-14 10:51:18 +0100266arch_initcall(arm64_device_init);
Catalin Marinasde79a642013-02-08 12:18:15 +0000267
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000268static DEFINE_PER_CPU(struct cpu, cpu_data);
269
270static int __init topology_init(void)
271{
272 int i;
273
274 for_each_possible_cpu(i) {
275 struct cpu *cpu = &per_cpu(cpu_data, i);
276 cpu->hotpluggable = 1;
277 register_cpu(cpu, i);
278 }
279
280 return 0;
281}
282subsys_initcall(topology_init);
283
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000284static const char *hwcap_str[] = {
285 "fp",
286 "asimd",
Sudeep KarkadaNagesha46efe542013-08-13 15:57:53 +0100287 "evtstrm",
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000288 NULL
289};
290
291static int c_show(struct seq_file *m, void *v)
292{
293 int i;
294
295 seq_printf(m, "Processor\t: %s rev %d (%s)\n",
296 cpu_name, read_cpuid_id() & 15, ELF_PLATFORM);
297
298 for_each_online_cpu(i) {
299 /*
300 * glibc reads /proc/cpuinfo to determine the number of
301 * online processors, looking for lines beginning with
302 * "processor". Give glibc what it expects.
303 */
304#ifdef CONFIG_SMP
305 seq_printf(m, "processor\t: %d\n", i);
306#endif
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000307 }
308
309 /* dump out the processor features */
310 seq_puts(m, "Features\t: ");
311
312 for (i = 0; hwcap_str[i]; i++)
313 if (elf_hwcap & (1 << i))
314 seq_printf(m, "%s ", hwcap_str[i]);
315
316 seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
317 seq_printf(m, "CPU architecture: AArch64\n");
318 seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15);
319 seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff);
320 seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
321
322 seq_puts(m, "\n");
323
324 seq_printf(m, "Hardware\t: %s\n", machine_name);
325
326 return 0;
327}
328
329static void *c_start(struct seq_file *m, loff_t *pos)
330{
331 return *pos < 1 ? (void *)1 : NULL;
332}
333
334static void *c_next(struct seq_file *m, void *v, loff_t *pos)
335{
336 ++*pos;
337 return NULL;
338}
339
340static void c_stop(struct seq_file *m, void *v)
341{
342}
343
344const struct seq_operations cpuinfo_op = {
345 .start = c_start,
346 .next = c_next,
347 .stop = c_stop,
348 .show = c_show
349};