xref: /kvm-unit-tests/lib/powerpc/setup.c (revision 6842bc34fcfd218b2e937e421bd98b5cd56dd872)
1d72b0449SAndrew Jones /*
2d72b0449SAndrew Jones  * Initialize machine setup information and I/O.
3d72b0449SAndrew Jones  *
4d72b0449SAndrew Jones  * After running setup() unit tests may query how many cpus they have
5d72b0449SAndrew Jones  * (nr_cpus), how much memory they have (PHYSICAL_END - PHYSICAL_START),
6d72b0449SAndrew Jones  * may use dynamic memory allocation (malloc, etc.), printf, and exit.
7d72b0449SAndrew Jones  * Finally, argc and argv are also ready to be passed to main().
8d72b0449SAndrew Jones  *
9d72b0449SAndrew Jones  * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
10d72b0449SAndrew Jones  *
11d72b0449SAndrew Jones  * This work is licensed under the terms of the GNU LGPL, version 2.
12d72b0449SAndrew Jones  */
13d72b0449SAndrew Jones #include <libcflat.h>
14d72b0449SAndrew Jones #include <libfdt/libfdt.h>
15d72b0449SAndrew Jones #include <devicetree.h>
16d72b0449SAndrew Jones #include <alloc.h>
17d72b0449SAndrew Jones #include <asm/setup.h>
18d72b0449SAndrew Jones #include <asm/page.h>
19*6842bc34SLaurent Vivier #include <asm/ppc_asm.h>
20*6842bc34SLaurent Vivier #include <asm/hcall.h>
21d72b0449SAndrew Jones 
22d72b0449SAndrew Jones extern unsigned long stacktop;
23d72b0449SAndrew Jones extern void io_init(void);
24d72b0449SAndrew Jones extern void setup_args(const char *args);
25d72b0449SAndrew Jones 
26d72b0449SAndrew Jones u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
27d72b0449SAndrew Jones int nr_cpus;
28d72b0449SAndrew Jones 
29d72b0449SAndrew Jones struct mem_region mem_regions[NR_MEM_REGIONS];
30d72b0449SAndrew Jones phys_addr_t __physical_start, __physical_end;
31d72b0449SAndrew Jones unsigned __icache_bytes, __dcache_bytes;
32d72b0449SAndrew Jones 
33d72b0449SAndrew Jones struct cpu_set_params {
34d72b0449SAndrew Jones 	unsigned icache_bytes;
35d72b0449SAndrew Jones 	unsigned dcache_bytes;
36d72b0449SAndrew Jones };
37d72b0449SAndrew Jones 
38*6842bc34SLaurent Vivier #define EXCEPTION_STACK_SIZE	(32*1024) /* 32kB */
39*6842bc34SLaurent Vivier 
40*6842bc34SLaurent Vivier static char exception_stack[NR_CPUS][EXCEPTION_STACK_SIZE];
41*6842bc34SLaurent Vivier 
42d72b0449SAndrew Jones static void cpu_set(int fdtnode, u32 regval, void *info)
43d72b0449SAndrew Jones {
44d72b0449SAndrew Jones 	static bool read_common_info = false;
45d72b0449SAndrew Jones 	struct cpu_set_params *params = info;
46d72b0449SAndrew Jones 	int cpu = nr_cpus++;
47d72b0449SAndrew Jones 
48d72b0449SAndrew Jones 	if (cpu >= NR_CPUS) {
49d72b0449SAndrew Jones 		printf("Number cpus exceeds maximum supported (%d).\n",
50d72b0449SAndrew Jones 			NR_CPUS);
51d72b0449SAndrew Jones 		assert(0);
52d72b0449SAndrew Jones 	}
53d72b0449SAndrew Jones 	cpus[cpu] = regval;
54d72b0449SAndrew Jones 
55*6842bc34SLaurent Vivier 	/* set exception stack address for this CPU (in SPGR0) */
56*6842bc34SLaurent Vivier 
57*6842bc34SLaurent Vivier 	asm volatile ("mtsprg0 %[addr]" ::
58*6842bc34SLaurent Vivier 		      [addr] "r" (exception_stack[cpu + 1]));
59*6842bc34SLaurent Vivier 
60d72b0449SAndrew Jones 	if (!read_common_info) {
61d72b0449SAndrew Jones 		const struct fdt_property *prop;
62d72b0449SAndrew Jones 		u32 *data;
63d72b0449SAndrew Jones 
64d72b0449SAndrew Jones 		prop = fdt_get_property(dt_fdt(), fdtnode,
65d72b0449SAndrew Jones 					"i-cache-line-size", NULL);
66d72b0449SAndrew Jones 		assert(prop != NULL);
67d72b0449SAndrew Jones 		data = (u32 *)prop->data;
68d72b0449SAndrew Jones 		params->icache_bytes = fdt32_to_cpu(*data);
69d72b0449SAndrew Jones 
70d72b0449SAndrew Jones 		prop = fdt_get_property(dt_fdt(), fdtnode,
71d72b0449SAndrew Jones 					"d-cache-line-size", NULL);
72d72b0449SAndrew Jones 		assert(prop != NULL);
73d72b0449SAndrew Jones 		data = (u32 *)prop->data;
74d72b0449SAndrew Jones 		params->dcache_bytes = fdt32_to_cpu(*data);
75d72b0449SAndrew Jones 
76d72b0449SAndrew Jones 		read_common_info = true;
77d72b0449SAndrew Jones 	}
78d72b0449SAndrew Jones }
79d72b0449SAndrew Jones 
80d72b0449SAndrew Jones static void cpu_init(void)
81d72b0449SAndrew Jones {
82d72b0449SAndrew Jones 	struct cpu_set_params params;
83d72b0449SAndrew Jones 	int ret;
84d72b0449SAndrew Jones 
85d72b0449SAndrew Jones 	nr_cpus = 0;
86d72b0449SAndrew Jones 	ret = dt_for_each_cpu_node(cpu_set, &params);
87d72b0449SAndrew Jones 	assert(ret == 0);
88d72b0449SAndrew Jones 	__icache_bytes = params.icache_bytes;
89d72b0449SAndrew Jones 	__dcache_bytes = params.dcache_bytes;
90*6842bc34SLaurent Vivier 
91*6842bc34SLaurent Vivier 	/* Interrupt Endianness */
92*6842bc34SLaurent Vivier 
93*6842bc34SLaurent Vivier #if  __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
94*6842bc34SLaurent Vivier         hcall(H_SET_MODE, 1, 4, 0, 0);
95*6842bc34SLaurent Vivier #else
96*6842bc34SLaurent Vivier         hcall(H_SET_MODE, 0, 4, 0, 0);
97*6842bc34SLaurent Vivier #endif
98d72b0449SAndrew Jones }
99d72b0449SAndrew Jones 
100d72b0449SAndrew Jones static void mem_init(phys_addr_t freemem_start)
101d72b0449SAndrew Jones {
102d72b0449SAndrew Jones 	struct dt_pbus_reg regs[NR_MEM_REGIONS];
103d72b0449SAndrew Jones 	struct mem_region primary, mem = {
104d72b0449SAndrew Jones 		.start = (phys_addr_t)-1,
105d72b0449SAndrew Jones 	};
106d72b0449SAndrew Jones 	int nr_regs, i;
107d72b0449SAndrew Jones 
108d72b0449SAndrew Jones 	nr_regs = dt_get_memory_params(regs, NR_MEM_REGIONS);
109d72b0449SAndrew Jones 	assert(nr_regs > 0);
110d72b0449SAndrew Jones 
111d72b0449SAndrew Jones 	primary.end = 0;
112d72b0449SAndrew Jones 
113d72b0449SAndrew Jones 	for (i = 0; i < nr_regs; ++i) {
114d72b0449SAndrew Jones 		mem_regions[i].start = regs[i].addr;
115d72b0449SAndrew Jones 		mem_regions[i].end = regs[i].addr + regs[i].size;
116d72b0449SAndrew Jones 
117d72b0449SAndrew Jones 		/*
118d72b0449SAndrew Jones 		 * pick the region we're in for our primary region
119d72b0449SAndrew Jones 		 */
120d72b0449SAndrew Jones 		if (freemem_start >= mem_regions[i].start
121d72b0449SAndrew Jones 				&& freemem_start < mem_regions[i].end) {
122d72b0449SAndrew Jones 			mem_regions[i].flags |= MR_F_PRIMARY;
123d72b0449SAndrew Jones 			primary = mem_regions[i];
124d72b0449SAndrew Jones 		}
125d72b0449SAndrew Jones 
126d72b0449SAndrew Jones 		/*
127d72b0449SAndrew Jones 		 * set the lowest and highest addresses found,
128d72b0449SAndrew Jones 		 * ignoring potential gaps
129d72b0449SAndrew Jones 		 */
130d72b0449SAndrew Jones 		if (mem_regions[i].start < mem.start)
131d72b0449SAndrew Jones 			mem.start = mem_regions[i].start;
132d72b0449SAndrew Jones 		if (mem_regions[i].end > mem.end)
133d72b0449SAndrew Jones 			mem.end = mem_regions[i].end;
134d72b0449SAndrew Jones 	}
135d72b0449SAndrew Jones 	assert(primary.end != 0);
136d72b0449SAndrew Jones //	assert(!(mem.start & ~PHYS_MASK) && !((mem.end - 1) & ~PHYS_MASK));
137d72b0449SAndrew Jones 
138d72b0449SAndrew Jones 	__physical_start = mem.start;	/* PHYSICAL_START */
139d72b0449SAndrew Jones 	__physical_end = mem.end;	/* PHYSICAL_END */
140d72b0449SAndrew Jones 
141d72b0449SAndrew Jones 	phys_alloc_init(freemem_start, primary.end - freemem_start);
142d72b0449SAndrew Jones 	phys_alloc_set_minimum_alignment(__icache_bytes > __dcache_bytes
143d72b0449SAndrew Jones 					 ? __icache_bytes : __dcache_bytes);
144d72b0449SAndrew Jones }
145d72b0449SAndrew Jones 
146d72b0449SAndrew Jones void setup(const void *fdt)
147d72b0449SAndrew Jones {
148d72b0449SAndrew Jones 	const char *bootargs;
149d72b0449SAndrew Jones 	u32 fdt_size;
150d72b0449SAndrew Jones 	int ret;
151d72b0449SAndrew Jones 
152d72b0449SAndrew Jones 	/*
153d72b0449SAndrew Jones 	 * Move the fdt to just above the stack. The free memory
154d72b0449SAndrew Jones 	 * then starts just after the fdt.
155d72b0449SAndrew Jones 	 */
156d72b0449SAndrew Jones 	fdt_size = fdt_totalsize(fdt);
157d72b0449SAndrew Jones 	ret = fdt_move(fdt, &stacktop, fdt_size);
158d72b0449SAndrew Jones 	assert(ret == 0);
159d72b0449SAndrew Jones 	ret = dt_init(&stacktop);
160d72b0449SAndrew Jones 	assert(ret == 0);
161d72b0449SAndrew Jones 
162d72b0449SAndrew Jones 	cpu_init();
163d72b0449SAndrew Jones 	mem_init(PAGE_ALIGN((unsigned long)&stacktop + fdt_size));
164d72b0449SAndrew Jones 	io_init();
165d72b0449SAndrew Jones 
166d72b0449SAndrew Jones 	ret = dt_get_bootargs(&bootargs);
167d72b0449SAndrew Jones 	assert(ret == 0);
168d72b0449SAndrew Jones 	setup_args(bootargs);
169d72b0449SAndrew Jones }
170