1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * (C) 2013
4  * David Feng <fenghua@phytium.com.cn>
5  * Sharma Bhupesh <bhupesh.sharma@freescale.com>
6  *
7  * (C) 2020 EPAM Systems Inc
8  */
9 
10 #include <common.h>
11 #include <cpu_func.h>
12 #include <dm.h>
13 #include <errno.h>
14 #include <malloc.h>
15 #include <xen.h>
16 #include <asm/global_data.h>
17 
18 #include <asm/io.h>
19 #include <asm/armv8/mmu.h>
20 #include <asm/xen.h>
21 #include <asm/xen/hypercall.h>
22 #include <asm/xen/system.h>
23 
24 #include <linux/compiler.h>
25 
26 #include <xen/gnttab.h>
27 #include <xen/hvm.h>
28 
29 DECLARE_GLOBAL_DATA_PTR;
30 
board_init(void)31 int board_init(void)
32 {
33 	return 0;
34 }
35 
36 /*
37  * Use fdt provided by Xen: according to
38  * https://www.kernel.org/doc/Documentation/arm64/booting.txt
39  * x0 is the physical address of the device tree blob (dtb) in system RAM.
40  * This is stored in rom_pointer during low level init.
41  */
board_fdt_blob_setup(void)42 void *board_fdt_blob_setup(void)
43 {
44 	if (fdt_magic(rom_pointer[0]) != FDT_MAGIC)
45 		return NULL;
46 	return (void *)rom_pointer[0];
47 }
48 
49 #define MAX_MEM_MAP_REGIONS 5
50 static struct mm_region xen_mem_map[MAX_MEM_MAP_REGIONS];
51 struct mm_region *mem_map = xen_mem_map;
52 
get_next_memory_node(const void * blob,int mem)53 static int get_next_memory_node(const void *blob, int mem)
54 {
55 	do {
56 		mem = fdt_node_offset_by_prop_value(blob, mem,
57 						    "device_type", "memory", 7);
58 	} while (!fdtdec_get_is_enabled(blob, mem));
59 
60 	return mem;
61 }
62 
setup_mem_map(void)63 static int setup_mem_map(void)
64 {
65 	int i = 0, ret, mem, reg = 0;
66 	struct fdt_resource res;
67 	const void *blob = gd->fdt_blob;
68 	u64 gfn;
69 	phys_addr_t gnttab_base;
70 	phys_size_t gnttab_sz;
71 
72 	/*
73 	 * Add "magic" region which is used by Xen to provide some essentials
74 	 * for the guest: we need console and xenstore.
75 	 */
76 	ret = hvm_get_parameter_maintain_dcache(HVM_PARAM_CONSOLE_PFN, &gfn);
77 	if (ret < 0) {
78 		printf("%s: Can't get HVM_PARAM_CONSOLE_PFN, ret %d\n",
79 		       __func__, ret);
80 		return -EINVAL;
81 	}
82 
83 	xen_mem_map[i].virt = PFN_PHYS(gfn);
84 	xen_mem_map[i].phys = PFN_PHYS(gfn);
85 	xen_mem_map[i].size = PAGE_SIZE;
86 	xen_mem_map[i].attrs = (PTE_BLOCK_MEMTYPE(MT_NORMAL) |
87 				PTE_BLOCK_INNER_SHARE);
88 	i++;
89 
90 	ret = hvm_get_parameter_maintain_dcache(HVM_PARAM_STORE_PFN, &gfn);
91 	if (ret < 0) {
92 		printf("%s: Can't get HVM_PARAM_STORE_PFN, ret %d\n",
93 		       __func__, ret);
94 		return -EINVAL;
95 	}
96 
97 	xen_mem_map[i].virt = PFN_PHYS(gfn);
98 	xen_mem_map[i].phys = PFN_PHYS(gfn);
99 	xen_mem_map[i].size = PAGE_SIZE;
100 	xen_mem_map[i].attrs = (PTE_BLOCK_MEMTYPE(MT_NORMAL) |
101 				PTE_BLOCK_INNER_SHARE);
102 	i++;
103 
104 	/* Get Xen's suggested physical page assignments for the grant table. */
105 	get_gnttab_base(&gnttab_base, &gnttab_sz);
106 
107 	xen_mem_map[i].virt = gnttab_base;
108 	xen_mem_map[i].phys = gnttab_base;
109 	xen_mem_map[i].size = gnttab_sz;
110 	xen_mem_map[i].attrs = (PTE_BLOCK_MEMTYPE(MT_NORMAL) |
111 				PTE_BLOCK_INNER_SHARE);
112 	i++;
113 
114 	mem = get_next_memory_node(blob, -1);
115 	if (mem < 0) {
116 		printf("%s: Missing /memory node\n", __func__);
117 		return -EINVAL;
118 	}
119 
120 	for (; i < MAX_MEM_MAP_REGIONS; i++) {
121 		ret = fdt_get_resource(blob, mem, "reg", reg++, &res);
122 		if (ret == -FDT_ERR_NOTFOUND) {
123 			reg = 0;
124 			mem = get_next_memory_node(blob, mem);
125 			if (mem == -FDT_ERR_NOTFOUND)
126 				break;
127 
128 			ret = fdt_get_resource(blob, mem, "reg", reg++, &res);
129 			if (ret == -FDT_ERR_NOTFOUND)
130 				break;
131 		}
132 		if (ret != 0) {
133 			printf("No reg property for memory node\n");
134 			return -EINVAL;
135 		}
136 
137 		xen_mem_map[i].virt = (phys_addr_t)res.start;
138 		xen_mem_map[i].phys = (phys_addr_t)res.start;
139 		xen_mem_map[i].size = (phys_size_t)(res.end - res.start + 1);
140 		xen_mem_map[i].attrs = (PTE_BLOCK_MEMTYPE(MT_NORMAL) |
141 					PTE_BLOCK_INNER_SHARE);
142 	}
143 	return 0;
144 }
145 
enable_caches(void)146 void enable_caches(void)
147 {
148 	/* Re-setup the memory map as BSS gets cleared after relocation. */
149 	setup_mem_map();
150 	icache_enable();
151 	dcache_enable();
152 }
153 
154 /* Read memory settings from the Xen provided device tree. */
dram_init(void)155 int dram_init(void)
156 {
157 	int ret;
158 
159 	ret = fdtdec_setup_mem_size_base();
160 	if (ret < 0)
161 		return ret;
162 	/* Setup memory map, so MMU page table size can be estimated. */
163 	return setup_mem_map();
164 }
165 
dram_init_banksize(void)166 int dram_init_banksize(void)
167 {
168 	return fdtdec_setup_memory_banksize();
169 }
170 
171 /*
172  * Board specific reset that is system reset.
173  */
reset_cpu(ulong addr)174 void reset_cpu(ulong addr)
175 {
176 }
177 
ft_system_setup(void * blob,struct bd_info * bd)178 int ft_system_setup(void *blob, struct bd_info *bd)
179 {
180 	return 0;
181 }
182 
ft_board_setup(void * blob,struct bd_info * bd)183 int ft_board_setup(void *blob, struct bd_info *bd)
184 {
185 	return 0;
186 }
187 
print_cpuinfo(void)188 int print_cpuinfo(void)
189 {
190 	printf("Xen virtual CPU\n");
191 	return 0;
192 }
193 
board_cleanup_before_linux(void)194 void board_cleanup_before_linux(void)
195 {
196 	xen_fini();
197 }
198 
199