blob: 512a337d7b5143daf2fa46fd0a6e71d52ce8a88f [file] [log] [blame]
Angel Pons5f249e62020-04-04 18:51:01 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
3
David Hendricks8cbd5692017-12-01 20:49:48 -08004/*
David Hendricks8cbd5692017-12-01 20:49:48 -08005 * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0.
6 */
7
8#include <bootmode.h>
9#include <console/console.h>
David Hendricks8cbd5692017-12-01 20:49:48 -080010#include <device/device.h>
11#include <soc/addressmap.h>
12#include <soc/clock.h>
13#include <soc/sdram.h>
14#include <soc/timer.h>
Jens Drenhausfe66a072018-10-09 13:02:49 +020015#include <soc/uart.h>
David Hendricks8cbd5692017-12-01 20:49:48 -080016#include <stddef.h>
17#include <stdlib.h>
18#include <string.h>
19#include <symbols.h>
20#include <libbdk-boot/bdk-boot.h>
Patrick Rudolphd0c67972018-04-17 13:47:55 +020021#include <soc/ecam0.h>
Patrick Rudolphde4410c2018-03-27 12:01:40 +020022#include <console/uart.h>
23#include <libbdk-hal/bdk-pcie.h>
Patrick Rudolphde4410c2018-03-27 12:01:40 +020024#include <device/pci.h>
25#include <libbdk-hal/bdk-qlm.h>
26#include <libbdk-hal/bdk-config.h>
27#include <libbdk-arch/bdk-csrs-bgx.h>
Patrick Rudolph5cdaa332018-04-20 14:43:21 +020028#include <bootmem.h>
29#include <soc/bl31_plat_params.h>
30#include <cbfs.h>
31#include <cbmem.h>
Patrick Rudolphde4410c2018-03-27 12:01:40 +020032#include <fit.h>
33
34static const char *QLM_BGX_MODE_MAP[BDK_QLM_MODE_LAST] = {
35 [BDK_QLM_MODE_SGMII_4X1] = "sgmii",
36 [BDK_QLM_MODE_SGMII_2X1] = "sgmii",
37 [BDK_QLM_MODE_SGMII_1X1] = "sgmii",
38 [BDK_QLM_MODE_XAUI_1X4] = "xaui",
39 [BDK_QLM_MODE_RXAUI_2X2] = "rxaui",
40 [BDK_QLM_MODE_RXAUI_1X2] = "rxaui",
41 [BDK_QLM_MODE_XFI_4X1] = "xfi",
42 [BDK_QLM_MODE_XFI_2X1] = "xfi",
43 [BDK_QLM_MODE_XFI_1X1] = "xfi",
44 [BDK_QLM_MODE_XLAUI_1X4] = "xlaui",
45 [BDK_QLM_MODE_10G_KR_4X1] = "xfi-10g-kr",
46 [BDK_QLM_MODE_10G_KR_2X1] = "xfi-10g-kr",
47 [BDK_QLM_MODE_10G_KR_1X1] = "xfi-10g-kr",
48 [BDK_QLM_MODE_40G_KR4_1X4] = "xlaui-40g-kr",
49 [BDK_QLM_MODE_QSGMII_4X1] = "qsgmii",
50};
51
52static void dt_platform_fixup_phy(struct device_tree_node *node, char *path,
53 int64_t phy_address, bdk_qlm_modes_t qlm_mode)
54{
Patrick Rudolph0a7d6902018-08-22 09:55:15 +020055 const char *data = NULL;
Patrick Rudolphde4410c2018-03-27 12:01:40 +020056 size_t size = 0;
Patrick Rudolph0a7d6902018-08-22 09:55:15 +020057 dt_find_bin_prop(node, "qlm-mode", (const void **)&data, &size);
Patrick Rudolphde4410c2018-03-27 12:01:40 +020058
59 if (!data || strncmp(data, path, 6) != 0)
60 return; /* No key prefix match. */
61 printk(BIOS_INFO, "%s: Node %s = %s\n", __func__, node->name, data);
62
63 if (strlen(path) == strlen(data) && strcmp(data, path) == 0) {
64 /* Keep node, remove "qlm-mode" property */
65 dt_delete_prop(node, "qlm-mode");
66 printk(BIOS_INFO, "%s: Removing qlm-mode on "
67 "node %s\n", __func__, node->name);
68 /* Linux only access the Phy via MDIO.
69 Remove 'phy-handle' if this option is not available */
70 switch (qlm_mode) {
71 case BDK_QLM_MODE_SGMII_4X1:
72 case BDK_QLM_MODE_SGMII_2X1:
73 case BDK_QLM_MODE_SGMII_1X1:
74 case BDK_QLM_MODE_QSGMII_4X1:
75 if ((phy_address & BDK_IF_PHY_TYPE_MASK) !=
76 BDK_IF_PHY_MDIO) {
77 dt_delete_prop(node, "phy-handle");
78 printk(BIOS_INFO, "%s: Removing phy-handle on "
79 "node %s\n", __func__, node->name);
80 }
81 break;
82 default:
83 break;
84 }
85 } else {
86 printk(BIOS_INFO, "%s: Removing node %s\n", __func__,
87 node->name);
88 /* No match, remove node */
89 list_remove(&node->list_node);
90 }
91}
92
93static void dt_iterate_phy(struct device_tree_node *parent,
94 const char *name,
95 char *path,
96 int64_t phy_address,
97 bdk_qlm_modes_t qlm_mode)
98{
99 struct device_tree_property *prop;
100
101 /* Check if parent itself has the required property value. */
102 list_for_each(prop, parent->properties, list_node) {
103 if (!strcmp(name, prop->prop.name)) {
104 dt_platform_fixup_phy(parent, path, phy_address,
105 qlm_mode);
106 }
107 }
108
109 struct device_tree_node *child;
110 list_for_each(child, parent->children, list_node) {
111 dt_iterate_phy(child, name, path, phy_address, qlm_mode);
112 }
113}
114
115static void dt_platform_fixup_mac(struct device_tree_node *node)
116{
117 const char *name = "local-mac-address";
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200118 const u64 *localmac = NULL;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200119 size_t size = 0;
120
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200121 dt_find_bin_prop(node, name, (const void **)&localmac, &size);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200122
123 if (!localmac)
124 return;
125 static size_t used_mac;
126
127 /* Extract our MAC address info so we can assign them */
128 size_t next_free_mac_address =
129 bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS);
130 size_t num_free_mac_addresses =
131 bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS_NUM);
132 size_t num_free_override =
133 bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS_NUM_OVERRIDE);
134 if (num_free_override != -1)
135 num_free_mac_addresses = num_free_override;
136
137 if (size == 6) {
138 if (*localmac)
139 return;
140 if (used_mac < num_free_mac_addresses) {
Julius Werner0e9116f2019-05-13 17:30:31 -0700141 u64 genmac = next_free_mac_address + used_mac;
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200142 dt_add_bin_prop(node, name, &genmac, 6);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200143 used_mac++;
144 return;
145 }
146 }
147
148 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, node->name);
149 list_remove(&node->list_node);
150}
151
152static void dt_iterate_mac(struct device_tree_node *parent)
153{
154 struct device_tree_property *prop;
155 const char *name = "local-mac-address";
156
157 /* Check if parent itself has the required property value. */
158 list_for_each(prop, parent->properties, list_node) {
159 if (!strcmp(name, prop->prop.name))
160 dt_platform_fixup_mac(parent);
161 }
162
163 struct device_tree_node *child;
164 list_for_each(child, parent->children, list_node) {
165 dt_iterate_mac(child);
166 }
167}
168
169/* Do additional device_tree modifications. */
170static int dt_platform_fixup(struct device_tree_fixup *fixup,
171 struct device_tree *tree)
172{
173 struct device_tree_node *dt_node;
174 size_t i;
175
176 /* Set the sclk clock rate. */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700177 dt_node = dt_find_node_by_path(tree, "/soc@0/sclk", NULL, NULL, 0);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200178 if (dt_node) {
179 const u32 freq = thunderx_get_io_clock();
180 printk(BIOS_INFO, "%s: Set SCLK to %u Hz\n", __func__, freq);
181 dt_add_u32_prop(dt_node, "clock-frequency", freq);
182 } else
183 printk(BIOS_ERR, "%s: Node not found. OS might miss-behave !\n",
184 __func__);
185
186 /* Set refclkuaa clock rate. */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700187 dt_node = dt_find_node_by_path(tree, "/soc@0/refclkuaa", NULL,
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200188 NULL, 0);
189 if (dt_node) {
190 const u32 freq = uart_platform_refclk();
191 printk(BIOS_INFO, "%s: Set REFCLKUAA to %u Hz\n", __func__,
192 freq);
193 dt_add_u32_prop(dt_node, "clock-frequency", freq);
194 } else
195 printk(BIOS_ERR, "%s: Node not found. OS might miss-behave !\n",
196 __func__);
197
Jens Drenhausfe66a072018-10-09 13:02:49 +0200198 /* Remove unused UART entries */
199 for (i = 0; i < 4; i++) {
200 char path[32];
201 const uint64_t addr = UAAx_PF_BAR0(i);
202 /* Remove the node */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700203 snprintf(path, sizeof(path), "/soc@0/serial@%llx", addr);
Julius Wernerf36d53c2019-05-03 18:23:34 -0700204 dt_node = dt_find_node_by_path(tree, path, NULL, NULL, 0);
Jens Drenhausfe66a072018-10-09 13:02:49 +0200205 if (!dt_node || uart_is_enabled(i)) {
206 printk(BIOS_INFO, "%s: ignoring %s\n", __func__, path);
207 continue;
208 }
209 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, path);
210 list_remove(&dt_node->list_node);
211 }
212
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200213 /* Remove unused PEM entries */
214 for (i = 0; i < 8; i++) {
215 char path[32];
216 u32 phandle = 0;
217 const uint64_t addr = PEM_PEMX_PF_BAR0(i);
218 /* Remove the node */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700219 snprintf(path, sizeof(path), "/soc@0/pci@%llx", addr);
Julius Wernerf36d53c2019-05-03 18:23:34 -0700220 dt_node = dt_find_node_by_path(tree, path, NULL, NULL, 0);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200221 if (!dt_node || bdk_pcie_is_running(0, i)) {
222 printk(BIOS_INFO, "%s: ignoring %s\n", __func__, path);
223 continue;
224 }
225 /* Store the phandle */
Julius Werner6702b682019-05-03 18:13:53 -0700226 phandle = dt_node->phandle;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200227 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, path);
228 list_remove(&dt_node->list_node);
229
230 /* Remove phandle to non existing nodes */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700231 snprintf(path, sizeof(path), "/soc@0/smmu0@%llx", SMMU_PF_BAR0);
Julius Wernerf36d53c2019-05-03 18:23:34 -0700232 dt_node = dt_find_node_by_path(tree, path, NULL, NULL, 0);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200233 if (!dt_node) {
234 printk(BIOS_ERR, "%s: SMMU entry not found\n",
235 __func__);
236 continue;
237 }
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200238 const u32 *data = NULL;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200239 size_t size = 0;
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200240 dt_find_bin_prop(dt_node, "mmu-masters", (const void **)&data,
241 &size);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200242 if (!size) {
243 printk(BIOS_ERR, "%s: mmu-masters entry not found\n",
244 __func__);
245 continue;
246 }
Patrick Rudolph70866e92018-08-22 09:52:42 +0200247
248 u32 *data_cleaned = malloc(size);
249 if (!data_cleaned)
250 continue;
251
252 size_t n = 0;
253 /* Remove phandle from mmu-masters list */
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200254 for (size_t j = 0; j < size / (sizeof(u32) * 2); j++)
Patrick Rudolph70866e92018-08-22 09:52:42 +0200255 if (be32_to_cpu(data[j * 2]) != phandle) {
256 data_cleaned[n * 2] = data[j * 2];
257 data_cleaned[n * 2 + 1] = data[j * 2 + 1];
258 n++;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200259 }
Patrick Rudolph70866e92018-08-22 09:52:42 +0200260
261 dt_add_bin_prop(dt_node, "mmu-masters", data_cleaned,
262 n * sizeof(u32) * 2);
263
264 free(data_cleaned);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200265 }
266
267 /* Remove QLM mode entries */
268 size_t bgx_index, bgx_iface;
269 for (bgx_iface = 0; bgx_iface < 4; bgx_iface++) {
270 for (bgx_index = 0; bgx_index < 4; bgx_index++) {
271 char path[32];
272 int qlm = bdk_qlm_get_qlm_num(0, BDK_IF_BGX,
273 bgx_iface, bgx_index);
274 bdk_qlm_modes_t qlm_mode = (qlm == -1) ?
275 BDK_QLM_MODE_DISABLED :
276 bdk_qlm_get_mode(0, qlm);
277
278 /* BGXX_CMRX_RX_DMAC_CTL is used to mark ports as
279 * disabled that would otherwise be enabled */
280 if (qlm_mode != BDK_QLM_MODE_DISABLED) {
281 BDK_CSR_INIT(rx_dmac_ctl, 0,
282 BDK_BGXX_CMRX_RX_DMAC_CTL(bgx_iface,
283 bgx_index));
284 if (rx_dmac_ctl.u == 0)
285 qlm_mode = BDK_QLM_MODE_DISABLED;
286 }
287
288 if (qlm_mode == BDK_QLM_MODE_DISABLED)
289 snprintf(path, sizeof(path), "0x0%x%x,disabled",
290 bgx_iface, bgx_index);
291 else
292 snprintf(path, sizeof(path), "0x0%x%x,%s",
293 bgx_iface, bgx_index,
294 QLM_BGX_MODE_MAP[qlm_mode]);
295
296 int64_t phy_address =
297 bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, 0,
298 bgx_iface, bgx_index);
299
300 dt_iterate_phy(tree->root, "qlm-mode", path,
301 phy_address, qlm_mode);
302 }
303 }
304
305 /* Set local MAC address */
306 dt_iterate_mac(tree->root);
307
308 return 0;
309}
David Hendricks8cbd5692017-12-01 20:49:48 -0800310
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200311extern u8 _sff8104[];
312extern u8 _esff8104[];
313
314void bootmem_platform_add_ranges(void)
315{
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200316 bootmem_add_range((uintptr_t)_sff8104,
317 ((uintptr_t)_esff8104 - (uintptr_t)_sff8104),
318 BM_MEM_RESERVED);
319
320 /* Scratchpad for ATF SATA quirks */
Patrick Rudolph52acef12018-08-08 12:46:18 +0200321 bootmem_add_range((sdram_size_mb() - 1) * MiB, 1 * MiB,
322 BM_MEM_RESERVED);
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200323}
324
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200325static void soc_read_resources(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800326{
Patrick Rudolpheead8792018-08-10 13:53:04 +0200327 // HACK: Don't advertise bootblock romstage CAR region, it's broken...
328 ram_resource(dev, 0, 2 * KiB, sdram_size_mb() * KiB - 2 * KiB);
David Hendricks8cbd5692017-12-01 20:49:48 -0800329}
330
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200331static void soc_init_atf(void)
332{
333 static struct bl31_fdt_param fdt_param = {
334 .h = { .type = PARAM_FDT, },
335 };
336
337 size_t size = 0;
338
339 void *ptr = cbfs_boot_map_with_leak("sff8104-linux.dtb",
340 CBFS_TYPE_RAW, &size);
341 if (ptr)
342 memcpy(_sff8104, ptr, size);
343 /* Point to devicetree in secure memory */
344 fdt_param.fdt_ptr = (uintptr_t)_sff8104;
345
Julius Wernerb3f24b42019-05-28 21:01:37 -0700346 cn81xx_register_bl31_param(&fdt_param.h);
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200347
348 static struct bl31_u64_param cbtable_param = {
349 .h = { .type = PARAM_COREBOOT_TABLE, },
350 };
351 /* Point to coreboot tables */
352 cbtable_param.value = (uint64_t)cbmem_find(CBMEM_ID_CBTABLE);
353 if (cbtable_param.value)
Julius Wernerb3f24b42019-05-28 21:01:37 -0700354 cn81xx_register_bl31_param(&cbtable_param.h);
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200355}
356
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200357static void soc_init(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800358{
359 /* Init ECAM, MDIO, PEM, PHY, QLM ... */
360 bdk_boot();
361
Julius Wernercd49cce2019-03-05 16:53:33 -0800362 if (CONFIG(PAYLOAD_FIT_SUPPORT)) {
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200363 struct device_tree_fixup *dt_fixup;
364
365 dt_fixup = malloc(sizeof(*dt_fixup));
366 if (dt_fixup) {
367 dt_fixup->fixup = dt_platform_fixup;
368 list_insert_after(&dt_fixup->list_node,
369 &device_tree_fixups);
370 }
371 }
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200372
Julius Wernercd49cce2019-03-05 16:53:33 -0800373 if (CONFIG(ARM64_USE_ARM_TRUSTED_FIRMWARE))
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200374 soc_init_atf();
David Hendricks8cbd5692017-12-01 20:49:48 -0800375}
376
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200377static void soc_final(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800378{
379 watchdog_disable(0);
380}
381
382static struct device_operations soc_ops = {
Patrick Rudolph88f81af2018-04-11 11:40:55 +0200383 .read_resources = soc_read_resources,
384 .set_resources = DEVICE_NOOP,
385 .enable_resources = DEVICE_NOOP,
386 .init = soc_init,
387 .final = soc_final,
David Hendricks8cbd5692017-12-01 20:49:48 -0800388};
389
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200390static void enable_soc_dev(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800391{
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200392 if (dev->path.type == DEVICE_PATH_DOMAIN &&
393 dev->path.domain.domain == 0) {
394 dev->ops = &pci_domain_ops_ecam0;
395 } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
396 dev->ops = &soc_ops;
397 }
David Hendricks8cbd5692017-12-01 20:49:48 -0800398}
399
400struct chip_operations soc_cavium_cn81xx_ops = {
401 CHIP_NAME("SOC Cavium CN81XX")
402 .enable_dev = enable_soc_dev,
403};