blob: 9c023d714f44fcdfcac65b3c43bd2215f900caed [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>
48#include <asm/sections.h>
49#include <asm/setup.h>
50#include <asm/cacheflush.h>
51#include <asm/tlbflush.h>
52#include <asm/traps.h>
53#include <asm/memblock.h>
Will Deacone790f1d2012-12-18 17:53:14 +000054#include <asm/psci.h>
Catalin Marinas9703d9d2012-03-05 11:49:27 +000055
56unsigned int processor_id;
57EXPORT_SYMBOL(processor_id);
58
59unsigned int elf_hwcap __read_mostly;
60EXPORT_SYMBOL_GPL(elf_hwcap);
61
62static const char *cpu_name;
63static const char *machine_name;
64phys_addr_t __fdt_pointer __initdata;
65
66/*
67 * Standard memory resources
68 */
69static struct resource mem_res[] = {
70 {
71 .name = "Kernel code",
72 .start = 0,
73 .end = 0,
74 .flags = IORESOURCE_MEM
75 },
76 {
77 .name = "Kernel data",
78 .start = 0,
79 .end = 0,
80 .flags = IORESOURCE_MEM
81 }
82};
83
84#define kernel_code mem_res[0]
85#define kernel_data mem_res[1]
86
87void __init early_print(const char *str, ...)
88{
89 char buf[256];
90 va_list ap;
91
92 va_start(ap, str);
93 vsnprintf(buf, sizeof(buf), str, ap);
94 va_end(ap);
95
96 printk("%s", buf);
97}
98
99static void __init setup_processor(void)
100{
101 struct cpu_info *cpu_info;
102
103 /*
104 * locate processor in the list of supported processor
105 * types. The linker builds this table for us from the
106 * entries in arch/arm/mm/proc.S
107 */
108 cpu_info = lookup_processor_type(read_cpuid_id());
109 if (!cpu_info) {
110 printk("CPU configuration botched (ID %08x), unable to continue.\n",
111 read_cpuid_id());
112 while (1);
113 }
114
115 cpu_name = cpu_info->cpu_name;
116
117 printk("CPU: %s [%08x] revision %d\n",
118 cpu_name, read_cpuid_id(), read_cpuid_id() & 15);
119
120 sprintf(init_utsname()->machine, "aarch64");
121 elf_hwcap = 0;
122}
123
124static void __init setup_machine_fdt(phys_addr_t dt_phys)
125{
126 struct boot_param_header *devtree;
127 unsigned long dt_root;
128
129 /* Check we have a non-NULL DT pointer */
130 if (!dt_phys) {
131 early_print("\n"
132 "Error: NULL or invalid device tree blob\n"
133 "The dtb must be 8-byte aligned and passed in the first 512MB of memory\n"
134 "\nPlease check your bootloader.\n");
135
136 while (true)
137 cpu_relax();
138
139 }
140
141 devtree = phys_to_virt(dt_phys);
142
143 /* Check device tree validity */
144 if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) {
145 early_print("\n"
146 "Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n"
147 "Expected 0x%x, found 0x%x\n"
148 "\nPlease check your bootloader.\n",
149 dt_phys, devtree, OF_DT_HEADER,
150 be32_to_cpu(devtree->magic));
151
152 while (true)
153 cpu_relax();
154 }
155
156 initial_boot_params = devtree;
157 dt_root = of_get_flat_dt_root();
158
159 machine_name = of_get_flat_dt_prop(dt_root, "model", NULL);
160 if (!machine_name)
161 machine_name = of_get_flat_dt_prop(dt_root, "compatible", NULL);
162 if (!machine_name)
163 machine_name = "<unknown>";
164 pr_info("Machine: %s\n", machine_name);
165
166 /* Retrieve various information from the /chosen node */
167 of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
168 /* Initialize {size,address}-cells info */
169 of_scan_flat_dt(early_init_dt_scan_root, NULL);
170 /* Setup memory, calling early_init_dt_add_memory_arch */
171 of_scan_flat_dt(early_init_dt_scan_memory, NULL);
172}
173
174void __init early_init_dt_add_memory_arch(u64 base, u64 size)
175{
Catalin Marinasf71a1a42012-10-16 12:00:29 +0100176 base &= PAGE_MASK;
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000177 size &= PAGE_MASK;
Catalin Marinasf71a1a42012-10-16 12:00:29 +0100178 if (base + size < PHYS_OFFSET) {
179 pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
180 base, base + size);
181 return;
182 }
183 if (base < PHYS_OFFSET) {
184 pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
185 base, PHYS_OFFSET);
186 size -= PHYS_OFFSET - base;
187 base = PHYS_OFFSET;
188 }
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000189 memblock_add(base, size);
190}
191
192void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
193{
194 return __va(memblock_alloc(size, align));
195}
196
197/*
198 * Limit the memory size that was specified via FDT.
199 */
200static int __init early_mem(char *p)
201{
202 phys_addr_t limit;
203
204 if (!p)
205 return 1;
206
207 limit = memparse(p, &p) & PAGE_MASK;
208 pr_notice("Memory limited to %lldMB\n", limit >> 20);
209
210 memblock_enforce_memory_limit(limit);
211
212 return 0;
213}
214early_param("mem", early_mem);
215
216static void __init request_standard_resources(void)
217{
218 struct memblock_region *region;
219 struct resource *res;
220
221 kernel_code.start = virt_to_phys(_text);
222 kernel_code.end = virt_to_phys(_etext - 1);
223 kernel_data.start = virt_to_phys(_sdata);
224 kernel_data.end = virt_to_phys(_end - 1);
225
226 for_each_memblock(memory, region) {
227 res = alloc_bootmem_low(sizeof(*res));
228 res->name = "System RAM";
229 res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
230 res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
231 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
232
233 request_resource(&iomem_resource, res);
234
235 if (kernel_code.start >= res->start &&
236 kernel_code.end <= res->end)
237 request_resource(res, &kernel_code);
238 if (kernel_data.start >= res->start &&
239 kernel_data.end <= res->end)
240 request_resource(res, &kernel_data);
241 }
242}
243
244void __init setup_arch(char **cmdline_p)
245{
246 setup_processor();
247
248 setup_machine_fdt(__fdt_pointer);
249
250 init_mm.start_code = (unsigned long) _text;
251 init_mm.end_code = (unsigned long) _etext;
252 init_mm.end_data = (unsigned long) _edata;
253 init_mm.brk = (unsigned long) _end;
254
255 *cmdline_p = boot_command_line;
256
257 parse_early_param();
258
259 arm64_memblock_init();
260
261 paging_init();
262 request_standard_resources();
263
264 unflatten_device_tree();
265
Will Deacone790f1d2012-12-18 17:53:14 +0000266 psci_init();
267
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000268#ifdef CONFIG_SMP
269 smp_init_cpus();
270#endif
271
272#ifdef CONFIG_VT
273#if defined(CONFIG_VGA_CONSOLE)
274 conswitchp = &vga_con;
275#elif defined(CONFIG_DUMMY_CONSOLE)
276 conswitchp = &dummy_con;
277#endif
278#endif
279}
280
Catalin Marinasde79a642013-02-08 12:18:15 +0000281static int __init arm64_of_clk_init(void)
282{
283 of_clk_init(NULL);
284 return 0;
285}
286arch_initcall(arm64_of_clk_init);
287
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000288static DEFINE_PER_CPU(struct cpu, cpu_data);
289
290static int __init topology_init(void)
291{
292 int i;
293
294 for_each_possible_cpu(i) {
295 struct cpu *cpu = &per_cpu(cpu_data, i);
296 cpu->hotpluggable = 1;
297 register_cpu(cpu, i);
298 }
299
300 return 0;
301}
302subsys_initcall(topology_init);
303
Catalin Marinasd6bafb92012-12-07 17:47:17 +0000304static int __init arm64_device_probe(void)
305{
306 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
307 return 0;
308}
309device_initcall(arm64_device_probe);
310
Catalin Marinas9703d9d2012-03-05 11:49:27 +0000311static const char *hwcap_str[] = {
312 "fp",
313 "asimd",
314 NULL
315};
316
317static int c_show(struct seq_file *m, void *v)
318{
319 int i;
320
321 seq_printf(m, "Processor\t: %s rev %d (%s)\n",
322 cpu_name, read_cpuid_id() & 15, ELF_PLATFORM);
323
324 for_each_online_cpu(i) {
325 /*
326 * glibc reads /proc/cpuinfo to determine the number of
327 * online processors, looking for lines beginning with
328 * "processor". Give glibc what it expects.
329 */
330#ifdef CONFIG_SMP
331 seq_printf(m, "processor\t: %d\n", i);
332#endif
333 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
334 loops_per_jiffy / (500000UL/HZ),
335 loops_per_jiffy / (5000UL/HZ) % 100);
336 }
337
338 /* dump out the processor features */
339 seq_puts(m, "Features\t: ");
340
341 for (i = 0; hwcap_str[i]; i++)
342 if (elf_hwcap & (1 << i))
343 seq_printf(m, "%s ", hwcap_str[i]);
344
345 seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
346 seq_printf(m, "CPU architecture: AArch64\n");
347 seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15);
348 seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff);
349 seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
350
351 seq_puts(m, "\n");
352
353 seq_printf(m, "Hardware\t: %s\n", machine_name);
354
355 return 0;
356}
357
358static void *c_start(struct seq_file *m, loff_t *pos)
359{
360 return *pos < 1 ? (void *)1 : NULL;
361}
362
363static void *c_next(struct seq_file *m, void *v, loff_t *pos)
364{
365 ++*pos;
366 return NULL;
367}
368
369static void c_stop(struct seq_file *m, void *v)
370{
371}
372
373const struct seq_operations cpuinfo_op = {
374 .start = c_start,
375 .next = c_next,
376 .stop = c_stop,
377 .show = c_show
378};