blob: 0bf76f7424c79fa85897bd8984308f755ddf4c44 [file] [log] [blame]
David Hendricks8cbd5692017-12-01 20:49:48 -08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2018 Facebook, Inc.
5 * Copyright 2003-2017 Cavium Inc. <support@cavium.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0.
17 */
18
19#include <bootmode.h>
20#include <console/console.h>
21#include <cpu/cpu.h>
22#include <device/device.h>
23#include <soc/addressmap.h>
24#include <soc/clock.h>
25#include <soc/sdram.h>
26#include <soc/timer.h>
Jens Drenhausfe66a072018-10-09 13:02:49 +020027#include <soc/uart.h>
David Hendricks8cbd5692017-12-01 20:49:48 -080028#include <stddef.h>
29#include <stdlib.h>
30#include <string.h>
31#include <symbols.h>
32#include <libbdk-boot/bdk-boot.h>
Patrick Rudolphd0c67972018-04-17 13:47:55 +020033#include <soc/ecam0.h>
Patrick Rudolphde4410c2018-03-27 12:01:40 +020034#include <console/uart.h>
35#include <libbdk-hal/bdk-pcie.h>
36#include <soc/ecam0.h>
37#include <device/pci.h>
38#include <libbdk-hal/bdk-qlm.h>
39#include <libbdk-hal/bdk-config.h>
40#include <libbdk-arch/bdk-csrs-bgx.h>
Patrick Rudolph5cdaa332018-04-20 14:43:21 +020041#include <bootmem.h>
42#include <soc/bl31_plat_params.h>
43#include <cbfs.h>
44#include <cbmem.h>
Patrick Rudolphde4410c2018-03-27 12:01:40 +020045#include <fit.h>
46
47static const char *QLM_BGX_MODE_MAP[BDK_QLM_MODE_LAST] = {
48 [BDK_QLM_MODE_SGMII_4X1] = "sgmii",
49 [BDK_QLM_MODE_SGMII_2X1] = "sgmii",
50 [BDK_QLM_MODE_SGMII_1X1] = "sgmii",
51 [BDK_QLM_MODE_XAUI_1X4] = "xaui",
52 [BDK_QLM_MODE_RXAUI_2X2] = "rxaui",
53 [BDK_QLM_MODE_RXAUI_1X2] = "rxaui",
54 [BDK_QLM_MODE_XFI_4X1] = "xfi",
55 [BDK_QLM_MODE_XFI_2X1] = "xfi",
56 [BDK_QLM_MODE_XFI_1X1] = "xfi",
57 [BDK_QLM_MODE_XLAUI_1X4] = "xlaui",
58 [BDK_QLM_MODE_10G_KR_4X1] = "xfi-10g-kr",
59 [BDK_QLM_MODE_10G_KR_2X1] = "xfi-10g-kr",
60 [BDK_QLM_MODE_10G_KR_1X1] = "xfi-10g-kr",
61 [BDK_QLM_MODE_40G_KR4_1X4] = "xlaui-40g-kr",
62 [BDK_QLM_MODE_QSGMII_4X1] = "qsgmii",
63};
64
65static void dt_platform_fixup_phy(struct device_tree_node *node, char *path,
66 int64_t phy_address, bdk_qlm_modes_t qlm_mode)
67{
Patrick Rudolph0a7d6902018-08-22 09:55:15 +020068 const char *data = NULL;
Patrick Rudolphde4410c2018-03-27 12:01:40 +020069 size_t size = 0;
Patrick Rudolph0a7d6902018-08-22 09:55:15 +020070 dt_find_bin_prop(node, "qlm-mode", (const void **)&data, &size);
Patrick Rudolphde4410c2018-03-27 12:01:40 +020071
72 if (!data || strncmp(data, path, 6) != 0)
73 return; /* No key prefix match. */
74 printk(BIOS_INFO, "%s: Node %s = %s\n", __func__, node->name, data);
75
76 if (strlen(path) == strlen(data) && strcmp(data, path) == 0) {
77 /* Keep node, remove "qlm-mode" property */
78 dt_delete_prop(node, "qlm-mode");
79 printk(BIOS_INFO, "%s: Removing qlm-mode on "
80 "node %s\n", __func__, node->name);
81 /* Linux only access the Phy via MDIO.
82 Remove 'phy-handle' if this option is not available */
83 switch (qlm_mode) {
84 case BDK_QLM_MODE_SGMII_4X1:
85 case BDK_QLM_MODE_SGMII_2X1:
86 case BDK_QLM_MODE_SGMII_1X1:
87 case BDK_QLM_MODE_QSGMII_4X1:
88 if ((phy_address & BDK_IF_PHY_TYPE_MASK) !=
89 BDK_IF_PHY_MDIO) {
90 dt_delete_prop(node, "phy-handle");
91 printk(BIOS_INFO, "%s: Removing phy-handle on "
92 "node %s\n", __func__, node->name);
93 }
94 break;
95 default:
96 break;
97 }
98 } else {
99 printk(BIOS_INFO, "%s: Removing node %s\n", __func__,
100 node->name);
101 /* No match, remove node */
102 list_remove(&node->list_node);
103 }
104}
105
106static void dt_iterate_phy(struct device_tree_node *parent,
107 const char *name,
108 char *path,
109 int64_t phy_address,
110 bdk_qlm_modes_t qlm_mode)
111{
112 struct device_tree_property *prop;
113
114 /* Check if parent itself has the required property value. */
115 list_for_each(prop, parent->properties, list_node) {
116 if (!strcmp(name, prop->prop.name)) {
117 dt_platform_fixup_phy(parent, path, phy_address,
118 qlm_mode);
119 }
120 }
121
122 struct device_tree_node *child;
123 list_for_each(child, parent->children, list_node) {
124 dt_iterate_phy(child, name, path, phy_address, qlm_mode);
125 }
126}
127
128static void dt_platform_fixup_mac(struct device_tree_node *node)
129{
130 const char *name = "local-mac-address";
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200131 const u64 *localmac = NULL;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200132 size_t size = 0;
133
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200134 dt_find_bin_prop(node, name, (const void **)&localmac, &size);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200135
136 if (!localmac)
137 return;
138 static size_t used_mac;
139
140 /* Extract our MAC address info so we can assign them */
141 size_t next_free_mac_address =
142 bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS);
143 size_t num_free_mac_addresses =
144 bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS_NUM);
145 size_t num_free_override =
146 bdk_config_get_int(BDK_CONFIG_MAC_ADDRESS_NUM_OVERRIDE);
147 if (num_free_override != -1)
148 num_free_mac_addresses = num_free_override;
149
150 if (size == 6) {
151 if (*localmac)
152 return;
153 if (used_mac < num_free_mac_addresses) {
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200154 const u64 genmac = next_free_mac_address + used_mac;
155 dt_add_bin_prop(node, name, &genmac, 6);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200156 used_mac++;
157 return;
158 }
159 }
160
161 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, node->name);
162 list_remove(&node->list_node);
163}
164
165static void dt_iterate_mac(struct device_tree_node *parent)
166{
167 struct device_tree_property *prop;
168 const char *name = "local-mac-address";
169
170 /* Check if parent itself has the required property value. */
171 list_for_each(prop, parent->properties, list_node) {
172 if (!strcmp(name, prop->prop.name))
173 dt_platform_fixup_mac(parent);
174 }
175
176 struct device_tree_node *child;
177 list_for_each(child, parent->children, list_node) {
178 dt_iterate_mac(child);
179 }
180}
181
182/* Do additional device_tree modifications. */
183static int dt_platform_fixup(struct device_tree_fixup *fixup,
184 struct device_tree *tree)
185{
186 struct device_tree_node *dt_node;
187 size_t i;
188
189 /* Set the sclk clock rate. */
190 dt_node = dt_find_node_by_path(tree->root, "soc@0/sclk", NULL, NULL, 0);
191 if (dt_node) {
192 const u32 freq = thunderx_get_io_clock();
193 printk(BIOS_INFO, "%s: Set SCLK to %u Hz\n", __func__, freq);
194 dt_add_u32_prop(dt_node, "clock-frequency", freq);
195 } else
196 printk(BIOS_ERR, "%s: Node not found. OS might miss-behave !\n",
197 __func__);
198
199 /* Set refclkuaa clock rate. */
200 dt_node = dt_find_node_by_path(tree->root, "soc@0/refclkuaa", NULL,
201 NULL, 0);
202 if (dt_node) {
203 const u32 freq = uart_platform_refclk();
204 printk(BIOS_INFO, "%s: Set REFCLKUAA to %u Hz\n", __func__,
205 freq);
206 dt_add_u32_prop(dt_node, "clock-frequency", freq);
207 } else
208 printk(BIOS_ERR, "%s: Node not found. OS might miss-behave !\n",
209 __func__);
210
Jens Drenhausfe66a072018-10-09 13:02:49 +0200211 /* Remove unused UART entries */
212 for (i = 0; i < 4; i++) {
213 char path[32];
214 const uint64_t addr = UAAx_PF_BAR0(i);
215 /* Remove the node */
216 snprintf(path, sizeof(path), "soc@0/serial@%llx", addr);
217 dt_node = dt_find_node_by_path(tree->root, path, NULL, NULL, 0);
218 if (!dt_node || uart_is_enabled(i)) {
219 printk(BIOS_INFO, "%s: ignoring %s\n", __func__, path);
220 continue;
221 }
222 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, path);
223 list_remove(&dt_node->list_node);
224 }
225
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200226 /* Remove unused PEM entries */
227 for (i = 0; i < 8; i++) {
228 char path[32];
229 u32 phandle = 0;
230 const uint64_t addr = PEM_PEMX_PF_BAR0(i);
231 /* Remove the node */
232 snprintf(path, sizeof(path), "soc@0/pci@%llx", addr);
233 dt_node = dt_find_node_by_path(tree->root, path, NULL, NULL, 0);
234 if (!dt_node || bdk_pcie_is_running(0, i)) {
235 printk(BIOS_INFO, "%s: ignoring %s\n", __func__, path);
236 continue;
237 }
238 /* Store the phandle */
239 phandle = dt_get_phandle(dt_node);
240 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, path);
241 list_remove(&dt_node->list_node);
242
243 /* Remove phandle to non existing nodes */
244 snprintf(path, sizeof(path), "soc@0/smmu0@%llx", SMMU_PF_BAR0);
245 dt_node = dt_find_node_by_path(tree->root, path, NULL, NULL, 0);
246 if (!dt_node) {
247 printk(BIOS_ERR, "%s: SMMU entry not found\n",
248 __func__);
249 continue;
250 }
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200251 const u32 *data = NULL;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200252 size_t size = 0;
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200253 dt_find_bin_prop(dt_node, "mmu-masters", (const void **)&data,
254 &size);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200255 if (!size) {
256 printk(BIOS_ERR, "%s: mmu-masters entry not found\n",
257 __func__);
258 continue;
259 }
Patrick Rudolph70866e92018-08-22 09:52:42 +0200260
261 u32 *data_cleaned = malloc(size);
262 if (!data_cleaned)
263 continue;
264
265 size_t n = 0;
266 /* Remove phandle from mmu-masters list */
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200267 for (size_t j = 0; j < size / (sizeof(u32) * 2); j++)
Patrick Rudolph70866e92018-08-22 09:52:42 +0200268 if (be32_to_cpu(data[j * 2]) != phandle) {
269 data_cleaned[n * 2] = data[j * 2];
270 data_cleaned[n * 2 + 1] = data[j * 2 + 1];
271 n++;
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200272 }
Patrick Rudolph70866e92018-08-22 09:52:42 +0200273
274 dt_add_bin_prop(dt_node, "mmu-masters", data_cleaned,
275 n * sizeof(u32) * 2);
276
277 free(data_cleaned);
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200278 }
279
280 /* Remove QLM mode entries */
281 size_t bgx_index, bgx_iface;
282 for (bgx_iface = 0; bgx_iface < 4; bgx_iface++) {
283 for (bgx_index = 0; bgx_index < 4; bgx_index++) {
284 char path[32];
285 int qlm = bdk_qlm_get_qlm_num(0, BDK_IF_BGX,
286 bgx_iface, bgx_index);
287 bdk_qlm_modes_t qlm_mode = (qlm == -1) ?
288 BDK_QLM_MODE_DISABLED :
289 bdk_qlm_get_mode(0, qlm);
290
291 /* BGXX_CMRX_RX_DMAC_CTL is used to mark ports as
292 * disabled that would otherwise be enabled */
293 if (qlm_mode != BDK_QLM_MODE_DISABLED) {
294 BDK_CSR_INIT(rx_dmac_ctl, 0,
295 BDK_BGXX_CMRX_RX_DMAC_CTL(bgx_iface,
296 bgx_index));
297 if (rx_dmac_ctl.u == 0)
298 qlm_mode = BDK_QLM_MODE_DISABLED;
299 }
300
301 if (qlm_mode == BDK_QLM_MODE_DISABLED)
302 snprintf(path, sizeof(path), "0x0%x%x,disabled",
303 bgx_iface, bgx_index);
304 else
305 snprintf(path, sizeof(path), "0x0%x%x,%s",
306 bgx_iface, bgx_index,
307 QLM_BGX_MODE_MAP[qlm_mode]);
308
309 int64_t phy_address =
310 bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, 0,
311 bgx_iface, bgx_index);
312
313 dt_iterate_phy(tree->root, "qlm-mode", path,
314 phy_address, qlm_mode);
315 }
316 }
317
318 /* Set local MAC address */
319 dt_iterate_mac(tree->root);
320
321 return 0;
322}
David Hendricks8cbd5692017-12-01 20:49:48 -0800323
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200324extern u8 _bl31[];
325extern u8 _ebl31[];
326extern u8 _sff8104[];
327extern u8 _esff8104[];
328
329void bootmem_platform_add_ranges(void)
330{
331 /* ATF reserved */
332 bootmem_add_range((uintptr_t)_bl31,
333 ((uintptr_t)_ebl31 - (uintptr_t)_bl31),
334 BM_MEM_RESERVED);
335
336 bootmem_add_range((uintptr_t)_sff8104,
337 ((uintptr_t)_esff8104 - (uintptr_t)_sff8104),
338 BM_MEM_RESERVED);
339
340 /* Scratchpad for ATF SATA quirks */
Patrick Rudolph52acef12018-08-08 12:46:18 +0200341 bootmem_add_range((sdram_size_mb() - 1) * MiB, 1 * MiB,
342 BM_MEM_RESERVED);
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200343}
344
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200345static void soc_read_resources(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800346{
Patrick Rudolpheead8792018-08-10 13:53:04 +0200347 // HACK: Don't advertise bootblock romstage CAR region, it's broken...
348 ram_resource(dev, 0, 2 * KiB, sdram_size_mb() * KiB - 2 * KiB);
David Hendricks8cbd5692017-12-01 20:49:48 -0800349}
350
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200351static void soc_init_atf(void)
352{
353 static struct bl31_fdt_param fdt_param = {
354 .h = { .type = PARAM_FDT, },
355 };
356
357 size_t size = 0;
358
359 void *ptr = cbfs_boot_map_with_leak("sff8104-linux.dtb",
360 CBFS_TYPE_RAW, &size);
361 if (ptr)
362 memcpy(_sff8104, ptr, size);
363 /* Point to devicetree in secure memory */
364 fdt_param.fdt_ptr = (uintptr_t)_sff8104;
365
366 register_bl31_param(&fdt_param.h);
367
368 static struct bl31_u64_param cbtable_param = {
369 .h = { .type = PARAM_COREBOOT_TABLE, },
370 };
371 /* Point to coreboot tables */
372 cbtable_param.value = (uint64_t)cbmem_find(CBMEM_ID_CBTABLE);
373 if (cbtable_param.value)
374 register_bl31_param(&cbtable_param.h);
375}
376
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200377static void soc_init(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800378{
379 /* Init ECAM, MDIO, PEM, PHY, QLM ... */
380 bdk_boot();
381
Patrick Rudolphde4410c2018-03-27 12:01:40 +0200382 if (IS_ENABLED(CONFIG_PAYLOAD_FIT_SUPPORT)) {
383 struct device_tree_fixup *dt_fixup;
384
385 dt_fixup = malloc(sizeof(*dt_fixup));
386 if (dt_fixup) {
387 dt_fixup->fixup = dt_platform_fixup;
388 list_insert_after(&dt_fixup->list_node,
389 &device_tree_fixups);
390 }
391 }
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200392
Jens Drenhausfe66a072018-10-09 13:02:49 +0200393 /* Init UARTs */
394 size_t i;
395 struct device *uart_dev;
396 for (i = 0; i <= 3; i++) {
397 uart_dev = dev_find_slot(1, PCI_DEVFN(8, i));
398 /* using device enable state from devicetree.cb */
399 if (uart_dev && uart_dev->enabled) {
400 if (!uart_is_enabled(i))
401 uart_setup(i, 0);
402 }
403 }
404
Patrick Rudolph5cdaa332018-04-20 14:43:21 +0200405 if (IS_ENABLED(CONFIG_ARM64_USE_ARM_TRUSTED_FIRMWARE))
406 soc_init_atf();
David Hendricks8cbd5692017-12-01 20:49:48 -0800407}
408
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200409static void soc_final(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800410{
411 watchdog_disable(0);
412}
413
414static struct device_operations soc_ops = {
Patrick Rudolph88f81af2018-04-11 11:40:55 +0200415 .read_resources = soc_read_resources,
416 .set_resources = DEVICE_NOOP,
417 .enable_resources = DEVICE_NOOP,
418 .init = soc_init,
419 .final = soc_final,
420 .scan_bus = NULL,
David Hendricks8cbd5692017-12-01 20:49:48 -0800421};
422
Elyes HAOUAS27667a22018-09-16 17:40:40 +0200423static void enable_soc_dev(struct device *dev)
David Hendricks8cbd5692017-12-01 20:49:48 -0800424{
Patrick Rudolphd0c67972018-04-17 13:47:55 +0200425 if (dev->path.type == DEVICE_PATH_DOMAIN &&
426 dev->path.domain.domain == 0) {
427 dev->ops = &pci_domain_ops_ecam0;
428 } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
429 dev->ops = &soc_ops;
430 }
David Hendricks8cbd5692017-12-01 20:49:48 -0800431}
432
433struct chip_operations soc_cavium_cn81xx_ops = {
434 CHIP_NAME("SOC Cavium CN81XX")
435 .enable_dev = enable_soc_dev,
436};