xref: /aosp_15_r20/external/coreboot/src/soc/cavium/cn81xx/soc.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 /*
4  * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0.
5  */
6 
7 #include <console/console.h>
8 #include <device/device.h>
9 #include <soc/addressmap.h>
10 #include <soc/clock.h>
11 #include <soc/sdram.h>
12 #include <soc/timer.h>
13 #include <soc/uart.h>
14 #include <stddef.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <symbols.h>
19 #include <libbdk-boot/bdk-boot.h>
20 #include <soc/ecam0.h>
21 #include <console/uart.h>
22 #include <libbdk-hal/bdk-pcie.h>
23 #include <device/pci.h>
24 #include <libbdk-hal/bdk-qlm.h>
25 #include <libbdk-hal/bdk-config.h>
26 #include <libbdk-arch/bdk-csrs-bgx.h>
27 #include <bootmem.h>
28 #include <soc/bl31_plat_params.h>
29 #include <cbfs.h>
30 #include <cbmem.h>
31 #include <fit.h>
32 
33 static const char *QLM_BGX_MODE_MAP[BDK_QLM_MODE_LAST] = {
34 	[BDK_QLM_MODE_SGMII_4X1]    = "sgmii",
35 	[BDK_QLM_MODE_SGMII_2X1]    = "sgmii",
36 	[BDK_QLM_MODE_SGMII_1X1]    = "sgmii",
37 	[BDK_QLM_MODE_XAUI_1X4]     = "xaui",
38 	[BDK_QLM_MODE_RXAUI_2X2]    = "rxaui",
39 	[BDK_QLM_MODE_RXAUI_1X2]    = "rxaui",
40 	[BDK_QLM_MODE_XFI_4X1]      = "xfi",
41 	[BDK_QLM_MODE_XFI_2X1]      = "xfi",
42 	[BDK_QLM_MODE_XFI_1X1]      = "xfi",
43 	[BDK_QLM_MODE_XLAUI_1X4]    = "xlaui",
44 	[BDK_QLM_MODE_10G_KR_4X1]   = "xfi-10g-kr",
45 	[BDK_QLM_MODE_10G_KR_2X1]   = "xfi-10g-kr",
46 	[BDK_QLM_MODE_10G_KR_1X1]   = "xfi-10g-kr",
47 	[BDK_QLM_MODE_40G_KR4_1X4]  = "xlaui-40g-kr",
48 	[BDK_QLM_MODE_QSGMII_4X1]   = "qsgmii",
49 };
50 
dt_platform_fixup_phy(struct device_tree_node * node,char * path,int64_t phy_address,bdk_qlm_modes_t qlm_mode)51 static void dt_platform_fixup_phy(struct device_tree_node *node, char *path,
52 				  int64_t phy_address, bdk_qlm_modes_t qlm_mode)
53 {
54 	const char *data = NULL;
55 	size_t size = 0;
56 	dt_find_bin_prop(node, "qlm-mode", (const void **)&data, &size);
57 
58 	if (!data || strncmp(data, path, 6) != 0)
59 		return; /* No key prefix match. */
60 	printk(BIOS_INFO, "%s: Node %s = %s\n", __func__, node->name, data);
61 
62 	if (strlen(path) == strlen(data) && strcmp(data, path) == 0) {
63 		/* Keep node, remove "qlm-mode" property */
64 		dt_delete_prop(node, "qlm-mode");
65 		printk(BIOS_INFO, "%s: Removing qlm-mode on "
66 		       "node %s\n", __func__, node->name);
67 		/* Linux only access the Phy via MDIO.
68 		Remove 'phy-handle' if this option is not available */
69 		switch (qlm_mode) {
70 		case BDK_QLM_MODE_SGMII_4X1:
71 		case BDK_QLM_MODE_SGMII_2X1:
72 		case BDK_QLM_MODE_SGMII_1X1:
73 		case BDK_QLM_MODE_QSGMII_4X1:
74 			if ((phy_address & BDK_IF_PHY_TYPE_MASK) !=
75 			    BDK_IF_PHY_MDIO) {
76 				dt_delete_prop(node, "phy-handle");
77 				printk(BIOS_INFO, "%s: Removing phy-handle on "
78 				       "node %s\n", __func__, node->name);
79 			}
80 			break;
81 		default:
82 			break;
83 		}
84 	} else {
85 		printk(BIOS_INFO, "%s: Removing node %s\n", __func__,
86 		       node->name);
87 		/* No match, remove node */
88 		list_remove(&node->list_node);
89 	}
90 }
91 
dt_iterate_phy(struct device_tree_node * parent,const char * name,char * path,int64_t phy_address,bdk_qlm_modes_t qlm_mode)92 static void dt_iterate_phy(struct device_tree_node *parent,
93 				  const char *name,
94 				  char *path,
95 				  int64_t phy_address,
96 				  bdk_qlm_modes_t qlm_mode)
97 {
98 	struct device_tree_property *prop;
99 
100 	/* Check if parent itself has the required property value. */
101 	list_for_each(prop, parent->properties, list_node) {
102 		if (!strcmp(name, prop->prop.name)) {
103 			dt_platform_fixup_phy(parent, path, phy_address,
104 					      qlm_mode);
105 		}
106 	}
107 
108 	struct device_tree_node *child;
109 	list_for_each(child, parent->children, list_node) {
110 		dt_iterate_phy(child, name, path, phy_address, qlm_mode);
111 	}
112 }
113 
dt_platform_fixup_mac(struct device_tree_node * node)114 static void dt_platform_fixup_mac(struct device_tree_node *node)
115 {
116 	const char *name = "local-mac-address";
117 	const u64 *localmac = NULL;
118 	size_t size = 0;
119 
120 	dt_find_bin_prop(node, name, (const void **)&localmac, &size);
121 
122 	if (!localmac)
123 		return;
124 	static size_t used_mac;
125 
126 	/* Extract our MAC address info so we can assign them */
127 	size_t next_free_mac_address =
128 		bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS);
129 	size_t num_free_mac_addresses =
130 		bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS_NUM);
131 	size_t num_free_override =
132 		bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS_NUM_OVERRIDE);
133 	if (num_free_override != -1)
134 		num_free_mac_addresses = num_free_override;
135 
136 	if (size == 6) {
137 		if (*localmac)
138 			return;
139 		if (used_mac < num_free_mac_addresses) {
140 			u64 genmac = next_free_mac_address + used_mac;
141 			dt_add_bin_prop(node, name, &genmac, 6);
142 			used_mac++;
143 			return;
144 		}
145 	}
146 
147 	printk(BIOS_INFO, "%s: Removing node %s\n", __func__, node->name);
148 	list_remove(&node->list_node);
149 }
150 
dt_iterate_mac(struct device_tree_node * parent)151 static void dt_iterate_mac(struct device_tree_node *parent)
152 {
153 	struct device_tree_property *prop;
154 	const char *name = "local-mac-address";
155 
156 	/* Check if parent itself has the required property value. */
157 	list_for_each(prop, parent->properties, list_node) {
158 		if (!strcmp(name, prop->prop.name))
159 			dt_platform_fixup_mac(parent);
160 	}
161 
162 	struct device_tree_node *child;
163 	list_for_each(child, parent->children, list_node) {
164 		dt_iterate_mac(child);
165 	}
166 }
167 
168 /* Do additional device_tree modifications. */
dt_platform_fixup(struct device_tree_fixup * fixup,struct device_tree * tree)169 static int dt_platform_fixup(struct device_tree_fixup *fixup,
170 			      struct device_tree *tree)
171 {
172 	struct device_tree_node *dt_node;
173 	size_t i;
174 
175 	/* Set the sclk clock rate. */
176 	dt_node = dt_find_node_by_path(tree, "/soc@0/sclk", NULL, NULL, 0);
177 	if (dt_node) {
178 		const u32 freq = thunderx_get_io_clock();
179 		printk(BIOS_INFO, "%s: Set SCLK to %u Hz\n", __func__, freq);
180 		dt_add_u32_prop(dt_node, "clock-frequency", freq);
181 	} else
182 		printk(BIOS_ERR, "%s: Node not found. OS might miss-behave !\n",
183 		       __func__);
184 
185 	/* Set refclkuaa clock rate. */
186 	dt_node = dt_find_node_by_path(tree, "/soc@0/refclkuaa", NULL,
187 				       NULL, 0);
188 	if (dt_node) {
189 		const u32 freq = uart_platform_refclk();
190 		printk(BIOS_INFO, "%s: Set REFCLKUAA to %u Hz\n", __func__,
191 		       freq);
192 		dt_add_u32_prop(dt_node, "clock-frequency", freq);
193 	} else
194 		printk(BIOS_ERR, "%s: Node not found. OS might miss-behave !\n",
195 		       __func__);
196 
197 	/* Remove unused UART entries */
198 	for (i = 0; i < 4; i++) {
199 		char path[32];
200 		const uint64_t addr = UAAx_PF_BAR0(i);
201 		/* Remove the node */
202 		snprintf(path, sizeof(path), "/soc@0/serial@%llx", addr);
203 		dt_node = dt_find_node_by_path(tree, path, NULL, NULL, 0);
204 		if (!dt_node || uart_is_enabled(i)) {
205 			printk(BIOS_INFO, "%s: ignoring %s\n", __func__, path);
206 			continue;
207 		}
208 		printk(BIOS_INFO, "%s: Removing node %s\n", __func__, path);
209 		list_remove(&dt_node->list_node);
210 	}
211 
212 	/* Remove unused PEM entries */
213 	for (i = 0; i < 8; i++) {
214 		char path[32];
215 		u32 phandle = 0;
216 		const uint64_t addr = PEM_PEMX_PF_BAR0(i);
217 		/* Remove the node */
218 		snprintf(path, sizeof(path), "/soc@0/pci@%llx", addr);
219 		dt_node = dt_find_node_by_path(tree, path, NULL, NULL, 0);
220 		if (!dt_node || bdk_pcie_is_running(0, i)) {
221 			printk(BIOS_INFO, "%s: ignoring %s\n", __func__, path);
222 			continue;
223 		}
224 		/* Store the phandle */
225 		phandle = dt_node->phandle;
226 		printk(BIOS_INFO, "%s: Removing node %s\n", __func__, path);
227 		list_remove(&dt_node->list_node);
228 
229 		/* Remove phandle to non existing nodes */
230 		snprintf(path, sizeof(path), "/soc@0/smmu0@%llx", SMMU_PF_BAR0);
231 		dt_node = dt_find_node_by_path(tree, path, NULL, NULL, 0);
232 		if (!dt_node) {
233 			printk(BIOS_ERR, "%s: SMMU entry not found\n",
234 			       __func__);
235 			continue;
236 		}
237 		const u32 *data = NULL;
238 		size_t size = 0;
239 		dt_find_bin_prop(dt_node, "mmu-masters", (const void **)&data,
240 				 &size);
241 		if (!size) {
242 			printk(BIOS_ERR, "%s: mmu-masters entry not found\n",
243 			       __func__);
244 			continue;
245 		}
246 
247 		u32 *data_cleaned = malloc(size);
248 		if (!data_cleaned)
249 			continue;
250 
251 		size_t n = 0;
252 		/* Remove phandle from mmu-masters list */
253 		for (size_t j = 0; j < size / (sizeof(u32) * 2); j++)
254 			if (be32_to_cpu(data[j * 2]) != phandle) {
255 				data_cleaned[n * 2] = data[j * 2];
256 				data_cleaned[n * 2 + 1] = data[j * 2 + 1];
257 				n++;
258 			}
259 
260 		dt_add_bin_prop(dt_node, "mmu-masters", data_cleaned,
261 				n * sizeof(u32) * 2);
262 
263 		free(data_cleaned);
264 	}
265 
266 	/* Remove QLM mode entries */
267 	size_t bgx_index, bgx_iface;
268 	for (bgx_iface = 0; bgx_iface < 4; bgx_iface++) {
269 		for (bgx_index = 0; bgx_index < 4; bgx_index++) {
270 			char path[32];
271 			int qlm = bdk_qlm_get_qlm_num(0, BDK_IF_BGX,
272 						      bgx_iface, bgx_index);
273 			bdk_qlm_modes_t qlm_mode = (qlm == -1) ?
274 				BDK_QLM_MODE_DISABLED :
275 				bdk_qlm_get_mode(0, qlm);
276 
277 			/* BGXX_CMRX_RX_DMAC_CTL is used to mark ports as
278 			 * disabled that would otherwise be enabled */
279 			if (qlm_mode != BDK_QLM_MODE_DISABLED) {
280 				BDK_CSR_INIT(rx_dmac_ctl, 0,
281 					BDK_BGXX_CMRX_RX_DMAC_CTL(bgx_iface,
282 								  bgx_index));
283 				if (rx_dmac_ctl.u == 0)
284 					qlm_mode = BDK_QLM_MODE_DISABLED;
285 			}
286 
287 			if (qlm_mode == BDK_QLM_MODE_DISABLED)
288 				snprintf(path, sizeof(path), "0x0%x%x,disabled",
289 					 bgx_iface, bgx_index);
290 			else
291 				snprintf(path, sizeof(path), "0x0%x%x,%s",
292 					 bgx_iface, bgx_index,
293 					 QLM_BGX_MODE_MAP[qlm_mode]);
294 
295 			int64_t phy_address =
296 			    bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, 0,
297 					       bgx_iface, bgx_index);
298 
299 			dt_iterate_phy(tree->root, "qlm-mode", path,
300 				       phy_address, qlm_mode);
301 		}
302 	}
303 
304 	/* Set local MAC address */
305 	dt_iterate_mac(tree->root);
306 
307 	return 0;
308 }
309 
310 extern u8 _sff8104[];
311 extern u8 _esff8104[];
312 
bootmem_platform_add_ranges(void)313 void bootmem_platform_add_ranges(void)
314 {
315 	bootmem_add_range((uintptr_t)_sff8104,
316 			  ((uintptr_t)_esff8104 - (uintptr_t)_sff8104),
317 			  BM_MEM_RESERVED);
318 
319 	/* Scratchpad for ATF SATA quirks */
320 	bootmem_add_range((sdram_size_mb() - 1) * MiB, 1 * MiB,
321 			  BM_MEM_RESERVED);
322 }
323 
soc_read_resources(struct device * dev)324 static void soc_read_resources(struct device *dev)
325 {
326 	// HACK: Don't advertise bootblock romstage CAR region, it's broken...
327 	ram_from_to(dev, 0, 2 * MiB, sdram_size_mb() * (uint64_t)MiB);
328 }
329 
soc_init_atf(void)330 static void soc_init_atf(void)
331 {
332 	static struct bl31_fdt_param fdt_param = {
333 		.h = { .type = PARAM_FDT, },
334 	};
335 
336 	size_t size = 0;
337 
338 	void *ptr = cbfs_map("sff8104-linux.dtb", &size);
339 	if (ptr)
340 		memcpy(_sff8104, ptr, size);
341 	/* Point to devicetree in secure memory */
342 	fdt_param.fdt_ptr = (uintptr_t)_sff8104;
343 
344 	cn81xx_register_bl31_param(&fdt_param.h);
345 
346 	static struct bl31_u64_param cbtable_param = {
347 		.h = { .type = PARAM_COREBOOT_TABLE, },
348 	};
349 	/* Point to coreboot tables */
350 	cbtable_param.value = (uint64_t)cbmem_find(CBMEM_ID_CBTABLE);
351 	if (cbtable_param.value)
352 		cn81xx_register_bl31_param(&cbtable_param.h);
353 }
354 
soc_init(struct device * dev)355 static void soc_init(struct device *dev)
356 {
357 	/* Init ECAM, MDIO, PEM, PHY, QLM ... */
358 	bdk_boot();
359 
360 	if (CONFIG(PAYLOAD_FIT_SUPPORT)) {
361 		struct device_tree_fixup *dt_fixup;
362 
363 		dt_fixup = malloc(sizeof(*dt_fixup));
364 		if (dt_fixup) {
365 			dt_fixup->fixup = dt_platform_fixup;
366 			list_insert_after(&dt_fixup->list_node,
367 					  &device_tree_fixups);
368 		}
369 	}
370 
371 	if (CONFIG(ARM64_USE_ARM_TRUSTED_FIRMWARE))
372 		soc_init_atf();
373 }
374 
soc_final(struct device * dev)375 static void soc_final(struct device *dev)
376 {
377 	watchdog_disable(0);
378 }
379 
380 static struct device_operations soc_ops = {
381 	.read_resources   = soc_read_resources,
382 	.set_resources    = noop_set_resources,
383 	.init             = soc_init,
384 	.final            = soc_final,
385 };
386 
enable_soc_dev(struct device * dev)387 static void enable_soc_dev(struct device *dev)
388 {
389 	if (dev->path.type == DEVICE_PATH_DOMAIN &&
390 		dev->path.domain.domain == 0) {
391 		dev->ops = &pci_domain_ops_ecam0;
392 	} else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
393 		dev->ops = &soc_ops;
394 	}
395 }
396 
397 struct chip_operations soc_cavium_cn81xx_ops = {
398 	.name = "SOC Cavium CN81XX",
399 	.enable_dev = enable_soc_dev,
400 };
401