diff options
author | Suneel Garapati <sgarapati@marvell.com> | 2019-10-19 18:37:55 -0700 |
---|---|---|
committer | Stefan Roese <sr@denx.de> | 2020-08-25 08:01:16 +0200 |
commit | 03c2288070155ee88d0c3341748a1b2b13418d8c (patch) | |
tree | c952178591efa580c3b8804ad647efe07b0d38b5 /board | |
parent | af6ba90048afb4e0db3ff2480364286f230f8b91 (diff) |
arm: octeontx: Add support for OcteonTX SoC platforms
This patch adds support for all OcteonTX 81xx/83xx
boards from Marvell.
For 81xx boards, use octeontx_81xx_defconfig and
for 83xx boards, use octeontx_83xx_defconfig.
Signed-off-by: Suneel Garapati <sgarapati@marvell.com>
Diffstat (limited to 'board')
-rw-r--r-- | board/Marvell/octeontx/Kconfig | 14 | ||||
-rw-r--r-- | board/Marvell/octeontx/MAINTAINERS | 8 | ||||
-rw-r--r-- | board/Marvell/octeontx/Makefile | 9 | ||||
-rw-r--r-- | board/Marvell/octeontx/board-fdt.c | 311 | ||||
-rw-r--r-- | board/Marvell/octeontx/board.c | 152 | ||||
-rw-r--r-- | board/Marvell/octeontx/smc.c | 25 | ||||
-rw-r--r-- | board/Marvell/octeontx/soc-utils.c | 50 |
7 files changed, 569 insertions, 0 deletions
diff --git a/board/Marvell/octeontx/Kconfig b/board/Marvell/octeontx/Kconfig new file mode 100644 index 0000000000..45d115916c --- /dev/null +++ b/board/Marvell/octeontx/Kconfig @@ -0,0 +1,14 @@ +if TARGET_OCTEONTX_81XX || TARGET_OCTEONTX_83XX + +config SYS_VENDOR + string + default "Marvell" + +config SYS_BOARD + string + default "octeontx" + +config SYS_CONFIG_NAME + default "octeontx_common" + +endif diff --git a/board/Marvell/octeontx/MAINTAINERS b/board/Marvell/octeontx/MAINTAINERS new file mode 100644 index 0000000000..1f3b12b1ab --- /dev/null +++ b/board/Marvell/octeontx/MAINTAINERS @@ -0,0 +1,8 @@ +OCTEONTX BOARD +M: Aaron Williams <awilliams@marvell.com> +S: Maintained +F: board/Marvell/octeontx/ +F: include/configs/octeontx_81xx.h +F: include/configs/octeontx_83xx.h +F: configs/octeontx_81xx_defconfig +F: configs/octeontx_83xx_defconfig diff --git a/board/Marvell/octeontx/Makefile b/board/Marvell/octeontx/Makefile new file mode 100644 index 0000000000..fbe32ae003 --- /dev/null +++ b/board/Marvell/octeontx/Makefile @@ -0,0 +1,9 @@ +#/* +# * Copyright (C) 2018 Marvell International Ltd. +# * +# * SPDX-License-Identifier: GPL-2.0 +# * https://spdx.org/licenses +# */ + +obj-y := board.o smc.o soc-utils.o +obj-$(CONFIG_OF_LIBFDT) += board-fdt.o diff --git a/board/Marvell/octeontx/board-fdt.c b/board/Marvell/octeontx/board-fdt.c new file mode 100644 index 0000000000..0b05ef11e9 --- /dev/null +++ b/board/Marvell/octeontx/board-fdt.c @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Marvell International Ltd. + * + * https://spdx.org/licenses + */ + +#include <errno.h> +#include <env.h> +#include <log.h> +#include <net.h> +#include <asm/io.h> +#include <linux/compiler.h> +#include <linux/libfdt.h> +#include <fdtdec.h> +#include <fdt_support.h> +#include <asm/arch/board.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int fdt_get_mdio_bus(const void *fdt, int phy_offset) +{ + int node, bus = -1; + const u64 *reg; + u64 addr; + + if (phy_offset < 0) + return -1; + /* obtain mdio node and get the reg prop */ + node = fdt_parent_offset(fdt, phy_offset); + if (node < 0) + return -1; + + reg = fdt_getprop(fdt, node, "reg", NULL); + addr = fdt64_to_cpu(*reg); + bus = (addr & (1 << 7)) ? 1 : 0; + return bus; +} + +static int fdt_get_phy_addr(const void *fdt, int phy_offset) +{ + const u32 *reg; + int addr = -1; + + if (phy_offset < 0) + return -1; + reg = fdt_getprop(fdt, phy_offset, "reg", NULL); + addr = fdt32_to_cpu(*reg); + return addr; +} + +void fdt_parse_phy_info(void) +{ + const void *fdt = gd->fdt_blob; + int offset = 0, node, bgx_id = 0, lmacid = 0; + const u32 *val; + char bgxname[24]; + int len, rgx_id = 0, eth_id = 0; + int phandle, phy_offset; + int subnode, i; + int bdknode; + + bdknode = fdt_path_offset(fdt, "/cavium,bdk"); + if (bdknode < 0) { + printf("%s: bdk node is missing from device tree: %s\n", + __func__, fdt_strerror(bdknode)); + } + + offset = fdt_node_offset_by_compatible(fdt, -1, "pci-bridge"); + if (offset < 1) + return; + + for (bgx_id = 0; bgx_id < MAX_BGX_PER_NODE; bgx_id++) { + int phy_addr[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = -1}; + bool autoneg_dis[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = 0}; + int mdio_bus[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = -1}; + bool lmac_reg[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = 0}; + bool lmac_enable[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = 0}; + + snprintf(bgxname, sizeof(bgxname), "bgx%d", bgx_id); + node = fdt_subnode_offset(fdt, offset, bgxname); + if (node < 0) { + /* check if it is rgx node */ + snprintf(bgxname, sizeof(bgxname), "rgx%d", rgx_id); + node = fdt_subnode_offset(fdt, offset, bgxname); + if (node < 0) { + debug("bgx%d/rgx0 node not found\n", bgx_id); + return; + } + } + debug("bgx%d node found\n", bgx_id); + + /* + * loop through each of the bgx/rgx nodes + * to find PHY nodes + */ + fdt_for_each_subnode(subnode, fdt, node) { + /* Check for reg property */ + val = fdt_getprop(fdt, subnode, "reg", &len); + if (val) { + debug("lmacid = %d\n", lmacid); + lmac_reg[lmacid] = 1; + } + /* check for phy-handle property */ + val = fdt_getprop(fdt, subnode, "phy-handle", &len); + if (val) { + phandle = fdt32_to_cpu(*val); + if (!phandle) { + debug("phandle not valid %d\n", lmacid); + } else { + phy_offset = fdt_node_offset_by_phandle + (fdt, phandle); + phy_addr[lmacid] = fdt_get_phy_addr + (fdt, phy_offset); + mdio_bus[lmacid] = fdt_get_mdio_bus + (fdt, phy_offset); + } + } else { + debug("phy-handle prop not found %d\n", + lmacid); + } + /* check for autonegotiation property */ + val = fdt_getprop(fdt, subnode, + "cavium,disable-autonegotiation", + &len); + if (val) + autoneg_dis[lmacid] = 1; + + eth_id++; + lmacid++; + } + + for (i = 0; i < MAX_LMAC_PER_BGX; i++) { + const char *str; + + snprintf(bgxname, sizeof(bgxname), + "BGX-ENABLE.N0.BGX%d.P%d", bgx_id, i); + if (bdknode >= 0) { + str = fdt_getprop(fdt, bdknode, + bgxname, &len); + if (str) + lmac_enable[i] = + simple_strtol(str, NULL, + 10); + } + } + + lmacid = 0; + bgx_set_board_info(bgx_id, mdio_bus, phy_addr, + autoneg_dis, lmac_reg, lmac_enable); + } +} + +static int fdt_get_bdk_node(void) +{ + int node, ret; + const void *fdt = gd->fdt_blob; + + if (!fdt) { + printf("ERROR: %s: no valid device tree found\n", __func__); + return 0; + } + + ret = fdt_check_header(fdt); + if (ret < 0) { + printf("fdt: %s\n", fdt_strerror(ret)); + return 0; + } + + node = fdt_path_offset(fdt, "/cavium,bdk"); + if (node < 0) { + printf("%s: /cavium,bdk is missing from device tree: %s\n", + __func__, fdt_strerror(node)); + return 0; + } + return node; +} + +const char *fdt_get_board_serial(void) +{ + const void *fdt = gd->fdt_blob; + int node, len = 64; + const char *str = NULL; + + node = fdt_get_bdk_node(); + if (!node) + return NULL; + + str = fdt_getprop(fdt, node, "BOARD-SERIAL", &len); + if (!str) + printf("Error: cannot retrieve board serial from fdt\n"); + return str; +} + +const char *fdt_get_board_revision(void) +{ + const void *fdt = gd->fdt_blob; + int node, len = 64; + const char *str = NULL; + + node = fdt_get_bdk_node(); + if (!node) + return NULL; + + str = fdt_getprop(fdt, node, "BOARD-REVISION", &len); + if (!str) + printf("Error: cannot retrieve board revision from fdt\n"); + return str; +} + +const char *fdt_get_board_model(void) +{ + const void *fdt = gd->fdt_blob; + int node, len = 16; + const char *str = NULL; + + node = fdt_get_bdk_node(); + if (!node) + return NULL; + + str = fdt_getprop(fdt, node, "BOARD-MODEL", &len); + if (!str) + printf("Error: cannot retrieve board model from fdt\n"); + return str; +} + +void fdt_board_get_ethaddr(int bgx, int lmac, unsigned char *eth) +{ + const void *fdt = gd->fdt_blob; + const char *mac = NULL; + int offset = 0, node, len; + int subnode, i = 0; + char bgxname[24]; + + offset = fdt_node_offset_by_compatible(fdt, -1, "pci-bridge"); + if (offset < 0) { + printf("%s couldn't find mrml bridge node in fdt\n", + __func__); + return; + } + if (bgx == 2 && otx_is_soc(CN81XX)) { + snprintf(bgxname, sizeof(bgxname), "rgx%d", 0); + lmac = 0; + } else { + snprintf(bgxname, sizeof(bgxname), "bgx%d", bgx); + } + + node = fdt_subnode_offset(fdt, offset, bgxname); + + fdt_for_each_subnode(subnode, fdt, node) { + if (i++ != lmac) + continue; + /* check for local-mac-address */ + mac = fdt_getprop(fdt, subnode, "local-mac-address", &len); + if (mac) { + debug("%s mac %pM\n", __func__, mac); + memcpy(eth, mac, ARP_HLEN); + } else { + memset(eth, 0, ARP_HLEN); + } + debug("%s eth %pM\n", __func__, eth); + return; + } +} + +int arch_fixup_memory_node(void *blob) +{ + return 0; +} + +int ft_board_setup(void *blob, struct bd_info *bd) +{ + /* remove "cavium, bdk" node from DT */ + int ret = 0, offset; + + ret = fdt_check_header(blob); + if (ret < 0) { + printf("ERROR: %s\n", fdt_strerror(ret)); + return ret; + } + + if (blob) { + offset = fdt_path_offset(blob, "/cavium,bdk"); + if (offset < 0) { + printf("ERROR: FDT BDK node not found\n"); + return offset; + } + + /* delete node */ + ret = fdt_del_node(blob, offset); + if (ret < 0) { + printf("WARNING : could not remove bdk node\n"); + return ret; + } + + debug("%s deleted bdk node\n", __func__); + } + + return 0; +} + +/** + * Return the FDT base address that was passed by ATF + * + * @return FDT base address received from ATF in x1 register + */ +void *board_fdt_blob_setup(void) +{ + return (void *)fdt_base_addr; +} diff --git a/board/Marvell/octeontx/board.c b/board/Marvell/octeontx/board.c new file mode 100644 index 0000000000..940faacbe3 --- /dev/null +++ b/board/Marvell/octeontx/board.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Marvell International Ltd. + * + * https://spdx.org/licenses + */ + +#include <dm.h> +#include <malloc.h> +#include <errno.h> +#include <env.h> +#include <init.h> +#include <log.h> +#include <netdev.h> +#include <pci_ids.h> +#include <asm/io.h> +#include <linux/compiler.h> +#include <linux/libfdt.h> +#include <fdt_support.h> +#include <asm/arch/smc.h> +#include <asm/arch/soc.h> +#include <asm/arch/board.h> +#include <dm/util.h> + +DECLARE_GLOBAL_DATA_PTR; + +void octeontx_cleanup_ethaddr(void) +{ + char ename[32]; + + for (int i = 0; i < 20; i++) { + sprintf(ename, i ? "eth%daddr" : "ethaddr", i); + if (env_get(ename)) + env_set(ename, NULL); + } +} + +int octeontx_board_has_pmp(void) +{ + return (otx_is_board("sff8104") || otx_is_board("nas8104")); +} + +int board_early_init_r(void) +{ + pci_init(); + return 0; +} + +int board_init(void) +{ + if (IS_ENABLED(CONFIG_NET_OCTEONTX)) + fdt_parse_phy_info(); + + return 0; +} + +int timer_init(void) +{ + return 0; +} + +int dram_init(void) +{ + gd->ram_size = smc_dram_size(0); + gd->ram_size -= CONFIG_SYS_SDRAM_BASE; + mem_map_fill(); + + return 0; +} + +void board_late_probe_devices(void) +{ + struct udevice *dev; + int err, bgx_cnt, i; + + /* Probe MAC(BGX) and NIC PF devices before Network stack init */ + bgx_cnt = otx_is_soc(CN81XX) ? 2 : 4; + for (i = 0; i < bgx_cnt; i++) { + err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM, + PCI_DEVICE_ID_CAVIUM_BGX, i, &dev); + if (err) + debug("%s BGX%d device not found\n", __func__, i); + } + if (otx_is_soc(CN81XX)) { + err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM, + PCI_DEVICE_ID_CAVIUM_RGX, 0, &dev); + if (err) + debug("%s RGX device not found\n", __func__); + } + err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM, + PCI_DEVICE_ID_CAVIUM_NIC, 0, &dev); + if (err) + debug("NIC PF device not found\n"); +} + +/** + * Board late initialization routine. + */ +int board_late_init(void) +{ + char boardname[32]; + char boardserial[150], boardrev[150]; + bool save_env = false; + const char *str; + + /* + * Try to cleanup ethaddr env variables, this is needed + * as with each boot, configuration of network interfaces can change. + */ + octeontx_cleanup_ethaddr(); + + snprintf(boardname, sizeof(boardname), "%s> ", fdt_get_board_model()); + env_set("prompt", boardname); + + set_working_fdt_addr(env_get_hex("fdtcontroladdr", fdt_base_addr)); + + str = fdt_get_board_revision(); + if (str) { + snprintf(boardrev, sizeof(boardrev), "%s", str); + if (env_get("boardrev") && + strcmp(boardrev, env_get("boardrev"))) + save_env = true; + env_set("boardrev", boardrev); + } + + str = fdt_get_board_serial(); + if (str) { + snprintf(boardserial, sizeof(boardserial), "%s", str); + if (env_get("serial#") && + strcmp(boardserial, env_get("serial#"))) + save_env = true; + env_set("serial#", boardserial); + } + + if (IS_ENABLED(CONFIG_NET_OCTEONTX)) + board_late_probe_devices(); + + if (save_env) + env_save(); + + return 0; +} + +/* + * Invoked before relocation, so limit to stack variables. + */ +int checkboard(void) +{ + printf("Board: %s\n", fdt_get_board_model()); + + return 0; +} diff --git a/board/Marvell/octeontx/smc.c b/board/Marvell/octeontx/smc.c new file mode 100644 index 0000000000..5eeba2358b --- /dev/null +++ b/board/Marvell/octeontx/smc.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Marvell International Ltd. + * + * https://spdx.org/licenses + */ + +#include <asm/global_data.h> +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/arch/smc.h> + +DECLARE_GLOBAL_DATA_PTR; + +ssize_t smc_dram_size(unsigned int node) +{ + struct pt_regs regs; + + regs.regs[0] = OCTEONTX_DRAM_SIZE; + regs.regs[1] = node; + smc_call(®s); + + return regs.regs[0]; +} + diff --git a/board/Marvell/octeontx/soc-utils.c b/board/Marvell/octeontx/soc-utils.c new file mode 100644 index 0000000000..5fd5afd48d --- /dev/null +++ b/board/Marvell/octeontx/soc-utils.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Marvell International Ltd. + * + * https://spdx.org/licenses + */ + +#include <dm.h> +#include <dm/util.h> +#include <errno.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/arch/soc.h> +#include <asm/arch/board.h> + +int read_platform(void) +{ + int plat = PLATFORM_HW; + + const char *model = fdt_get_board_model(); + + if (model && !strncmp(model, "ASIM-", 5)) + plat = PLATFORM_ASIM; + if (model && !strncmp(model, "EMUL-", 5)) + plat = PLATFORM_EMULATOR; + return plat; +} + +static inline u64 read_midr(void) +{ + u64 result; + + asm ("mrs %[rd],MIDR_EL1" : [rd] "=r" (result)); + return result; +} + +u8 read_partnum(void) +{ + return ((read_midr() >> 4) & 0xFF); +} + +const char *read_board_name(void) +{ + return fdt_get_board_model(); +} + +bool read_alt_pkg(void) +{ + return false; +} |