| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (C) 2018 Marvell International Ltd. |
| * |
| * https://spdx.org/licenses |
| */ |
| |
| #include <errno.h> |
| #include <fdtdec.h> |
| #include <fdt_support.h> |
| #include <log.h> |
| |
| #include <linux/compiler.h> |
| #include <linux/libfdt.h> |
| |
| #include <asm/arch/board.h> |
| #include <asm/arch/smc.h> |
| #include <asm/global_data.h> |
| #include <asm/io.h> |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| 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; |
| } |
| |
| u64 fdt_get_board_mac_addr(void) |
| { |
| int node, len = 16; |
| const char *str = NULL; |
| const void *fdt = gd->fdt_blob; |
| u64 mac_addr = 0; |
| |
| node = fdt_get_bdk_node(); |
| if (!node) |
| return mac_addr; |
| str = fdt_getprop(fdt, node, "BOARD-MAC-ADDRESS", &len); |
| if (str) |
| mac_addr = simple_strtol(str, NULL, 16); |
| return mac_addr; |
| } |
| |
| int fdt_get_board_mac_cnt(void) |
| { |
| int node, len = 16; |
| const char *str = NULL; |
| const void *fdt = gd->fdt_blob; |
| int mac_count = 0; |
| |
| node = fdt_get_bdk_node(); |
| if (!node) |
| return mac_count; |
| str = fdt_getprop(fdt, node, "BOARD-MAC-ADDRESS-NUM", &len); |
| if (str) { |
| mac_count = simple_strtol(str, NULL, 10); |
| if (!mac_count) |
| mac_count = simple_strtol(str, NULL, 16); |
| debug("fdt: MAC_NUM %d\n", mac_count); |
| } else { |
| printf("Error: cannot retrieve mac count prop from fdt\n"); |
| } |
| str = fdt_getprop(gd->fdt_blob, node, "BOARD-MAC-ADDRESS-NUM-OVERRIDE", |
| &len); |
| if (str) { |
| if (simple_strtol(str, NULL, 10) >= 0) |
| mac_count = simple_strtol(str, NULL, 10); |
| debug("fdt: MAC_NUM %d\n", mac_count); |
| } else { |
| printf("Error: cannot retrieve mac num override prop\n"); |
| } |
| return mac_count; |
| } |
| |
| 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) |
| { |
| int node, len = 16; |
| const char *str = NULL; |
| const void *fdt = gd->fdt_blob; |
| |
| 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; |
| } |
| |
| int arch_fixup_memory_node(void *blob) |
| { |
| return 0; |
| } |
| |
| int ft_board_setup(void *blob, struct bd_info *bd) |
| { |
| int nodeoff, node, ret, i; |
| const char *temp; |
| |
| static const char * const |
| octeontx_brd_nodes[] = {"BOARD-MODEL", |
| "BOARD-SERIAL", |
| "BOARD-MAC-ADDRESS", |
| "BOARD-REVISION", |
| "BOARD-MAC-ADDRESS-NUM" |
| }; |
| char nodes[ARRAY_SIZE(octeontx_brd_nodes)][32]; |
| |
| ret = fdt_check_header(blob); |
| if (ret < 0) { |
| printf("ERROR: %s\n", fdt_strerror(ret)); |
| return ret; |
| } |
| |
| if (blob) { |
| nodeoff = fdt_path_offset(blob, "/cavium,bdk"); |
| if (nodeoff < 0) { |
| printf("ERROR: FDT BDK node not found\n"); |
| return nodeoff; |
| } |
| |
| /* Read properties in temporary variables */ |
| for (i = 0; i < ARRAY_SIZE(octeontx_brd_nodes); i++) { |
| temp = fdt_getprop(blob, nodeoff, |
| octeontx_brd_nodes[i], NULL); |
| strncpy(nodes[i], temp, sizeof(nodes[i])); |
| } |
| |
| /* Delete cavium,bdk node */ |
| ret = fdt_del_node(blob, nodeoff); |
| if (ret < 0) { |
| printf("WARNING : could not remove cavium, bdk node\n"); |
| return ret; |
| } |
| debug("%s deleted 'cavium,bdk' node\n", __func__); |
| /* |
| * Add a new node at root level which would have |
| * necessary info |
| */ |
| node = fdt_add_subnode(blob, 0, "octeontx_brd"); |
| if (node < 0) { |
| printf("Cannot create node octeontx_brd: %s\n", |
| fdt_strerror(node)); |
| return -EIO; |
| } |
| |
| /* Populate properties in node */ |
| for (i = 0; i < ARRAY_SIZE(octeontx_brd_nodes); i++) { |
| if (fdt_setprop_string(blob, node, |
| octeontx_brd_nodes[i], |
| nodes[i])) { |
| printf("Can't set %s\n", nodes[i]); |
| return -EIO; |
| } |
| } |
| } |
| |
| 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(int *err) |
| { |
| *err = 0; |
| return (void *)fdt_base_addr; |
| } |