1 /* 2 * Initialize machine setup information and I/O. 3 * 4 * After running setup() unit tests may query how many cpus they have 5 * (nr_cpus), how much memory they have (PHYS_END - PHYS_OFFSET), may 6 * use dynamic memory allocation (malloc, etc.), printf, and exit. 7 * Finally, argc and argv are also ready to be passed to main(). 8 * 9 * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> 10 * 11 * This work is licensed under the terms of the GNU LGPL, version 2. 12 */ 13 #include <libcflat.h> 14 #include <libfdt/libfdt.h> 15 #include <devicetree.h> 16 #include <alloc.h> 17 #include <asm/thread_info.h> 18 #include <asm/setup.h> 19 #include <asm/page.h> 20 #include <asm/mmu.h> 21 #include <asm/smp.h> 22 23 extern unsigned long stacktop; 24 extern void io_init(void); 25 extern void setup_args(const char *args); 26 27 u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) }; 28 int nr_cpus; 29 30 phys_addr_t __phys_offset, __phys_end; 31 32 static void cpu_set(int fdtnode __unused, u32 regval, void *info __unused) 33 { 34 int cpu = nr_cpus++; 35 assert(cpu < NR_CPUS); 36 cpus[cpu] = regval; 37 set_cpu_present(cpu, true); 38 } 39 40 static void cpu_init(void) 41 { 42 int ret; 43 44 nr_cpus = 0; 45 ret = dt_for_each_cpu_node(cpu_set, NULL); 46 assert(ret == 0); 47 set_cpu_online(0, true); 48 } 49 50 static void mem_init(phys_addr_t freemem_start) 51 { 52 /* we only expect one membank to be defined in the DT */ 53 struct dt_pbus_reg regs[1]; 54 phys_addr_t mem_start, mem_end; 55 int ret; 56 57 ret = dt_get_memory_params(regs, 1); 58 assert(ret != 0); 59 60 mem_start = regs[0].addr; 61 mem_end = mem_start + regs[0].size; 62 63 assert(!(mem_start & ~PHYS_MASK) && !((mem_end-1) & ~PHYS_MASK)); 64 assert(freemem_start >= mem_start && freemem_start < mem_end); 65 66 __phys_offset = mem_start; /* PHYS_OFFSET */ 67 __phys_end = mem_end; /* PHYS_END */ 68 69 phys_alloc_init(freemem_start, mem_end - freemem_start); 70 phys_alloc_set_minimum_alignment(SMP_CACHE_BYTES); 71 72 mmu_enable_idmap(); 73 } 74 75 void setup(const void *fdt) 76 { 77 const char *bootargs; 78 u32 fdt_size; 79 int ret; 80 81 /* 82 * Move the fdt to just above the stack. The free memory 83 * then starts just after the fdt. 84 */ 85 fdt_size = fdt_totalsize(fdt); 86 ret = fdt_move(fdt, &stacktop, fdt_size); 87 assert(ret == 0); 88 ret = dt_init(&stacktop); 89 assert(ret == 0); 90 91 mem_init(PAGE_ALIGN((unsigned long)&stacktop + fdt_size)); 92 io_init(); 93 cpu_init(); 94 95 thread_info_init(current_thread_info(), 0); 96 97 ret = dt_get_bootargs(&bootargs); 98 assert(ret == 0); 99 setup_args(bootargs); 100 } 101