blob: 9312593fe69ed4507a8f088256155d3505ef9591 [file] [log] [blame]
David Hendricks8cbd5692017-12-01 20:49:48 -08001/*
2 * This file is part of the coreboot project.
3 *
David Hendricks8cbd5692017-12-01 20:49:48 -08004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0.
15 */
16
17#include <bootmode.h>
18#include <console/console.h>
David Hendricks8cbd5692017-12-01 20:49:48 -080019#include <device/device.h>
20#include <soc/addressmap.h>
21#include <soc/clock.h>
22#include <soc/sdram.h>
23#include <soc/timer.h>
Jens Drenhausfe66a072018-10-09 13:02:49 +020024#include <soc/uart.h>
David Hendricks8cbd5692017-12-01 20:49:48 -080025#include <stddef.h>
26#include <stdlib.h>
27#include <string.h>
28#include <symbols.h>
29#include <libbdk-boot/bdk-boot.h>
Patrick Rudolphd0c67972018-04-17 13:47:55 +020030#include <soc/ecam0.h>
Patrick Rudolphde4410c2018-03-27 12:01:40 +020031#include <console/uart.h>
32#include <libbdk-hal/bdk-pcie.h>
Patrick Rudolphde4410c2018-03-27 12:01:40 +020033#include <device/pci.h>
34#include <libbdk-hal/bdk-qlm.h>
35#include <libbdk-hal/bdk-config.h>
36#include <libbdk-arch/bdk-csrs-bgx.h>
Patrick Rudolph5cdaa332018-04-20 14:43:21 +020037#include <bootmem.h>
38#include <soc/bl31_plat_params.h>
39#include <cbfs.h>
40#include <cbmem.h>
Patrick Rudolphde4410c2018-03-27 12:01:40 +020041#include <fit.h>
42
43static const char *QLM_BGX_MODE_MAP[BDK_QLM_MODE_LAST] = {
44 [BDK_QLM_MODE_SGMII_4X1] = "sgmii",
45 [BDK_QLM_MODE_SGMII_2X1] = "sgmii",
46 [BDK_QLM_MODE_SGMII_1X1] = "sgmii",
47 [BDK_QLM_MODE_XAUI_1X4] = "xaui",
48 [BDK_QLM_MODE_RXAUI_2X2] = "rxaui",
49 [BDK_QLM_MODE_RXAUI_1X2] = "rxaui",
50 [BDK_QLM_MODE_XFI_4X1] = "xfi",
51 [BDK_QLM_MODE_XFI_2X1] = "xfi",
52 [BDK_QLM_MODE_XFI_1X1] = "xfi",
53 [BDK_QLM_MODE_XLAUI_1X4] = "xlaui",
54 [BDK_QLM_MODE_10G_KR_4X1] = "xfi-10g-kr",
55 [BDK_QLM_MODE_10G_KR_2X1] = "xfi-10g-kr",
56 [BDK_QLM_MODE_10G_KR_1X1] = "xfi-10g-kr",
57 [BDK_QLM_MODE_40G_KR4_1X4] = "xlaui-40g-kr",
58 [BDK_QLM_MODE_QSGMII_4X1] = "qsgmii",
59};
60
61static void dt_platform_fixup_phy(struct device_tree_node *node, char *path,
62 int64_t phy_address, bdk_qlm_modes_t qlm_mode)
63{
Patrick Rudolph0a7d6902018-08-22 09:55:15 +020064 const char *data = NULL;
Patrick Rudolphde4410c2018-03-27 12:01:40 +020065 size_t size = 0;
Patrick Rudolph0a7d6902018-08-22 09:55:15 +020066 dt_find_bin_prop(node, "qlm-mode", (const void **)&data, &size);
Patrick Rudolphde4410c2018-03-27 12:01:40 +020067
68 if (!data || strncmp(data, path, 6) != 0)
69 return; /* No key prefix match. */
70 printk(BIOS_INFO, "%s: Node %s = %s\n", __func__, node->name, data);
71
72 if (strlen(path) == strlen(data) && strcmp(data, path) == 0) {
73 /* Keep node, remove "qlm-mode" property */
74 dt_delete_prop(node, "qlm-mode");
75 printk(BIOS_INFO, "%s: Removing qlm-mode on "
76 "node %s\n", __func__, node->name);
77 /* Linux only access the Phy via MDIO.
78 Remove 'phy-handle' if this option is not available */
79 switch (qlm_mode) {
80 case BDK_QLM_MODE_SGMII_4X1:
81 case BDK_QLM_MODE_SGMII_2X1:
82 case BDK_QLM_MODE_SGMII_1X1:
83 case BDK_QLM_MODE_QSGMII_4X1:
84 if ((phy_address & BDK_IF_PHY_TYPE_MASK) !=
85 BDK_IF_PHY_MDIO) {
86 dt_delete_prop(node, "phy-handle");
87 printk(BIOS_INFO, "%s: Removing phy-handle on "
88 "node %s\n", __func__, node->name);
89 }
90 break;
91 default:
92 break;
93 }
94 } else {
95 printk(BIOS_INFO, "%s: Removing node %s\n", __func__,
96 node->name);
97 /* No match, remove node */
98 list_remove(&node->list_node);
99 }
100}
101
102static void dt_iterate_phy(struct device_tree_node *parent,
103 const char *name,
104 char *path,
105 int64_t phy_address,
106 bdk_qlm_modes_t qlm_mode)
107{
108 struct device_tree_property *prop;
109
110 /* Check if parent itself has the required property value. */
111 list_for_each(prop, parent->properties, list_node) {
112 if (!strcmp(name, prop->prop.name)) {
113 dt_platform_fixup_phy(parent, path, phy_address,
114 qlm_mode);
115 }
116 }
117
118 struct device_tree_node *child;
119 list_for_each(child, parent->children, list_node) {
120 dt_iterate_phy(child, name, path, phy_address, qlm_mode);
121 }
122}
123
124static void dt_platform_fixup_mac(struct device_tree_node *node)
125{
126 const char *name = "local-mac-address";
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200127 const u64 *localmac = NULL;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200128 size_t size = 0;
129
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200130 dt_find_bin_prop(node, name, (const void **)&localmac, &size);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200131
132 if (!localmac)
133 return;
134 static size_t used_mac;
135
136 /* Extract our MAC address info so we can assign them */
137 size_t next_free_mac_address =
138 bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS);
139 size_t num_free_mac_addresses =
140 bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS_NUM);
141 size_t num_free_override =
142 bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS_NUM_OVERRIDE);
143 if (num_free_override != -1)
144 num_free_mac_addresses = num_free_override;
145
146 if (size == 6) {
147 if (*localmac)
148 return;
149 if (used_mac < num_free_mac_addresses) {
Julius Werner0e9116f2019-05-13 17:30:31 -0700150 u64 genmac = next_free_mac_address + used_mac;
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200151 dt_add_bin_prop(node, name, &genmac, 6);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200152 used_mac++;
153 return;
154 }
155 }
156
157 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, node->name);
158 list_remove(&node->list_node);
159}
160
161static void dt_iterate_mac(struct device_tree_node *parent)
162{
163 struct device_tree_property *prop;
164 const char *name = "local-mac-address";
165
166 /* Check if parent itself has the required property value. */
167 list_for_each(prop, parent->properties, list_node) {
168 if (!strcmp(name, prop->prop.name))
169 dt_platform_fixup_mac(parent);
170 }
171
172 struct device_tree_node *child;
173 list_for_each(child, parent->children, list_node) {
174 dt_iterate_mac(child);
175 }
176}
177
178/* Do additional device_tree modifications. */
179static int dt_platform_fixup(struct device_tree_fixup *fixup,
180 struct device_tree *tree)
181{
182 struct device_tree_node *dt_node;
183 size_t i;
184
185 /* Set the sclk clock rate. */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700186 dt_node = dt_find_node_by_path(tree, "/soc@0/sclk", NULL, NULL, 0);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200187 if (dt_node) {
188 const u32 freq = thunderx_get_io_clock();
189 printk(BIOS_INFO, "%s: Set SCLK to %u Hz\n", __func__, freq);
190 dt_add_u32_prop(dt_node, "clock-frequency", freq);
191 } else
192 printk(BIOS_ERR, "%s: Node not found. OS might miss-behave !\n",
193 __func__);
194
195 /* Set refclkuaa clock rate. */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700196 dt_node = dt_find_node_by_path(tree, "/soc@0/refclkuaa", NULL,
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200197 NULL, 0);
198 if (dt_node) {
199 const u32 freq = uart_platform_refclk();
200 printk(BIOS_INFO, "%s: Set REFCLKUAA to %u Hz\n", __func__,
201 freq);
202 dt_add_u32_prop(dt_node, "clock-frequency", freq);
203 } else
204 printk(BIOS_ERR, "%s: Node not found. OS might miss-behave !\n",
205 __func__);
206
Jens Drenhausfe66a072018-10-09 13:02:49 +0200207 /* Remove unused UART entries */
208 for (i = 0; i < 4; i++) {
209 char path[32];
210 const uint64_t addr = UAAx_PF_BAR0(i);
211 /* Remove the node */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700212 snprintf(path, sizeof(path), "/soc@0/serial@%llx", addr);
Julius Wernerf36d53c2019-05-03 18:23:34 -0700213 dt_node = dt_find_node_by_path(tree, path, NULL, NULL, 0);
Jens Drenhausfe66a072018-10-09 13:02:49 +0200214 if (!dt_node || uart_is_enabled(i)) {
215 printk(BIOS_INFO, "%s: ignoring %s\n", __func__, path);
216 continue;
217 }
218 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, path);
219 list_remove(&dt_node->list_node);
220 }
221
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200222 /* Remove unused PEM entries */
223 for (i = 0; i < 8; i++) {
224 char path[32];
225 u32 phandle = 0;
226 const uint64_t addr = PEM_PEMX_PF_BAR0(i);
227 /* Remove the node */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700228 snprintf(path, sizeof(path), "/soc@0/pci@%llx", addr);
Julius Wernerf36d53c2019-05-03 18:23:34 -0700229 dt_node = dt_find_node_by_path(tree, path, NULL, NULL, 0);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200230 if (!dt_node || bdk_pcie_is_running(0, i)) {
231 printk(BIOS_INFO, "%s: ignoring %s\n", __func__, path);
232 continue;
233 }
234 /* Store the phandle */
Julius Werner6702b682019-05-03 18:13:53 -0700235 phandle = dt_node->phandle;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200236 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, path);
237 list_remove(&dt_node->list_node);
238
239 /* Remove phandle to non existing nodes */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700240 snprintf(path, sizeof(path), "/soc@0/smmu0@%llx", SMMU_PF_BAR0);
Julius Wernerf36d53c2019-05-03 18:23:34 -0700241 dt_node = dt_find_node_by_path(tree, path, NULL, NULL, 0);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200242 if (!dt_node) {
243 printk(BIOS_ERR, "%s: SMMU entry not found\n",
244 __func__);
245 continue;
246 }
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200247 const u32 *data = NULL;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200248 size_t size = 0;
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200249 dt_find_bin_prop(dt_node, "mmu-masters", (const void **)&data,
250 &size);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200251 if (!size) {
252 printk(BIOS_ERR, "%s: mmu-masters entry not found\n",
253 __func__);
254 continue;
255 }
Patrick Rudolph70866e92018-08-22 09:52:42 +0200256
257 u32 *data_cleaned = malloc(size);
258 if (!data_cleaned)
259 continue;
260
261 size_t n = 0;
262 /* Remove phandle from mmu-masters list */
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200263 for (size_t j = 0; j < size / (sizeof(u32) * 2); j++)
Patrick Rudolph70866e92018-08-22 09:52:42 +0200264 if (be32_to_cpu(data[j * 2]) != phandle) {
265 data_cleaned[n * 2] = data[j * 2];
266 data_cleaned[n * 2 + 1] = data[j * 2 + 1];
267 n++;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200268 }
Patrick Rudolph70866e92018-08-22 09:52:42 +0200269
270 dt_add_bin_prop(dt_node, "mmu-masters", data_cleaned,
271 n * sizeof(u32) * 2);
272
273 free(data_cleaned);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200274 }
275
276 /* Remove QLM mode entries */
277 size_t bgx_index, bgx_iface;
278 for (bgx_iface = 0; bgx_iface < 4; bgx_iface++) {
279 for (bgx_index = 0; bgx_index < 4; bgx_index++) {
280 char path[32];
281 int qlm = bdk_qlm_get_qlm_num(0, BDK_IF_BGX,
282 bgx_iface, bgx_index);
283 bdk_qlm_modes_t qlm_mode = (qlm == -1) ?
284 BDK_QLM_MODE_DISABLED :
285 bdk_qlm_get_mode(0, qlm);
286
287 /* BGXX_CMRX_RX_DMAC_CTL is used to mark ports as
288 * disabled that would otherwise be enabled */
289 if (qlm_mode != BDK_QLM_MODE_DISABLED) {
290 BDK_CSR_INIT(rx_dmac_ctl, 0,
291 BDK_BGXX_CMRX_RX_DMAC_CTL(bgx_iface,
292 bgx_index));
293 if (rx_dmac_ctl.u == 0)
294 qlm_mode = BDK_QLM_MODE_DISABLED;
295 }
296
297 if (qlm_mode == BDK_QLM_MODE_DISABLED)
298 snprintf(path, sizeof(path), "0x0%x%x,disabled",
299 bgx_iface, bgx_index);
300 else
301 snprintf(path, sizeof(path), "0x0%x%x,%s",
302 bgx_iface, bgx_index,
303 QLM_BGX_MODE_MAP[qlm_mode]);
304
305 int64_t phy_address =
306 bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, 0,
307 bgx_iface, bgx_index);
308
309 dt_iterate_phy(tree->root, "qlm-mode", path,
310 phy_address, qlm_mode);
311 }
312 }
313
314 /* Set local MAC address */
315 dt_iterate_mac(tree->root);
316
317 return 0;
318}
David Hendricks8cbd5692017-12-01 20:49:48 -0800319
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200320extern u8 _sff8104[];
321extern u8 _esff8104[];
322
323void bootmem_platform_add_ranges(void)
324{
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200325 bootmem_add_range((uintptr_t)_sff8104,
326 ((uintptr_t)_esff8104 - (uintptr_t)_sff8104),
327 BM_MEM_RESERVED);
328
329 /* Scratchpad for ATF SATA quirks */
Patrick Rudolph52acef12018-08-08 12:46:18 +0200330 bootmem_add_range((sdram_size_mb() - 1) * MiB, 1 * MiB,
331 BM_MEM_RESERVED);
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200332}
333
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200334static void soc_read_resources(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800335{
Patrick Rudolpheead8792018-08-10 13:53:04 +0200336 // HACK: Don't advertise bootblock romstage CAR region, it's broken...
337 ram_resource(dev, 0, 2 * KiB, sdram_size_mb() * KiB - 2 * KiB);
David Hendricks8cbd5692017-12-01 20:49:48 -0800338}
339
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200340static void soc_init_atf(void)
341{
342 static struct bl31_fdt_param fdt_param = {
343 .h = { .type = PARAM_FDT, },
344 };
345
346 size_t size = 0;
347
348 void *ptr = cbfs_boot_map_with_leak("sff8104-linux.dtb",
349 CBFS_TYPE_RAW, &size);
350 if (ptr)
351 memcpy(_sff8104, ptr, size);
352 /* Point to devicetree in secure memory */
353 fdt_param.fdt_ptr = (uintptr_t)_sff8104;
354
Julius Wernerb3f24b42019-05-28 21:01:37 -0700355 cn81xx_register_bl31_param(&fdt_param.h);
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200356
357 static struct bl31_u64_param cbtable_param = {
358 .h = { .type = PARAM_COREBOOT_TABLE, },
359 };
360 /* Point to coreboot tables */
361 cbtable_param.value = (uint64_t)cbmem_find(CBMEM_ID_CBTABLE);
362 if (cbtable_param.value)
Julius Wernerb3f24b42019-05-28 21:01:37 -0700363 cn81xx_register_bl31_param(&cbtable_param.h);
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200364}
365
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200366static void soc_init(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800367{
368 /* Init ECAM, MDIO, PEM, PHY, QLM ... */
369 bdk_boot();
370
Julius Wernercd49cce2019-03-05 16:53:33 -0800371 if (CONFIG(PAYLOAD_FIT_SUPPORT)) {
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200372 struct device_tree_fixup *dt_fixup;
373
374 dt_fixup = malloc(sizeof(*dt_fixup));
375 if (dt_fixup) {
376 dt_fixup->fixup = dt_platform_fixup;
377 list_insert_after(&dt_fixup->list_node,
378 &device_tree_fixups);
379 }
380 }
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200381
Julius Wernercd49cce2019-03-05 16:53:33 -0800382 if (CONFIG(ARM64_USE_ARM_TRUSTED_FIRMWARE))
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200383 soc_init_atf();
David Hendricks8cbd5692017-12-01 20:49:48 -0800384}
385
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200386static void soc_final(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800387{
388 watchdog_disable(0);
389}
390
391static struct device_operations soc_ops = {
Patrick Rudolph88f81af2018-04-11 11:40:55 +0200392 .read_resources = soc_read_resources,
393 .set_resources = DEVICE_NOOP,
394 .enable_resources = DEVICE_NOOP,
395 .init = soc_init,
396 .final = soc_final,
David Hendricks8cbd5692017-12-01 20:49:48 -0800397};
398
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200399static void enable_soc_dev(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800400{
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200401 if (dev->path.type == DEVICE_PATH_DOMAIN &&
402 dev->path.domain.domain == 0) {
403 dev->ops = &pci_domain_ops_ecam0;
404 } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
405 dev->ops = &soc_ops;
406 }
David Hendricks8cbd5692017-12-01 20:49:48 -0800407}
408
409struct chip_operations soc_cavium_cn81xx_ops = {
410 CHIP_NAME("SOC Cavium CN81XX")
411 .enable_dev = enable_soc_dev,
412};