mb/google/nissa/var/rull: Add 6W and 15W DPTF parameters
[coreboot.git] / src / soc / cavium / cn81xx / soc.c
blobe0caea6cd7940c99092602c837d2af4941d27b6d
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 /*
4 * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0.
5 */
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>
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",
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)
54 const char *data = NULL;
55 size_t size = 0;
56 dt_find_bin_prop(node, "qlm-mode", (const void **)&data, &size);
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);
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);
80 break;
81 default:
82 break;
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);
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)
98 struct device_tree_property *prop;
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);
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);
114 static void dt_platform_fixup_mac(struct device_tree_node *node)
116 const char *name = "local-mac-address";
117 const u64 *localmac = NULL;
118 size_t size = 0;
120 dt_find_bin_prop(node, name, (const void **)&localmac, &size);
122 if (!localmac)
123 return;
124 static size_t used_mac;
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;
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;
147 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, node->name);
148 list_remove(&node->list_node);
151 static void dt_iterate_mac(struct device_tree_node *parent)
153 struct device_tree_property *prop;
154 const char *name = "local-mac-address";
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);
162 struct device_tree_node *child;
163 list_for_each(child, parent->children, list_node) {
164 dt_iterate_mac(child);
168 /* Do additional device_tree modifications. */
169 static int dt_platform_fixup(struct device_tree_fixup *fixup,
170 struct device_tree *tree)
172 struct device_tree_node *dt_node;
173 size_t i;
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__);
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__);
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;
208 printk(BIOS_INFO, "%s: Removing node %s\n", __func__, path);
209 list_remove(&dt_node->list_node);
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;
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);
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;
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;
247 u32 *data_cleaned = malloc(size);
248 if (!data_cleaned)
249 continue;
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++;
260 dt_add_bin_prop(dt_node, "mmu-masters", data_cleaned,
261 n * sizeof(u32) * 2);
263 free(data_cleaned);
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);
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;
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]);
295 int64_t phy_address =
296 bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, 0,
297 bgx_iface, bgx_index);
299 dt_iterate_phy(tree->root, "qlm-mode", path,
300 phy_address, qlm_mode);
304 /* Set local MAC address */
305 dt_iterate_mac(tree->root);
307 return 0;
310 extern u8 _sff8104[];
311 extern u8 _esff8104[];
313 void bootmem_platform_add_ranges(void)
315 bootmem_add_range((uintptr_t)_sff8104,
316 ((uintptr_t)_esff8104 - (uintptr_t)_sff8104),
317 BM_MEM_RESERVED);
319 /* Scratchpad for ATF SATA quirks */
320 bootmem_add_range((sdram_size_mb() - 1) * MiB, 1 * MiB,
321 BM_MEM_RESERVED);
324 static void soc_read_resources(struct device *dev)
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);
330 static void soc_init_atf(void)
332 static struct bl31_fdt_param fdt_param = {
333 .h = { .type = PARAM_FDT, },
336 size_t size = 0;
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;
344 cn81xx_register_bl31_param(&fdt_param.h);
346 static struct bl31_u64_param cbtable_param = {
347 .h = { .type = PARAM_COREBOOT_TABLE, },
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);
355 static void soc_init(struct device *dev)
357 /* Init ECAM, MDIO, PEM, PHY, QLM ... */
358 bdk_boot();
360 if (CONFIG(PAYLOAD_FIT_SUPPORT)) {
361 struct device_tree_fixup *dt_fixup;
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);
371 if (CONFIG(ARM64_USE_ARM_TRUSTED_FIRMWARE))
372 soc_init_atf();
375 static void soc_final(struct device *dev)
377 watchdog_disable(0);
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,
387 static void enable_soc_dev(struct device *dev)
389 if (is_domain0(dev)) {
390 dev->ops = &pci_domain_ops_ecam0;
391 } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
392 dev->ops = &soc_ops;
396 struct chip_operations soc_cavium_cn81xx_ops = {
397 .name = "SOC Cavium CN81XX",
398 .enable_dev = enable_soc_dev,