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 (PHYSICAL_END - PHYSICAL_START), 6 * may 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) 2016, 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/setup.h> 18 #include <asm/page.h> 19 #include <asm/hcall.h> 20 21 extern unsigned long stacktop; 22 extern void io_init(void); 23 extern void setup_args_progname(const char *args); 24 25 u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) }; 26 int nr_cpus; 27 28 struct mem_region mem_regions[NR_MEM_REGIONS]; 29 phys_addr_t __physical_start, __physical_end; 30 unsigned __icache_bytes, __dcache_bytes; 31 32 struct cpu_set_params { 33 unsigned icache_bytes; 34 unsigned dcache_bytes; 35 }; 36 37 #define EXCEPTION_STACK_SIZE (32*1024) /* 32kB */ 38 39 static char exception_stack[NR_CPUS][EXCEPTION_STACK_SIZE]; 40 41 static void cpu_set(int fdtnode, u32 regval, void *info) 42 { 43 static bool read_common_info = false; 44 struct cpu_set_params *params = info; 45 int cpu = nr_cpus++; 46 47 if (cpu >= NR_CPUS) { 48 printf("Number cpus exceeds maximum supported (%d).\n", 49 NR_CPUS); 50 assert(0); 51 } 52 cpus[cpu] = regval; 53 54 /* set exception stack address for this CPU (in SPGR0) */ 55 56 asm volatile ("mtsprg0 %[addr]" :: 57 [addr] "r" (exception_stack[cpu + 1])); 58 59 if (!read_common_info) { 60 const struct fdt_property *prop; 61 u32 *data; 62 63 prop = fdt_get_property(dt_fdt(), fdtnode, 64 "i-cache-line-size", NULL); 65 assert(prop != NULL); 66 data = (u32 *)prop->data; 67 params->icache_bytes = fdt32_to_cpu(*data); 68 69 prop = fdt_get_property(dt_fdt(), fdtnode, 70 "d-cache-line-size", NULL); 71 assert(prop != NULL); 72 data = (u32 *)prop->data; 73 params->dcache_bytes = fdt32_to_cpu(*data); 74 75 read_common_info = true; 76 } 77 } 78 79 static void cpu_init(void) 80 { 81 struct cpu_set_params params; 82 int ret; 83 84 nr_cpus = 0; 85 ret = dt_for_each_cpu_node(cpu_set, ¶ms); 86 assert(ret == 0); 87 __icache_bytes = params.icache_bytes; 88 __dcache_bytes = params.dcache_bytes; 89 90 /* Interrupt Endianness */ 91 92 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 93 hcall(H_SET_MODE, 1, 4, 0, 0); 94 #else 95 hcall(H_SET_MODE, 0, 4, 0, 0); 96 #endif 97 } 98 99 static void mem_init(phys_addr_t freemem_start) 100 { 101 struct dt_pbus_reg regs[NR_MEM_REGIONS]; 102 struct mem_region primary, mem = { 103 .start = (phys_addr_t)-1, 104 }; 105 int nr_regs, i; 106 107 nr_regs = dt_get_memory_params(regs, NR_MEM_REGIONS); 108 assert(nr_regs > 0); 109 110 primary.end = 0; 111 112 for (i = 0; i < nr_regs; ++i) { 113 mem_regions[i].start = regs[i].addr; 114 mem_regions[i].end = regs[i].addr + regs[i].size; 115 116 /* 117 * pick the region we're in for our primary region 118 */ 119 if (freemem_start >= mem_regions[i].start 120 && freemem_start < mem_regions[i].end) { 121 mem_regions[i].flags |= MR_F_PRIMARY; 122 primary = mem_regions[i]; 123 } 124 125 /* 126 * set the lowest and highest addresses found, 127 * ignoring potential gaps 128 */ 129 if (mem_regions[i].start < mem.start) 130 mem.start = mem_regions[i].start; 131 if (mem_regions[i].end > mem.end) 132 mem.end = mem_regions[i].end; 133 } 134 assert(primary.end != 0); 135 // assert(!(mem.start & ~PHYS_MASK) && !((mem.end - 1) & ~PHYS_MASK)); 136 137 __physical_start = mem.start; /* PHYSICAL_START */ 138 __physical_end = mem.end; /* PHYSICAL_END */ 139 140 phys_alloc_init(freemem_start, primary.end - freemem_start); 141 phys_alloc_set_minimum_alignment(__icache_bytes > __dcache_bytes 142 ? __icache_bytes : __dcache_bytes); 143 } 144 145 void setup(const void *fdt) 146 { 147 const char *bootargs; 148 u32 fdt_size; 149 int ret; 150 151 /* 152 * Move the fdt to just above the stack. The free memory 153 * then starts just after the fdt. 154 */ 155 fdt_size = fdt_totalsize(fdt); 156 ret = fdt_move(fdt, &stacktop, fdt_size); 157 assert(ret == 0); 158 ret = dt_init(&stacktop); 159 assert(ret == 0); 160 161 cpu_init(); 162 mem_init(PAGE_ALIGN((unsigned long)&stacktop + fdt_size)); 163 io_init(); 164 165 ret = dt_get_bootargs(&bootargs); 166 assert(ret == 0); 167 setup_args_progname(bootargs); 168 } 169