1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2018 Marvell International Ltd. 4 * 5 * https://spdx.org/licenses 6 */ 7 8#include <errno.h> 9#include <env.h> 10#include <log.h> 11#include <net.h> 12#include <asm/io.h> 13#include <linux/compiler.h> 14#include <linux/libfdt.h> 15#include <fdtdec.h> 16#include <fdt_support.h> 17#include <asm/arch/board.h> 18#include <asm/global_data.h> 19 20DECLARE_GLOBAL_DATA_PTR; 21 22static int fdt_get_mdio_bus(const void *fdt, int phy_offset) 23{ 24 int node, bus = -1; 25 const u64 *reg; 26 u64 addr; 27 28 if (phy_offset < 0) 29 return -1; 30 /* obtain mdio node and get the reg prop */ 31 node = fdt_parent_offset(fdt, phy_offset); 32 if (node < 0) 33 return -1; 34 35 reg = fdt_getprop(fdt, node, "reg", NULL); 36 addr = fdt64_to_cpu(*reg); 37 bus = (addr & (1 << 7)) ? 1 : 0; 38 return bus; 39} 40 41static int fdt_get_phy_addr(const void *fdt, int phy_offset) 42{ 43 const u32 *reg; 44 int addr = -1; 45 46 if (phy_offset < 0) 47 return -1; 48 reg = fdt_getprop(fdt, phy_offset, "reg", NULL); 49 addr = fdt32_to_cpu(*reg); 50 return addr; 51} 52 53void fdt_parse_phy_info(void) 54{ 55 const void *fdt = gd->fdt_blob; 56 int offset = 0, node, bgx_id = 0, lmacid = 0; 57 const u32 *val; 58 char bgxname[24]; 59 int len, rgx_id = 0, eth_id = 0; 60 int phandle, phy_offset; 61 int subnode, i; 62 int bdknode; 63 64 bdknode = fdt_path_offset(fdt, "/cavium,bdk"); 65 if (bdknode < 0) { 66 printf("%s: bdk node is missing from device tree: %s\n", 67 __func__, fdt_strerror(bdknode)); 68 } 69 70 offset = fdt_node_offset_by_compatible(fdt, -1, "pci-bridge"); 71 if (offset < 1) 72 return; 73 74 for (bgx_id = 0; bgx_id < MAX_BGX_PER_NODE; bgx_id++) { 75 int phy_addr[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = -1}; 76 bool autoneg_dis[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = 0}; 77 int mdio_bus[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = -1}; 78 bool lmac_reg[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = 0}; 79 bool lmac_enable[LMAC_CNT] = {[0 ... LMAC_CNT - 1] = 0}; 80 81 snprintf(bgxname, sizeof(bgxname), "bgx%d", bgx_id); 82 node = fdt_subnode_offset(fdt, offset, bgxname); 83 if (node < 0) { 84 /* check if it is rgx node */ 85 snprintf(bgxname, sizeof(bgxname), "rgx%d", rgx_id); 86 node = fdt_subnode_offset(fdt, offset, bgxname); 87 if (node < 0) { 88 debug("bgx%d/rgx0 node not found\n", bgx_id); 89 return; 90 } 91 } 92 debug("bgx%d node found\n", bgx_id); 93 94 /* 95 * loop through each of the bgx/rgx nodes 96 * to find PHY nodes 97 */ 98 fdt_for_each_subnode(subnode, fdt, node) { 99 /* Check for reg property */ 100 val = fdt_getprop(fdt, subnode, "reg", &len); 101 if (val) { 102 debug("lmacid = %d\n", lmacid); 103 lmac_reg[lmacid] = 1; 104 } 105 /* check for phy-handle property */ 106 val = fdt_getprop(fdt, subnode, "phy-handle", &len); 107 if (val) { 108 phandle = fdt32_to_cpu(*val); 109 if (!phandle) { 110 debug("phandle not valid %d\n", lmacid); 111 } else { 112 phy_offset = fdt_node_offset_by_phandle 113 (fdt, phandle); 114 phy_addr[lmacid] = fdt_get_phy_addr 115 (fdt, phy_offset); 116 mdio_bus[lmacid] = fdt_get_mdio_bus 117 (fdt, phy_offset); 118 } 119 } else { 120 debug("phy-handle prop not found %d\n", 121 lmacid); 122 } 123 /* check for autonegotiation property */ 124 val = fdt_getprop(fdt, subnode, 125 "cavium,disable-autonegotiation", 126 &len); 127 if (val) 128 autoneg_dis[lmacid] = 1; 129 130 eth_id++; 131 lmacid++; 132 } 133 134 for (i = 0; i < MAX_LMAC_PER_BGX; i++) { 135 const char *str; 136 137 snprintf(bgxname, sizeof(bgxname), 138 "BGX-ENABLE.N0.BGX%d.P%d", bgx_id, i); 139 if (bdknode >= 0) { 140 str = fdt_getprop(fdt, bdknode, 141 bgxname, &len); 142 if (str) 143 lmac_enable[i] = 144 simple_strtol(str, NULL, 145 10); 146 } 147 } 148 149 lmacid = 0; 150 bgx_set_board_info(bgx_id, mdio_bus, phy_addr, 151 autoneg_dis, lmac_reg, lmac_enable); 152 } 153} 154 155static int fdt_get_bdk_node(void) 156{ 157 int node, ret; 158 const void *fdt = gd->fdt_blob; 159 160 if (!fdt) { 161 printf("ERROR: %s: no valid device tree found\n", __func__); 162 return 0; 163 } 164 165 ret = fdt_check_header(fdt); 166 if (ret < 0) { 167 printf("fdt: %s\n", fdt_strerror(ret)); 168 return 0; 169 } 170 171 node = fdt_path_offset(fdt, "/cavium,bdk"); 172 if (node < 0) { 173 printf("%s: /cavium,bdk is missing from device tree: %s\n", 174 __func__, fdt_strerror(node)); 175 return 0; 176 } 177 return node; 178} 179 180const char *fdt_get_board_serial(void) 181{ 182 const void *fdt = gd->fdt_blob; 183 int node, len = 64; 184 const char *str = NULL; 185 186 node = fdt_get_bdk_node(); 187 if (!node) 188 return NULL; 189 190 str = fdt_getprop(fdt, node, "BOARD-SERIAL", &len); 191 if (!str) 192 printf("Error: cannot retrieve board serial from fdt\n"); 193 return str; 194} 195 196const char *fdt_get_board_revision(void) 197{ 198 const void *fdt = gd->fdt_blob; 199 int node, len = 64; 200 const char *str = NULL; 201 202 node = fdt_get_bdk_node(); 203 if (!node) 204 return NULL; 205 206 str = fdt_getprop(fdt, node, "BOARD-REVISION", &len); 207 if (!str) 208 printf("Error: cannot retrieve board revision from fdt\n"); 209 return str; 210} 211 212const char *fdt_get_board_model(void) 213{ 214 const void *fdt = gd->fdt_blob; 215 int node, len = 16; 216 const char *str = NULL; 217 218 node = fdt_get_bdk_node(); 219 if (!node) 220 return NULL; 221 222 str = fdt_getprop(fdt, node, "BOARD-MODEL", &len); 223 if (!str) 224 printf("Error: cannot retrieve board model from fdt\n"); 225 return str; 226} 227 228void fdt_board_get_ethaddr(int bgx, int lmac, unsigned char *eth) 229{ 230 const void *fdt = gd->fdt_blob; 231 const char *mac = NULL; 232 int offset = 0, node, len; 233 int subnode, i = 0; 234 char bgxname[24]; 235 236 offset = fdt_node_offset_by_compatible(fdt, -1, "pci-bridge"); 237 if (offset < 0) { 238 printf("%s couldn't find mrml bridge node in fdt\n", 239 __func__); 240 return; 241 } 242 if (bgx == 2 && otx_is_soc(CN81XX)) { 243 snprintf(bgxname, sizeof(bgxname), "rgx%d", 0); 244 lmac = 0; 245 } else { 246 snprintf(bgxname, sizeof(bgxname), "bgx%d", bgx); 247 } 248 249 node = fdt_subnode_offset(fdt, offset, bgxname); 250 251 fdt_for_each_subnode(subnode, fdt, node) { 252 if (i++ != lmac) 253 continue; 254 /* check for local-mac-address */ 255 mac = fdt_getprop(fdt, subnode, "local-mac-address", &len); 256 if (mac) { 257 debug("%s mac %pM\n", __func__, mac); 258 memcpy(eth, mac, ARP_HLEN); 259 } else { 260 memset(eth, 0, ARP_HLEN); 261 } 262 debug("%s eth %pM\n", __func__, eth); 263 return; 264 } 265} 266 267int arch_fixup_memory_node(void *blob) 268{ 269 return 0; 270} 271 272int ft_board_setup(void *blob, struct bd_info *bd) 273{ 274 /* remove "cavium, bdk" node from DT */ 275 int ret = 0, offset; 276 277 ret = fdt_check_header(blob); 278 if (ret < 0) { 279 printf("ERROR: %s\n", fdt_strerror(ret)); 280 return ret; 281 } 282 283 if (blob) { 284 /* delete cavium,bdk node if it exists */ 285 offset = fdt_path_offset(blob, "/cavium,bdk"); 286 if (offset >= 0) { 287 ret = fdt_del_node(blob, offset); 288 if (ret < 0) { 289 printf("WARNING : could not remove bdk node\n"); 290 return ret; 291 } 292 debug("%s deleted bdk node\n", __func__); 293 } 294 } 295 296 return 0; 297} 298 299/** 300 * Return the FDT base address that was passed by ATF 301 * 302 * Return: FDT base address received from ATF in x1 register 303 */ 304void *board_fdt_blob_setup(int *err) 305{ 306 *err = 0; 307 return (void *)fdt_base_addr; 308} 309