1 /* SPDX-License-Identifier: GPL-2.0-only */
4 * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0.
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>
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>
28 #include <soc/bl31_plat_params.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
;
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 */
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
) !=
76 dt_delete_prop(node
, "phy-handle");
77 printk(BIOS_INFO
, "%s: Removing phy-handle on "
78 "node %s\n", __func__
, node
->name
);
85 printk(BIOS_INFO
, "%s: Removing node %s\n", __func__
,
87 /* No match, remove node */
88 list_remove(&node
->list_node
);
92 static void dt_iterate_phy(struct device_tree_node
*parent
,
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
,
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
;
120 dt_find_bin_prop(node
, name
, (const void **)&localmac
, &size
);
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
;
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);
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
;
175 /* Set the sclk clock rate. */
176 dt_node
= dt_find_node_by_path(tree
, "/soc@0/sclk", NULL
, NULL
, 0);
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
);
182 printk(BIOS_ERR
, "%s: Node not found. OS might miss-behave !\n",
185 /* Set refclkuaa clock rate. */
186 dt_node
= dt_find_node_by_path(tree
, "/soc@0/refclkuaa", NULL
,
189 const u32 freq
= uart_platform_refclk();
190 printk(BIOS_INFO
, "%s: Set REFCLKUAA to %u Hz\n", __func__
,
192 dt_add_u32_prop(dt_node
, "clock-frequency", freq
);
194 printk(BIOS_ERR
, "%s: Node not found. OS might miss-behave !\n",
197 /* Remove unused UART entries */
198 for (i
= 0; i
< 4; i
++) {
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
);
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
++) {
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
);
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);
233 printk(BIOS_ERR
, "%s: SMMU entry not found\n",
237 const u32
*data
= NULL
;
239 dt_find_bin_prop(dt_node
, "mmu-masters", (const void **)&data
,
242 printk(BIOS_ERR
, "%s: mmu-masters entry not found\n",
247 u32
*data_cleaned
= malloc(size
);
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];
260 dt_add_bin_prop(dt_node
, "mmu-masters", data_cleaned
,
261 n
* sizeof(u32
) * 2);
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
++) {
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
,
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
);
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
);
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
),
319 /* Scratchpad for ATF SATA quirks */
320 bootmem_add_range((sdram_size_mb() - 1) * MiB
, 1 * MiB
,
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
, },
338 void *ptr
= cbfs_map("sff8104-linux.dtb", &size
);
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 ... */
360 if (CONFIG(PAYLOAD_FIT_SUPPORT
)) {
361 struct device_tree_fixup
*dt_fixup
;
363 dt_fixup
= malloc(sizeof(*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
))
375 static void soc_final(struct device
*dev
)
380 static struct device_operations soc_ops
= {
381 .read_resources
= soc_read_resources
,
382 .set_resources
= noop_set_resources
,
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
) {
396 struct chip_operations soc_cavium_cn81xx_ops
= {
397 .name
= "SOC Cavium CN81XX",
398 .enable_dev
= enable_soc_dev
,