1 /* SPDX-License-Identifier: GPL-2.0+ */
2 /*
3  * Copyright (c) 2017 Tuomas Tynkkynen
4  */
5 
6 #include <cpu_func.h>
7 #include <dm.h>
8 #include <env.h>
9 #include <fdtdec.h>
10 #include <fdt_support.h>
11 #include <init.h>
12 #include <log.h>
13 #include <usb.h>
14 #include <asm/armv8/mmu.h>
15 
16 #include "qemu-sbsa.h"
17 
18 /* Assigned in lowlevel_init.S
19  * Push the variable into the .data section so that it
20  * does not get cleared later.
21  */
22 unsigned long __section(".data") fw_dtb_pointer;
23 
24 static struct mm_region qemu_sbsa_mem_map[] = {
25 	{
26 		/* Secure flash */
27 		.virt = SBSA_SECURE_FLASH_BASE_ADDR,
28 		.phys = SBSA_SECURE_FLASH_BASE_ADDR,
29 		.size = SBSA_SECURE_FLASH_LENGTH,
30 		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
31 			 PTE_BLOCK_INNER_SHARE |
32 			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
33 	}, {
34 		/* Flash */
35 		.virt = SBSA_FLASH_BASE_ADDR,
36 		.phys = SBSA_FLASH_BASE_ADDR,
37 		.size = SBSA_FLASH_LENGTH,
38 		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
39 			 PTE_BLOCK_INNER_SHARE
40 	}, {
41 		/* Lowmem peripherals */
42 		.virt = SBSA_PERIPH_BASE_ADDR,
43 		.phys = SBSA_PERIPH_BASE_ADDR,
44 		.size = SBSA_PCIE_MMIO_BASE_ADDR - SBSA_PERIPH_BASE_ADDR,
45 		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
46 			 PTE_BLOCK_NON_SHARE |
47 			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
48 	}, {
49 		/* 32-bit address PCIE MMIO space */
50 		.virt = SBSA_PCIE_MMIO_BASE_ADDR,
51 		.phys = SBSA_PCIE_MMIO_BASE_ADDR,
52 		.size = SBSA_PCIE_MMIO_LENGTH,
53 		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
54 			 PTE_BLOCK_NON_SHARE |
55 			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
56 	}, {
57 		/* PCI-E ECAM memory area */
58 		.virt = SBSA_PCIE_ECAM_BASE_ADDR,
59 		.phys = SBSA_PCIE_ECAM_BASE_ADDR,
60 		.size = SBSA_PCIE_ECAM_LENGTH,
61 		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
62 			 PTE_BLOCK_NON_SHARE |
63 			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
64 	}, {
65 		/* Highmem PCI-E MMIO memory area */
66 		.virt = SBSA_PCIE_MMIO_HIGH_BASE_ADDR,
67 		.phys = SBSA_PCIE_MMIO_HIGH_BASE_ADDR,
68 		.size = SBSA_PCIE_MMIO_HIGH_LENGTH,
69 		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
70 			 PTE_BLOCK_NON_SHARE |
71 			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
72 	}, {
73 		/* DRAM */
74 		.virt = SBSA_MEM_BASE_ADDR,
75 		.phys = SBSA_MEM_BASE_ADDR,
76 		.size = 0x800000000000ULL,
77 		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
78 			 PTE_BLOCK_INNER_SHARE
79 	}, {
80 		/* List terminator */
81 		0,
82 	}
83 };
84 
85 struct mm_region *mem_map = qemu_sbsa_mem_map;
86 
board_late_init(void)87 int board_late_init(void)
88 {
89 	/* start usb so that usb keyboard can be used as input device */
90 	if (CONFIG_IS_ENABLED(USB_KEYBOARD))
91 		usb_init();
92 
93 	return 0;
94 }
95 
96 /**
97  * dtb_dt_qemu - Return the address of the QEMU provided FDT.
98  *
99  * @return: Pointer to FDT or NULL on failure
100  */
dtb_dt_qemu(void)101 static void *dtb_dt_qemu(void)
102 {
103 	/* FDT might be at start of DRAM */
104 	if (fdt_magic(SBSA_MEM_BASE_ADDR) == FDT_MAGIC)
105 		return (void *)(u64)SBSA_MEM_BASE_ADDR;
106 
107 	/* When ARM_LINUX_KERNEL_AS_BL33 is enabled in ATF, it's passed in x0 */
108 	if (fw_dtb_pointer >= SBSA_MEM_BASE_ADDR &&
109 	    fdt_magic(fw_dtb_pointer) == FDT_MAGIC) {
110 		return (void *)fw_dtb_pointer;
111 	}
112 
113 	return NULL;
114 }
115 
116 /*
117  * QEMU doesn't set compatible on cpus.
118  * Add them to make sure the U-Boot driver properly bind.
119  */
fdtdec_fix_cpus(void * fdt_blob)120 static int fdtdec_fix_cpus(void *fdt_blob)
121 {
122 	int cpus_offset, off, ret;
123 	u64 mpidr, i = 0;
124 
125 	cpus_offset = fdt_path_offset(fdt_blob, "/cpus");
126 	if (cpus_offset < 0) {
127 		puts("couldn't find /cpus node\n");
128 		return cpus_offset;
129 	}
130 
131 	fdt_for_each_subnode(off, fdt_blob, cpus_offset) {
132 		if (strncmp(fdt_get_name(fdt_blob, off, NULL), "cpu@", 4))
133 			continue;
134 
135 		mpidr = 0;
136 		ret = smc_get_mpidr(i, &mpidr);
137 		if (ret) {
138 			log_warning("Failed to get MPIDR for processor %lld from SMC: %d\n",
139 				    i, ret);
140 			mpidr = i;
141 		}
142 
143 		ret = fdt_setprop_string(fdt_blob, off, "compatible", "arm,armv8");
144 		if (ret < 0)
145 			return ret;
146 
147 		ret = fdt_setprop_string(fdt_blob, off, "device_type", "cpu");
148 		if (ret < 0)
149 			return ret;
150 
151 		ret = fdt_setprop_u64(fdt_blob, off, "reg", mpidr);
152 		if (ret < 0)
153 			return ret;
154 		i++;
155 	}
156 	return 0;
157 }
158 
159 /*
160  * Update the GIC node when necessary and add optional ITS when it has a
161  * non zero base-address.
162  */
fdtdec_fix_gic(void * fdt)163 static int fdtdec_fix_gic(void *fdt)
164 {
165 	u64 gic_dist_base = SBSA_GIC_DIST_BASE_ADDR;
166 	u64 gic_redist_base = SBSA_GIC_REDIST_BASE_ADDR;
167 	u64 gic_its_base = 0;
168 	int offs, ret;
169 	u64 reg[10];
170 
171 	/* Invoke SMC to get real base-address */
172 	smc_get_gic_dist_base(&gic_dist_base);
173 	smc_get_gic_redist_base(&gic_redist_base);
174 
175 	if ((gic_dist_base != SBSA_GIC_DIST_BASE_ADDR) ||
176 	    (gic_redist_base != SBSA_GIC_REDIST_BASE_ADDR)) {
177 		offs = fdt_path_offset(fdt, "/interrupt-controller");
178 		if (offs < 0) {
179 			puts("couldn't find /interrupt-controller node\n");
180 			return offs;
181 		}
182 
183 		reg[0] = cpu_to_fdt64(gic_dist_base);
184 		reg[1] = cpu_to_fdt64((u64)SBSA_GIC_DIST_LENGTH);
185 		reg[2] = cpu_to_fdt64(gic_redist_base);
186 		reg[3] = cpu_to_fdt64((u64)SBSA_GIC_REDIST_LENGTH);
187 		reg[4] = cpu_to_fdt64(0);
188 		reg[5] = cpu_to_fdt64(0);
189 		reg[6] = cpu_to_fdt64(SBSA_GIC_HBASE_ADDR);
190 		reg[7] = cpu_to_fdt64((u64)SBSA_GIC_HBASE_LENGTH);
191 		reg[8] = cpu_to_fdt64(SBSA_GIC_VBASE_ADDR);
192 		reg[9] = cpu_to_fdt64((u64)SBSA_GIC_VBASE_LENGTH);
193 
194 		ret = fdt_setprop_inplace(fdt, offs, "reg", reg, sizeof(reg));
195 	}
196 
197 	smc_get_gic_its_base(&gic_its_base);
198 
199 	if (gic_its_base != 0) {
200 		offs = fdt_path_offset(fdt, "/interrupt-controller/msi-controller");
201 		if (offs < 0)
202 			return offs;
203 
204 		ret = fdt_setprop_string(fdt, offs, "status", "okay");
205 		if (ret < 0)
206 			return ret;
207 
208 		reg[0] = cpu_to_fdt64(gic_its_base);
209 		reg[1] = 0;
210 
211 		ret = fdt_setprop(fdt, offs, "reg", reg, sizeof(u64) * 2);
212 		if (ret < 0)
213 			return ret;
214 	}
215 
216 	return 0;
217 }
218 
fdtdec_board_setup(const void * fdt_blob)219 int fdtdec_board_setup(const void *fdt_blob)
220 {
221 	void *qemu_fdt;
222 	int ret;
223 
224 	/*
225 	 * Locate the QEMU provided DTB that contains the CPUs and amount of DRAM.
226 	 */
227 	qemu_fdt = dtb_dt_qemu();
228 	if (!qemu_fdt) {
229 		log_err("QEMU FDT not found\n");
230 		return -ENODEV;
231 	}
232 
233 	ret = fdt_increase_size((void *)fdt_blob, 1024 + fdt_totalsize(qemu_fdt));
234 	if (ret)
235 		return -ENOMEM;
236 
237 	/*
238 	 * Merge the QEMU DTB as overlay into the U-Boot provided DTB.
239 	 */
240 	ret = fdt_overlay_apply_node((void *)fdt_blob, 0, qemu_fdt, 0);
241 	if (ret < 0)
242 		log_err("Failed to apply overlay: %d\n", ret);
243 
244 	/* Fix QEMU nodes to make sure U-Boot drivers are properly working */
245 	ret = fdtdec_fix_cpus((void *)fdt_blob);
246 	if (ret < 0)
247 		log_err("Failed to fix CPUs in FDT: %d\n", ret);
248 
249 	ret = fdtdec_fix_gic((void *)fdt_blob);
250 	if (ret < 0)
251 		log_err("Failed to fix INTC in FDT: %d\n", ret);
252 
253 	return 0;
254 }
255 
misc_init_r(void)256 int misc_init_r(void)
257 {
258 	return env_set_hex("fdt_addr", (uintptr_t)gd->fdt_blob);
259 }
260 
reset_cpu(void)261 void reset_cpu(void)
262 {
263 }
264 
dram_init(void)265 int dram_init(void)
266 {
267 	return fdtdec_setup_mem_size_base();
268 }