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 }