blob: 85a9e00e0e571c88eaf56cea89317b38a1cfebb1 [file] [log] [blame]
Angel Pons5f249e62020-04-04 18:51:01 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Angel Pons5f249e62020-04-04 18:51:01 +02002
David Hendricks8cbd5692017-12-01 20:49:48 -08003/*
David Hendricks8cbd5692017-12-01 20:49:48 -08004 * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0.
5 */
6
David Hendricks8cbd5692017-12-01 20:49:48 -08007#include <console/console.h>
David Hendricks8cbd5692017-12-01 20:49:48 -08008#include <device/device.h>
9#include <soc/addressmap.h>
10#include <soc/clock.h>
11#include <soc/sdram.h>
12#include <soc/timer.h>
Jens Drenhausfe66a072018-10-09 13:02:49 +020013#include <soc/uart.h>
David Hendricks8cbd5692017-12-01 20:49:48 -080014#include <stddef.h>
15#include <stdlib.h>
16#include <string.h>
17#include <symbols.h>
18#include <libbdk-boot/bdk-boot.h>
Patrick Rudolphd0c67972018-04-17 13:47:55 +020019#include <soc/ecam0.h>
Patrick Rudolphde4410c2018-03-27 12:01:40 +020020#include <console/uart.h>
21#include <libbdk-hal/bdk-pcie.h>
Patrick Rudolphde4410c2018-03-27 12:01:40 +020022#include <device/pci.h>
23#include <libbdk-hal/bdk-qlm.h>
24#include <libbdk-hal/bdk-config.h>
25#include <libbdk-arch/bdk-csrs-bgx.h>
Patrick Rudolph5cdaa332018-04-20 14:43:21 +020026#include <bootmem.h>
27#include <soc/bl31_plat_params.h>
28#include <cbfs.h>
29#include <cbmem.h>
Patrick Rudolphde4410c2018-03-27 12:01:40 +020030#include <fit.h>
31
32static const char *QLM_BGX_MODE_MAP[BDK_QLM_MODE_LAST] = {
33 [BDK_QLM_MODE_SGMII_4X1] = "sgmii",
34 [BDK_QLM_MODE_SGMII_2X1] = "sgmii",
35 [BDK_QLM_MODE_SGMII_1X1] = "sgmii",
36 [BDK_QLM_MODE_XAUI_1X4] = "xaui",
37 [BDK_QLM_MODE_RXAUI_2X2] = "rxaui",
38 [BDK_QLM_MODE_RXAUI_1X2] = "rxaui",
39 [BDK_QLM_MODE_XFI_4X1] = "xfi",
40 [BDK_QLM_MODE_XFI_2X1] = "xfi",
41 [BDK_QLM_MODE_XFI_1X1] = "xfi",
42 [BDK_QLM_MODE_XLAUI_1X4] = "xlaui",
43 [BDK_QLM_MODE_10G_KR_4X1] = "xfi-10g-kr",
44 [BDK_QLM_MODE_10G_KR_2X1] = "xfi-10g-kr",
45 [BDK_QLM_MODE_10G_KR_1X1] = "xfi-10g-kr",
46 [BDK_QLM_MODE_40G_KR4_1X4] = "xlaui-40g-kr",
47 [BDK_QLM_MODE_QSGMII_4X1] = "qsgmii",
48};
49
50static void dt_platform_fixup_phy(struct device_tree_node *node, char *path,
51 int64_t phy_address, bdk_qlm_modes_t qlm_mode)
52{
Patrick Rudolph0a7d6902018-08-22 09:55:15 +020053 const char *data = NULL;
Patrick Rudolphde4410c2018-03-27 12:01:40 +020054 size_t size = 0;
Patrick Rudolph0a7d6902018-08-22 09:55:15 +020055 dt_find_bin_prop(node, "qlm-mode", (const void **)&data, &size);
Patrick Rudolphde4410c2018-03-27 12:01:40 +020056
57 if (!data || strncmp(data, path, 6) != 0)
58 return; /* No key prefix match. */
59 printk(BIOS_INFO, "%s: Node %s = %s\n", __func__, node->name, data);
60
61 if (strlen(path) == strlen(data) && strcmp(data, path) == 0) {
62 /* Keep node, remove "qlm-mode" property */
63 dt_delete_prop(node, "qlm-mode");
64 printk(BIOS_INFO, "%s: Removing qlm-mode on "
65 "node %s\n", __func__, node->name);
66 /* Linux only access the Phy via MDIO.
67 Remove 'phy-handle' if this option is not available */
68 switch (qlm_mode) {
69 case BDK_QLM_MODE_SGMII_4X1:
70 case BDK_QLM_MODE_SGMII_2X1:
71 case BDK_QLM_MODE_SGMII_1X1:
72 case BDK_QLM_MODE_QSGMII_4X1:
73 if ((phy_address & BDK_IF_PHY_TYPE_MASK) !=
74 BDK_IF_PHY_MDIO) {
75 dt_delete_prop(node, "phy-handle");
76 printk(BIOS_INFO, "%s: Removing phy-handle on "
77 "node %s\n", __func__, node->name);
78 }
79 break;
80 default:
81 break;
82 }
83 } else {
84 printk(BIOS_INFO, "%s: Removing node %s\n", __func__,
85 node->name);
86 /* No match, remove node */
87 list_remove(&node->list_node);
88 }
89}
90
91static void dt_iterate_phy(struct device_tree_node *parent,
92 const char *name,
93 char *path,
94 int64_t phy_address,
95 bdk_qlm_modes_t qlm_mode)
96{
97 struct device_tree_property *prop;
98
99 /* Check if parent itself has the required property value. */
100 list_for_each(prop, parent->properties, list_node) {
101 if (!strcmp(name, prop->prop.name)) {
102 dt_platform_fixup_phy(parent, path, phy_address,
103 qlm_mode);
104 }
105 }
106
107 struct device_tree_node *child;
108 list_for_each(child, parent->children, list_node) {
109 dt_iterate_phy(child, name, path, phy_address, qlm_mode);
110 }
111}
112
113static void dt_platform_fixup_mac(struct device_tree_node *node)
114{
115 const char *name = "local-mac-address";
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200116 const u64 *localmac = NULL;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200117 size_t size = 0;
118
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200119 dt_find_bin_prop(node, name, (const void **)&localmac, &size);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200120
121 if (!localmac)
122 return;
123 static size_t used_mac;
124
125 /* Extract our MAC address info so we can assign them */
126 size_t next_free_mac_address =
127 bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS);
128 size_t num_free_mac_addresses =
129 bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS_NUM);
130 size_t num_free_override =
131 bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS_NUM_OVERRIDE);
132 if (num_free_override != -1)
133 num_free_mac_addresses = num_free_override;
134
135 if (size == 6) {
136 if (*localmac)
137 return;
138 if (used_mac < num_free_mac_addresses) {
Julius Werner0e9116f2019-05-13 17:30:31 -0700139 u64 genmac = next_free_mac_address + used_mac;
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200140 dt_add_bin_prop(node, name, &genmac, 6);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200141 used_mac++;
142 return;
143 }
144 }
145
146 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, node->name);
147 list_remove(&node->list_node);
148}
149
150static void dt_iterate_mac(struct device_tree_node *parent)
151{
152 struct device_tree_property *prop;
153 const char *name = "local-mac-address";
154
155 /* Check if parent itself has the required property value. */
156 list_for_each(prop, parent->properties, list_node) {
157 if (!strcmp(name, prop->prop.name))
158 dt_platform_fixup_mac(parent);
159 }
160
161 struct device_tree_node *child;
162 list_for_each(child, parent->children, list_node) {
163 dt_iterate_mac(child);
164 }
165}
166
167/* Do additional device_tree modifications. */
168static int dt_platform_fixup(struct device_tree_fixup *fixup,
169 struct device_tree *tree)
170{
171 struct device_tree_node *dt_node;
172 size_t i;
173
174 /* Set the sclk clock rate. */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700175 dt_node = dt_find_node_by_path(tree, "/soc@0/sclk", NULL, NULL, 0);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200176 if (dt_node) {
177 const u32 freq = thunderx_get_io_clock();
178 printk(BIOS_INFO, "%s: Set SCLK to %u Hz\n", __func__, freq);
179 dt_add_u32_prop(dt_node, "clock-frequency", freq);
180 } else
181 printk(BIOS_ERR, "%s: Node not found. OS might miss-behave !\n",
182 __func__);
183
184 /* Set refclkuaa clock rate. */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700185 dt_node = dt_find_node_by_path(tree, "/soc@0/refclkuaa", NULL,
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200186 NULL, 0);
187 if (dt_node) {
188 const u32 freq = uart_platform_refclk();
189 printk(BIOS_INFO, "%s: Set REFCLKUAA to %u Hz\n", __func__,
190 freq);
191 dt_add_u32_prop(dt_node, "clock-frequency", freq);
192 } else
193 printk(BIOS_ERR, "%s: Node not found. OS might miss-behave !\n",
194 __func__);
195
Jens Drenhausfe66a072018-10-09 13:02:49 +0200196 /* Remove unused UART entries */
197 for (i = 0; i < 4; i++) {
198 char path[32];
199 const uint64_t addr = UAAx_PF_BAR0(i);
200 /* Remove the node */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700201 snprintf(path, sizeof(path), "/soc@0/serial@%llx", addr);
Julius Wernerf36d53c2019-05-03 18:23:34 -0700202 dt_node = dt_find_node_by_path(tree, path, NULL, NULL, 0);
Jens Drenhausfe66a072018-10-09 13:02:49 +0200203 if (!dt_node || uart_is_enabled(i)) {
204 printk(BIOS_INFO, "%s: ignoring %s\n", __func__, path);
205 continue;
206 }
207 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, path);
208 list_remove(&dt_node->list_node);
209 }
210
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200211 /* Remove unused PEM entries */
212 for (i = 0; i < 8; i++) {
213 char path[32];
214 u32 phandle = 0;
215 const uint64_t addr = PEM_PEMX_PF_BAR0(i);
216 /* Remove the node */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700217 snprintf(path, sizeof(path), "/soc@0/pci@%llx", addr);
Julius Wernerf36d53c2019-05-03 18:23:34 -0700218 dt_node = dt_find_node_by_path(tree, path, NULL, NULL, 0);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200219 if (!dt_node || bdk_pcie_is_running(0, i)) {
220 printk(BIOS_INFO, "%s: ignoring %s\n", __func__, path);
221 continue;
222 }
223 /* Store the phandle */
Julius Werner6702b682019-05-03 18:13:53 -0700224 phandle = dt_node->phandle;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200225 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, path);
226 list_remove(&dt_node->list_node);
227
228 /* Remove phandle to non existing nodes */
Julius Wernerfbec63d2019-05-03 18:29:28 -0700229 snprintf(path, sizeof(path), "/soc@0/smmu0@%llx", SMMU_PF_BAR0);
Julius Wernerf36d53c2019-05-03 18:23:34 -0700230 dt_node = dt_find_node_by_path(tree, path, NULL, NULL, 0);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200231 if (!dt_node) {
232 printk(BIOS_ERR, "%s: SMMU entry not found\n",
233 __func__);
234 continue;
235 }
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200236 const u32 *data = NULL;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200237 size_t size = 0;
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200238 dt_find_bin_prop(dt_node, "mmu-masters", (const void **)&data,
239 &size);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200240 if (!size) {
241 printk(BIOS_ERR, "%s: mmu-masters entry not found\n",
242 __func__);
243 continue;
244 }
Patrick Rudolph70866e92018-08-22 09:52:42 +0200245
246 u32 *data_cleaned = malloc(size);
247 if (!data_cleaned)
248 continue;
249
250 size_t n = 0;
251 /* Remove phandle from mmu-masters list */
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200252 for (size_t j = 0; j < size / (sizeof(u32) * 2); j++)
Patrick Rudolph70866e92018-08-22 09:52:42 +0200253 if (be32_to_cpu(data[j * 2]) != phandle) {
254 data_cleaned[n * 2] = data[j * 2];
255 data_cleaned[n * 2 + 1] = data[j * 2 + 1];
256 n++;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200257 }
Patrick Rudolph70866e92018-08-22 09:52:42 +0200258
259 dt_add_bin_prop(dt_node, "mmu-masters", data_cleaned,
260 n * sizeof(u32) * 2);
261
262 free(data_cleaned);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200263 }
264
265 /* Remove QLM mode entries */
266 size_t bgx_index, bgx_iface;
267 for (bgx_iface = 0; bgx_iface < 4; bgx_iface++) {
268 for (bgx_index = 0; bgx_index < 4; bgx_index++) {
269 char path[32];
270 int qlm = bdk_qlm_get_qlm_num(0, BDK_IF_BGX,
271 bgx_iface, bgx_index);
272 bdk_qlm_modes_t qlm_mode = (qlm == -1) ?
273 BDK_QLM_MODE_DISABLED :
274 bdk_qlm_get_mode(0, qlm);
275
276 /* BGXX_CMRX_RX_DMAC_CTL is used to mark ports as
277 * disabled that would otherwise be enabled */
278 if (qlm_mode != BDK_QLM_MODE_DISABLED) {
279 BDK_CSR_INIT(rx_dmac_ctl, 0,
280 BDK_BGXX_CMRX_RX_DMAC_CTL(bgx_iface,
281 bgx_index));
282 if (rx_dmac_ctl.u == 0)
283 qlm_mode = BDK_QLM_MODE_DISABLED;
284 }
285
286 if (qlm_mode == BDK_QLM_MODE_DISABLED)
287 snprintf(path, sizeof(path), "0x0%x%x,disabled",
288 bgx_iface, bgx_index);
289 else
290 snprintf(path, sizeof(path), "0x0%x%x,%s",
291 bgx_iface, bgx_index,
292 QLM_BGX_MODE_MAP[qlm_mode]);
293
294 int64_t phy_address =
295 bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, 0,
296 bgx_iface, bgx_index);
297
298 dt_iterate_phy(tree->root, "qlm-mode", path,
299 phy_address, qlm_mode);
300 }
301 }
302
303 /* Set local MAC address */
304 dt_iterate_mac(tree->root);
305
306 return 0;
307}
David Hendricks8cbd5692017-12-01 20:49:48 -0800308
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200309extern u8 _sff8104[];
310extern u8 _esff8104[];
311
312void bootmem_platform_add_ranges(void)
313{
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200314 bootmem_add_range((uintptr_t)_sff8104,
315 ((uintptr_t)_esff8104 - (uintptr_t)_sff8104),
316 BM_MEM_RESERVED);
317
318 /* Scratchpad for ATF SATA quirks */
Patrick Rudolph52acef12018-08-08 12:46:18 +0200319 bootmem_add_range((sdram_size_mb() - 1) * MiB, 1 * MiB,
320 BM_MEM_RESERVED);
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200321}
322
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200323static void soc_read_resources(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800324{
Patrick Rudolpheead8792018-08-10 13:53:04 +0200325 // HACK: Don't advertise bootblock romstage CAR region, it's broken...
Kyösti Mälkki27d62992022-05-24 20:25:58 +0300326 ram_resource_kb(dev, 0, 2 * KiB, sdram_size_mb() * KiB - 2 * KiB);
David Hendricks8cbd5692017-12-01 20:49:48 -0800327}
328
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200329static void soc_init_atf(void)
330{
331 static struct bl31_fdt_param fdt_param = {
332 .h = { .type = PARAM_FDT, },
333 };
334
335 size_t size = 0;
336
Julius Werner834b3ec2020-03-04 16:52:08 -0800337 void *ptr = cbfs_map("sff8104-linux.dtb", &size);
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200338 if (ptr)
339 memcpy(_sff8104, ptr, size);
340 /* Point to devicetree in secure memory */
341 fdt_param.fdt_ptr = (uintptr_t)_sff8104;
342
Julius Wernerb3f24b42019-05-28 21:01:37 -0700343 cn81xx_register_bl31_param(&fdt_param.h);
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200344
345 static struct bl31_u64_param cbtable_param = {
346 .h = { .type = PARAM_COREBOOT_TABLE, },
347 };
348 /* Point to coreboot tables */
349 cbtable_param.value = (uint64_t)cbmem_find(CBMEM_ID_CBTABLE);
350 if (cbtable_param.value)
Julius Wernerb3f24b42019-05-28 21:01:37 -0700351 cn81xx_register_bl31_param(&cbtable_param.h);
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200352}
353
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200354static void soc_init(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800355{
356 /* Init ECAM, MDIO, PEM, PHY, QLM ... */
357 bdk_boot();
358
Julius Wernercd49cce2019-03-05 16:53:33 -0800359 if (CONFIG(PAYLOAD_FIT_SUPPORT)) {
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200360 struct device_tree_fixup *dt_fixup;
361
362 dt_fixup = malloc(sizeof(*dt_fixup));
363 if (dt_fixup) {
364 dt_fixup->fixup = dt_platform_fixup;
365 list_insert_after(&dt_fixup->list_node,
366 &device_tree_fixups);
367 }
368 }
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200369
Julius Wernercd49cce2019-03-05 16:53:33 -0800370 if (CONFIG(ARM64_USE_ARM_TRUSTED_FIRMWARE))
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200371 soc_init_atf();
David Hendricks8cbd5692017-12-01 20:49:48 -0800372}
373
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200374static void soc_final(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800375{
376 watchdog_disable(0);
377}
378
379static struct device_operations soc_ops = {
Patrick Rudolph88f81af2018-04-11 11:40:55 +0200380 .read_resources = soc_read_resources,
Nico Huber2f8ba692020-04-05 14:05:24 +0200381 .set_resources = noop_set_resources,
Patrick Rudolph88f81af2018-04-11 11:40:55 +0200382 .init = soc_init,
383 .final = soc_final,
David Hendricks8cbd5692017-12-01 20:49:48 -0800384};
385
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200386static void enable_soc_dev(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800387{
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200388 if (dev->path.type == DEVICE_PATH_DOMAIN &&
389 dev->path.domain.domain == 0) {
390 dev->ops = &pci_domain_ops_ecam0;
391 } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
392 dev->ops = &soc_ops;
393 }
David Hendricks8cbd5692017-12-01 20:49:48 -0800394}
395
396struct chip_operations soc_cavium_cn81xx_ops = {
397 CHIP_NAME("SOC Cavium CN81XX")
398 .enable_dev = enable_soc_dev,
399};