blob: 3943c9243200d4060c7e24446f24cce20be34a28 [file] [log] [blame]
Patrick Rudolphcb42bc82024-10-23 15:20:08 +02001/* 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 */
22unsigned long __section(".data") fw_dtb_pointer;
23
24static 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
85struct mm_region *mem_map = qemu_sbsa_mem_map;
86
87int 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
96int board_init(void)
97{
98 return 0;
99}
100
101/**
102 * dtb_dt_qemu - Return the address of the QEMU provided FDT.
103 *
104 * @return: Pointer to FDT or NULL on failure
105 */
106static void *dtb_dt_qemu(void)
107{
108 /* FDT might be at start of DRAM */
109 if (fdt_magic(SBSA_MEM_BASE_ADDR) == FDT_MAGIC)
110 return (void *)(u64)SBSA_MEM_BASE_ADDR;
111
112 /* When ARM_LINUX_KERNEL_AS_BL33 is enabled in ATF, it's passed in x0 */
113 if (fw_dtb_pointer >= SBSA_MEM_BASE_ADDR &&
114 fdt_magic(fw_dtb_pointer) == FDT_MAGIC) {
115 return (void *)fw_dtb_pointer;
116 }
117
118 return NULL;
119}
120
121/*
122 * QEMU doesn't set compatible on cpus.
123 * Add them to make sure the U-Boot driver properly bind.
124 */
125static int fdtdec_fix_cpus(void *fdt_blob)
126{
127 int cpus_offset, off, ret;
128 u64 mpidr, i = 0;
129
130 cpus_offset = fdt_path_offset(fdt_blob, "/cpus");
131 if (cpus_offset < 0) {
132 puts("couldn't find /cpus node\n");
133 return cpus_offset;
134 }
135
136 fdt_for_each_subnode(off, fdt_blob, cpus_offset) {
137 if (strncmp(fdt_get_name(fdt_blob, off, NULL), "cpu@", 4))
138 continue;
139
140 mpidr = 0;
141 ret = smc_get_mpidr(i, &mpidr);
142 if (ret) {
143 log_warning("Failed to get MPIDR for processor %lld from SMC: %d\n",
144 i, ret);
145 mpidr = i;
146 }
147
148 ret = fdt_setprop_string(fdt_blob, off, "compatible", "arm,armv8");
149 if (ret < 0)
150 return ret;
151
152 ret = fdt_setprop_string(fdt_blob, off, "device_type", "cpu");
153 if (ret < 0)
154 return ret;
155
156 ret = fdt_setprop_u64(fdt_blob, off, "reg", mpidr);
157 if (ret < 0)
158 return ret;
159 i++;
160 }
161 return 0;
162}
163
164/*
165 * Update the GIC node when necessary and add optional ITS when it has a
166 * non zero base-address.
167 */
168static int fdtdec_fix_gic(void *fdt)
169{
170 u64 gic_dist_base = SBSA_GIC_DIST_BASE_ADDR;
171 u64 gic_redist_base = SBSA_GIC_REDIST_BASE_ADDR;
172 u64 gic_its_base = 0;
173 int offs, ret;
174 u64 reg[10];
175
176 /* Invoke SMC to get real base-address */
177 smc_get_gic_dist_base(&gic_dist_base);
178 smc_get_gic_redist_base(&gic_redist_base);
179
180 if ((gic_dist_base != SBSA_GIC_DIST_BASE_ADDR) ||
181 (gic_redist_base != SBSA_GIC_REDIST_BASE_ADDR)) {
182 offs = fdt_path_offset(fdt, "/interrupt-controller");
183 if (offs < 0) {
184 puts("couldn't find /interrupt-controller node\n");
185 return offs;
186 }
187
188 reg[0] = cpu_to_fdt64(gic_dist_base);
189 reg[1] = cpu_to_fdt64((u64)SBSA_GIC_DIST_LENGTH);
190 reg[2] = cpu_to_fdt64(gic_redist_base);
191 reg[3] = cpu_to_fdt64((u64)SBSA_GIC_REDIST_LENGTH);
192 reg[4] = cpu_to_fdt64(0);
193 reg[5] = cpu_to_fdt64(0);
194 reg[6] = cpu_to_fdt64(SBSA_GIC_HBASE_ADDR);
195 reg[7] = cpu_to_fdt64((u64)SBSA_GIC_HBASE_LENGTH);
196 reg[8] = cpu_to_fdt64(SBSA_GIC_VBASE_ADDR);
197 reg[9] = cpu_to_fdt64((u64)SBSA_GIC_VBASE_LENGTH);
198
199 ret = fdt_setprop_inplace(fdt, offs, "reg", reg, sizeof(reg));
200 }
201
202 smc_get_gic_its_base(&gic_its_base);
203
204 if (gic_its_base != 0) {
205 offs = fdt_path_offset(fdt, "/its");
206 if (offs < 0)
207 return offs;
208
209 ret = fdt_setprop_string(fdt, offs, "status", "okay");
210 if (ret < 0)
211 return ret;
212
213 reg[0] = cpu_to_fdt64(gic_its_base);
214 reg[1] = 0;
215
216 ret = fdt_setprop(fdt, offs, "reg", reg, sizeof(u64) * 2);
217 if (ret < 0)
218 return ret;
219 }
220
221 return 0;
222}
223
224int fdtdec_board_setup(const void *fdt_blob)
225{
226 void *qemu_fdt;
227 int ret;
228
229 /*
230 * Locate the QEMU provided DTB that contains the CPUs and amount of DRAM.
231 */
232 qemu_fdt = dtb_dt_qemu();
233 if (!qemu_fdt) {
234 log_err("QEMU FDT not found\n");
235 return -ENODEV;
236 }
237
238 ret = fdt_increase_size((void *)fdt_blob, 1024 + fdt_totalsize(qemu_fdt));
239 if (ret)
240 return -ENOMEM;
241
242 /*
243 * Merge the QEMU DTB as overlay into the U-Boot provided DTB.
244 */
245 ret = fdt_overlay_apply_node((void *)fdt_blob, 0, qemu_fdt, 0);
246 if (ret < 0)
247 log_err("Failed to apply overlay: %d\n", ret);
248
249 /* Fix QEMU nodes to make sure U-Boot drivers are properly working */
250 ret = fdtdec_fix_cpus((void *)fdt_blob);
251 if (ret < 0)
252 log_err("Failed to fix CPUs in FDT: %d\n", ret);
253
254 ret = fdtdec_fix_gic((void *)fdt_blob);
255 if (ret < 0)
256 log_err("Failed to fix INTC in FDT: %d\n", ret);
257
258 return 0;
259}
260
261int misc_init_r(void)
262{
263 return env_set_hex("fdt_addr", (uintptr_t)gd->fdt_blob);
264}
265
266void reset_cpu(void)
267{
268}
269
270int dram_init(void)
271{
272 return fdtdec_setup_mem_size_base();
273}