1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2018-2022 Marvell International Ltd. 4 * 5 * Helper functions to abstract board specific data about 6 * network ports from the rest of the cvmx-helper files. 7 */ 8 9#include <i2c.h> 10#include <log.h> 11#include <malloc.h> 12#include <net.h> 13#include <linux/delay.h> 14 15#include <mach/cvmx-regs.h> 16#include <mach/cvmx-csr.h> 17#include <mach/cvmx-bootmem.h> 18#include <mach/octeon-model.h> 19#include <mach/octeon_fdt.h> 20#include <mach/cvmx-helper.h> 21#include <mach/cvmx-helper-board.h> 22#include <mach/cvmx-helper-cfg.h> 23#include <mach/cvmx-helper-fdt.h> 24#include <mach/cvmx-helper-gpio.h> 25 26#include <mach/cvmx-smix-defs.h> 27#include <mach/cvmx-mdio.h> 28#include <mach/cvmx-qlm.h> 29 30DECLARE_GLOBAL_DATA_PTR; 31 32static bool sfp_parsed; 33 34static int __cvmx_helper_78xx_parse_phy(struct cvmx_phy_info *phy_info, 35 int ipd_port); 36static int __get_phy_info_from_dt(cvmx_phy_info_t *phy_info, int ipd_port); 37 38/** 39 * Writes to a Microsemi VSC7224 16-bit register 40 * 41 * @param[in] i2c_bus i2c bus data structure (must be enabled) 42 * @param addr Address of VSC7224 on the i2c bus 43 * @param reg 8-bit register number to write to 44 * @param val 16-bit value to write 45 * 46 * @return 0 for success 47 */ 48static int cvmx_write_vsc7224_reg(const struct cvmx_fdt_i2c_bus_info *i2c_bus, 49 u8 addr, u8 reg, u16 val) 50{ 51 struct udevice *dev; 52 u8 buffer[2]; 53 int ret; 54 55 ret = i2c_get_chip(i2c_bus->i2c_bus, addr, 1, &dev); 56 if (ret) { 57 debug("Cannot find I2C device: %d\n", ret); 58 return -1; 59 } 60 61 ret = dm_i2c_write(dev, reg, buffer, 2); 62 if (ret) { 63 debug("Cannot write I2C device: %d\n", ret); 64 return -1; 65 } 66 67 return 0; 68} 69 70/** 71 * Writes to a Microsemi VSC7224 16-bit register 72 * 73 * @param[in] i2c_bus i2c bus data structure (must be enabled) 74 * @param addr Address of VSC7224 on the i2c bus 75 * @param reg 8-bit register number to write to 76 * 77 * @return 16-bit value or error if < 0 78 */ 79static int cvmx_read_vsc7224_reg(const struct cvmx_fdt_i2c_bus_info *i2c_bus, 80 u8 addr, u8 reg) 81{ 82 struct udevice *dev; 83 u8 buffer[2]; 84 int ret; 85 86 ret = i2c_get_chip(i2c_bus->i2c_bus, addr, 1, &dev); 87 if (ret) { 88 debug("Cannot find I2C device: %d\n", ret); 89 return -1; 90 } 91 92 ret = dm_i2c_read(dev, reg, buffer, 2); 93 if (ret) { 94 debug("Cannot read I2C device: %d\n", ret); 95 return -1; 96 } 97 98 return (buffer[0] << 8) | buffer[1]; 99} 100 101/** 102 * Function called whenever mod_abs/mod_prs has changed for Microsemi VSC7224 103 * 104 * @param sfp pointer to SFP data structure 105 * @param val 1 if absent, 0 if present, otherwise not set 106 * @param data user-defined data 107 * 108 * @return 0 for success, -1 on error 109 */ 110int cvmx_sfp_vsc7224_mod_abs_changed(struct cvmx_fdt_sfp_info *sfp, int val, 111 void *data) 112{ 113 int err; 114 struct cvmx_sfp_mod_info *mod_info; 115 int length; 116 struct cvmx_vsc7224 *vsc7224; 117 struct cvmx_vsc7224_chan *vsc7224_chan; 118 struct cvmx_vsc7224_tap *taps, *match = NULL; 119 int i; 120 121 debug("%s(%s, %d, %p): Module %s\n", __func__, sfp->name, val, data, 122 val ? "absent" : "present"); 123 if (val) 124 return 0; 125 126 /* We're here if we detect that the module is now present */ 127 err = cvmx_sfp_read_i2c_eeprom(sfp); 128 if (err) { 129 debug("%s: Error reading the SFP module eeprom for %s\n", 130 __func__, sfp->name); 131 return err; 132 } 133 mod_info = &sfp->sfp_info; 134 135 if (!mod_info->valid || !sfp->valid) { 136 debug("%s: Module data is invalid\n", __func__); 137 return -1; 138 } 139 140 vsc7224_chan = sfp->vsc7224_chan; 141 while (vsc7224_chan) { 142 /* We don't do any rx tuning */ 143 if (!vsc7224_chan->is_tx) { 144 vsc7224_chan = vsc7224_chan->next; 145 continue; 146 } 147 148 /* Walk through all the channels */ 149 taps = vsc7224_chan->taps; 150 if (mod_info->limiting) 151 length = 0; 152 else 153 length = mod_info->max_copper_cable_len; 154 debug("%s: limiting: %d, length: %d\n", __func__, 155 mod_info->limiting, length); 156 157 /* Find a matching length in the taps table */ 158 for (i = 0; i < vsc7224_chan->num_taps; i++) { 159 if (length >= taps->len) 160 match = taps; 161 taps++; 162 } 163 if (!match) { 164 debug("%s(%s, %d, %p): Error: no matching tap for length %d\n", 165 __func__, sfp->name, val, data, length); 166 return -1; 167 } 168 debug("%s(%s): Applying %cx taps to vsc7224 %s:%d for cable length %d+\n", 169 __func__, sfp->name, vsc7224_chan->is_tx ? 't' : 'r', 170 vsc7224_chan->vsc7224->name, vsc7224_chan->lane, 171 match->len); 172 /* Program the taps */ 173 vsc7224 = vsc7224_chan->vsc7224; 174 cvmx_write_vsc7224_reg(vsc7224->i2c_bus, vsc7224->i2c_addr, 175 0x7f, vsc7224_chan->lane); 176 if (!vsc7224_chan->maintap_disable) 177 cvmx_write_vsc7224_reg(vsc7224->i2c_bus, 178 vsc7224->i2c_addr, 0x99, 179 match->main_tap); 180 if (!vsc7224_chan->pretap_disable) 181 cvmx_write_vsc7224_reg(vsc7224->i2c_bus, 182 vsc7224->i2c_addr, 0x9a, 183 match->pre_tap); 184 if (!vsc7224_chan->posttap_disable) 185 cvmx_write_vsc7224_reg(vsc7224->i2c_bus, 186 vsc7224->i2c_addr, 0x9b, 187 match->post_tap); 188 189 /* Re-use val and disable taps if needed */ 190 if (vsc7224_chan->maintap_disable || 191 vsc7224_chan->pretap_disable || 192 vsc7224_chan->posttap_disable) { 193 val = cvmx_read_vsc7224_reg(vsc7224->i2c_bus, 194 vsc7224->i2c_addr, 0x97); 195 if (vsc7224_chan->maintap_disable) 196 val |= 0x800; 197 if (vsc7224_chan->pretap_disable) 198 val |= 0x1000; 199 if (vsc7224_chan->posttap_disable) 200 val |= 0x400; 201 cvmx_write_vsc7224_reg(vsc7224->i2c_bus, 202 vsc7224->i2c_addr, 0x97, val); 203 } 204 vsc7224_chan = vsc7224_chan->next; 205 } 206 207 return err; 208} 209 210/** 211 * Update the mod_abs and error LED 212 * 213 * @param ipd_port ipd port number 214 * @param link link information 215 */ 216static void __cvmx_helper_update_sfp(int ipd_port, 217 struct cvmx_fdt_sfp_info *sfp_info, 218 cvmx_helper_link_info_t link) 219{ 220 debug("%s(%d): checking mod_abs\n", __func__, ipd_port); 221 222 cvmx_sfp_check_mod_abs(sfp_info, sfp_info->mod_abs_data); 223} 224 225static void cvmx_sfp_update_link(struct cvmx_fdt_sfp_info *sfp, 226 cvmx_helper_link_info_t link) 227{ 228 while (sfp) { 229 debug("%s(%s): checking mod_abs\n", __func__, sfp->name); 230 if (link.s.link_up && sfp->last_mod_abs) 231 cvmx_sfp_check_mod_abs(sfp, sfp->mod_abs_data); 232 sfp = sfp->next_iface_sfp; 233 } 234} 235 236/** 237 * @INTERNAL 238 * This function is used ethernet ports link speed. This functions uses the 239 * device tree information to determine the phy address and type of PHY. 240 * The only supproted PHYs are Marvell and Broadcom. 241 * 242 * @param ipd_port IPD input port associated with the port we want to get link 243 * status for. 244 * 245 * @return The ports link status. If the link isn't fully resolved, this must 246 * return zero. 247 */ 248cvmx_helper_link_info_t __cvmx_helper_board_link_get_from_dt(int ipd_port) 249{ 250 cvmx_helper_link_info_t result; 251 cvmx_phy_info_t *phy_info = NULL; 252 cvmx_phy_info_t local_phy_info; 253 int xiface = 0, index = 0; 254 bool use_inband = false; 255 struct cvmx_fdt_sfp_info *sfp_info; 256 const void *fdt_addr = CASTPTR(const void *, gd->fdt_blob); 257 258 result.u64 = 0; 259 260 if (ipd_port >= 0) { 261 int mode; 262 263 xiface = cvmx_helper_get_interface_num(ipd_port); 264 index = cvmx_helper_get_interface_index_num(ipd_port); 265 mode = cvmx_helper_interface_get_mode(xiface); 266 if (!cvmx_helper_get_port_autonegotiation(xiface, index)) { 267 result.s.link_up = 1; 268 result.s.full_duplex = 1; 269 switch (mode) { 270 case CVMX_HELPER_INTERFACE_MODE_RGMII: 271 case CVMX_HELPER_INTERFACE_MODE_GMII: 272 case CVMX_HELPER_INTERFACE_MODE_SGMII: 273 case CVMX_HELPER_INTERFACE_MODE_QSGMII: 274 case CVMX_HELPER_INTERFACE_MODE_AGL: 275 case CVMX_HELPER_INTERFACE_MODE_SPI: 276 if (OCTEON_IS_MODEL(OCTEON_CN70XX)) { 277 struct cvmx_xiface xi = 278 cvmx_helper_xiface_to_node_interface( 279 xiface); 280 u64 gbaud = cvmx_qlm_get_gbaud_mhz(0); 281 282 result.s.speed = gbaud * 8 / 10; 283 if (cvmx_qlm_get_dlm_mode( 284 0, xi.interface) == 285 CVMX_QLM_MODE_SGMII) 286 result.s.speed >>= 1; 287 else 288 result.s.speed >>= 2; 289 } else { 290 result.s.speed = 1000; 291 } 292 break; 293 case CVMX_HELPER_INTERFACE_MODE_RXAUI: 294 case CVMX_HELPER_INTERFACE_MODE_XAUI: 295 case CVMX_HELPER_INTERFACE_MODE_10G_KR: 296 case CVMX_HELPER_INTERFACE_MODE_XFI: 297 result.s.speed = 10000; 298 break; 299 case CVMX_HELPER_INTERFACE_MODE_XLAUI: 300 case CVMX_HELPER_INTERFACE_MODE_40G_KR4: 301 result.s.speed = 40000; 302 break; 303 default: 304 break; 305 } 306 307 sfp_info = cvmx_helper_cfg_get_sfp_info(xiface, index); 308 /* Initialize the SFP info if it hasn't already been 309 * done. 310 */ 311 if (!sfp_info && !sfp_parsed) { 312 cvmx_sfp_parse_device_tree(fdt_addr); 313 sfp_parsed = true; 314 cvmx_sfp_read_all_modules(); 315 sfp_info = cvmx_helper_cfg_get_sfp_info(xiface, 316 index); 317 } 318 /* If the link is down or the link is up but we still 319 * register the module as being absent, re-check 320 * mod_abs. 321 */ 322 cvmx_sfp_update_link(sfp_info, result); 323 324 cvmx_helper_update_link_led(xiface, index, result); 325 326 return result; 327 } 328 phy_info = cvmx_helper_get_port_phy_info(xiface, index); 329 if (!phy_info) { 330 debug("%s: phy info not saved in config, allocating for 0x%x:%d\n", 331 __func__, xiface, index); 332 333 phy_info = (cvmx_phy_info_t *)cvmx_bootmem_alloc( 334 sizeof(*phy_info), 0); 335 if (!phy_info) { 336 debug("%s: Out of memory\n", __func__); 337 return result; 338 } 339 memset(phy_info, 0, sizeof(*phy_info)); 340 phy_info->phy_addr = -1; 341 debug("%s: Setting phy info for 0x%x:%d to %p\n", 342 __func__, xiface, index, phy_info); 343 cvmx_helper_set_port_phy_info(xiface, index, phy_info); 344 } 345 } else { 346 /* For management ports we don't store the PHY information 347 * so we use a local copy instead. 348 */ 349 phy_info = &local_phy_info; 350 memset(phy_info, 0, sizeof(*phy_info)); 351 phy_info->phy_addr = -1; 352 } 353 354 if (phy_info->phy_addr == -1) { 355 if (octeon_has_feature(OCTEON_FEATURE_BGX)) { 356 if (__cvmx_helper_78xx_parse_phy(phy_info, ipd_port)) { 357 phy_info->phy_addr = -1; 358 use_inband = true; 359 } 360 } else if (__get_phy_info_from_dt(phy_info, ipd_port) < 0) { 361 phy_info->phy_addr = -1; 362 use_inband = true; 363 } 364 } 365 366 /* If we can't get the PHY info from the device tree then try 367 * the inband state. 368 */ 369 if (use_inband) { 370 result.s.full_duplex = 1; 371 result.s.link_up = 1; 372 result.s.speed = 1000; 373 return result; 374 } 375 376 if (phy_info->phy_addr < 0) 377 return result; 378 379 if (phy_info->link_function) 380 result = phy_info->link_function(phy_info); 381 else 382 result = cvmx_helper_link_get(ipd_port); 383 384 sfp_info = cvmx_helper_cfg_get_sfp_info(xiface, index); 385 while (sfp_info) { 386 /* If the link is down or the link is up but we still register 387 * the module as being absent, re-check mod_abs. 388 */ 389 if (!result.s.link_up || 390 (result.s.link_up && sfp_info->last_mod_abs)) 391 __cvmx_helper_update_sfp(ipd_port, sfp_info, result); 392 sfp_info = sfp_info->next_iface_sfp; 393 } 394 395 return result; 396} 397 398cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) 399{ 400 cvmx_helper_link_info_t result; 401 402 /* Unless we fix it later, all links are defaulted to down */ 403 result.u64 = 0; 404 405 return __cvmx_helper_board_link_get_from_dt(ipd_port); 406} 407 408void cvmx_helper_update_link_led(int xiface, int index, 409 cvmx_helper_link_info_t result) 410{ 411} 412 413void cvmx_helper_leds_show_error(struct cvmx_phy_gpio_leds *leds, bool error) 414{ 415} 416 417int __cvmx_helper_board_interface_probe(int interface, int supported_ports) 418{ 419 return supported_ports; 420} 421 422/** 423 * Returns the Ethernet node offset in the device tree 424 * 425 * @param fdt_addr - pointer to flat device tree in memory 426 * @param aliases - offset of alias in device tree 427 * @param ipd_port - ipd port number to look up 428 * 429 * @returns offset of Ethernet node if >= 0, error if -1 430 */ 431int __pip_eth_node(const void *fdt_addr, int aliases, int ipd_port) 432{ 433 char name_buffer[20]; 434 const char *pip_path; 435 int pip, iface, eth; 436 int interface_num = cvmx_helper_get_interface_num(ipd_port); 437 int interface_index = cvmx_helper_get_interface_index_num(ipd_port); 438 cvmx_helper_interface_mode_t interface_mode = 439 cvmx_helper_interface_get_mode(interface_num); 440 441 /* The following are not found in the device tree */ 442 switch (interface_mode) { 443 case CVMX_HELPER_INTERFACE_MODE_ILK: 444 case CVMX_HELPER_INTERFACE_MODE_LOOP: 445 case CVMX_HELPER_INTERFACE_MODE_SRIO: 446 debug("ERROR: No node expected for interface: %d, port: %d, mode: %s\n", 447 interface_index, ipd_port, 448 cvmx_helper_interface_mode_to_string(interface_mode)); 449 return -1; 450 default: 451 break; 452 } 453 pip_path = (const char *)fdt_getprop(fdt_addr, aliases, "pip", NULL); 454 if (!pip_path) { 455 debug("ERROR: pip path not found in device tree\n"); 456 return -1; 457 } 458 pip = fdt_path_offset(fdt_addr, pip_path); 459 debug("ipdd_port=%d pip_path=%s pip=%d ", ipd_port, pip_path, pip); 460 if (pip < 0) { 461 debug("ERROR: pip not found in device tree\n"); 462 return -1; 463 } 464 snprintf(name_buffer, sizeof(name_buffer), "interface@%d", 465 interface_num); 466 iface = fdt_subnode_offset(fdt_addr, pip, name_buffer); 467 debug("iface=%d ", iface); 468 if (iface < 0) { 469 debug("ERROR : pip intf %d not found in device tree\n", 470 interface_num); 471 return -1; 472 } 473 snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", 474 interface_index); 475 eth = fdt_subnode_offset(fdt_addr, iface, name_buffer); 476 debug("eth=%d\n", eth); 477 if (eth < 0) { 478 debug("ERROR : pip interface@%d ethernet@%d not found in device tree\n", 479 interface_num, interface_index); 480 return -1; 481 } 482 return eth; 483} 484 485int __mix_eth_node(const void *fdt_addr, int aliases, int interface_index) 486{ 487 char name_buffer[20]; 488 const char *mix_path; 489 int mix; 490 491 snprintf(name_buffer, sizeof(name_buffer), "mix%d", interface_index); 492 mix_path = 493 (const char *)fdt_getprop(fdt_addr, aliases, name_buffer, NULL); 494 if (!mix_path) { 495 debug("ERROR: mix%d path not found in device tree\n", 496 interface_index); 497 } 498 mix = fdt_path_offset(fdt_addr, mix_path); 499 if (mix < 0) { 500 debug("ERROR: %s not found in device tree\n", mix_path); 501 return -1; 502 } 503 return mix; 504} 505 506static int __mdiobus_addr_to_unit(u32 addr) 507{ 508 int unit = (addr >> 7) & 3; 509 510 if (!OCTEON_IS_MODEL(OCTEON_CN68XX) && !OCTEON_IS_MODEL(OCTEON_CN78XX)) 511 unit >>= 1; 512 return unit; 513} 514 515/** 516 * Parse the muxed MDIO interface information from the device tree 517 * 518 * @param phy_info - pointer to phy info data structure to update 519 * @param mdio_offset - offset of MDIO bus 520 * @param mux_offset - offset of MUX, parent of mdio_offset 521 * 522 * @return 0 for success or -1 523 */ 524static int __get_muxed_mdio_info_from_dt(cvmx_phy_info_t *phy_info, 525 int mdio_offset, int mux_offset) 526{ 527 const void *fdt_addr = CASTPTR(const void *, gd->fdt_blob); 528 int phandle; 529 int smi_offset; 530 int gpio_offset; 531 u64 smi_addr = 0; 532 int len; 533 u32 *pgpio_handle; 534 int gpio_count = 0; 535 u32 *prop_val; 536 int offset; 537 const char *prop_name; 538 539 debug("%s(%p, 0x%x, 0x%x)\n", __func__, phy_info, mdio_offset, 540 mux_offset); 541 542 /* Get register value to put onto the GPIO lines to select */ 543 phy_info->gpio_value = 544 cvmx_fdt_get_int(fdt_addr, mdio_offset, "reg", -1); 545 if (phy_info->gpio_value < 0) { 546 debug("Could not get register value for muxed MDIO bus from DT\n"); 547 return -1; 548 } 549 550 smi_offset = cvmx_fdt_lookup_phandle(fdt_addr, mux_offset, 551 "mdio-parent-bus"); 552 if (smi_offset < 0) { 553 debug("Invalid SMI offset for muxed MDIO interface in device tree\n"); 554 return -1; 555 } 556 smi_addr = cvmx_fdt_get_uint64(fdt_addr, smi_offset, "reg", 0); 557 558 /* Convert SMI address to a MDIO interface */ 559 switch (smi_addr) { 560 case 0x1180000001800: 561 case 0x1180000003800: /* 68XX address */ 562 phy_info->mdio_unit = 0; 563 break; 564 case 0x1180000001900: 565 case 0x1180000003880: 566 phy_info->mdio_unit = 1; 567 break; 568 case 0x1180000003900: 569 phy_info->mdio_unit = 2; 570 break; 571 case 0x1180000003980: 572 phy_info->mdio_unit = 3; 573 break; 574 default: 575 phy_info->mdio_unit = 1; 576 break; 577 } 578 /* Find the GPIO MUX controller */ 579 pgpio_handle = 580 (u32 *)fdt_getprop(fdt_addr, mux_offset, "gpios", &len); 581 if (!pgpio_handle || len < 12 || (len % 12) != 0 || 582 len > CVMX_PHY_MUX_MAX_GPIO * 12) { 583 debug("Invalid GPIO for muxed MDIO controller in DT\n"); 584 return -1; 585 } 586 587 for (gpio_count = 0; gpio_count < len / 12; gpio_count++) { 588 phandle = fdt32_to_cpu(pgpio_handle[gpio_count * 3]); 589 phy_info->gpio[gpio_count] = 590 fdt32_to_cpu(pgpio_handle[gpio_count * 3 + 1]); 591 gpio_offset = fdt_node_offset_by_phandle(fdt_addr, phandle); 592 if (gpio_offset < 0) { 593 debug("Cannot access parent GPIO node in DT\n"); 594 return -1; 595 } 596 if (!fdt_node_check_compatible(fdt_addr, gpio_offset, 597 "cavium,octeon-3860-gpio")) { 598 phy_info->gpio_type[gpio_count] = GPIO_OCTEON; 599 } else if (!fdt_node_check_compatible(fdt_addr, gpio_offset, 600 "nxp,pca8574")) { 601 /* GPIO is a TWSI GPIO unit which might sit behind 602 * another mux. 603 */ 604 phy_info->gpio_type[gpio_count] = GPIO_PCA8574; 605 prop_val = (u32 *)fdt_getprop( 606 fdt_addr, gpio_offset, "reg", NULL); 607 if (!prop_val) { 608 debug("Could not find TWSI address of npx pca8574 GPIO from DT\n"); 609 return -1; 610 } 611 /* Get the TWSI address of the GPIO unit */ 612 phy_info->cvmx_gpio_twsi[gpio_count] = 613 fdt32_to_cpu(*prop_val); 614 /* Get the selector on the GPIO mux if present */ 615 offset = fdt_parent_offset(fdt_addr, gpio_offset); 616 prop_val = (u32 *)fdt_getprop(fdt_addr, offset, 617 "reg", NULL); 618 if (prop_val) { 619 phy_info->gpio_parent_mux_select = 620 fdt32_to_cpu(*prop_val); 621 /* Go up another level */ 622 offset = fdt_parent_offset(fdt_addr, offset); 623 if (!fdt_node_check_compatible(fdt_addr, offset, 624 "nxp,pca9548")) { 625 prop_val = (u32 *)fdt_getprop( 626 fdt_addr, offset, "reg", NULL); 627 if (!prop_val) { 628 debug("Could not read MUX TWSI address from DT\n"); 629 return -1; 630 } 631 phy_info->gpio_parent_mux_twsi = 632 fdt32_to_cpu(*prop_val); 633 } 634 } 635 } else { 636 prop_name = (char *)fdt_getprop(fdt_addr, gpio_offset, 637 "compatible", NULL); 638 debug("Unknown GPIO type %s\n", prop_name); 639 return -1; 640 } 641 } 642 return 0; 643} 644 645/** 646 * @INTERNAL 647 * Converts a BGX address to the node, interface and port number 648 * 649 * @param bgx_addr Address of CSR register 650 * 651 * @return node, interface and port number, will be -1 for invalid address. 652 */ 653static struct cvmx_xiface __cvmx_bgx_reg_addr_to_xiface(u64 bgx_addr) 654{ 655 struct cvmx_xiface xi = { -1, -1 }; 656 657 xi.node = cvmx_csr_addr_to_node(bgx_addr); 658 bgx_addr = cvmx_csr_addr_strip_node(bgx_addr); 659 if ((bgx_addr & 0xFFFFFFFFF0000000) != 0x00011800E0000000) { 660 debug("%s: Invalid BGX address 0x%llx\n", __func__, 661 (unsigned long long)bgx_addr); 662 xi.node = -1; 663 return xi; 664 } 665 xi.interface = (bgx_addr >> 24) & 0x0F; 666 667 return xi; 668} 669 670static cvmx_helper_link_info_t 671__get_marvell_phy_link_state(cvmx_phy_info_t *phy_info) 672{ 673 cvmx_helper_link_info_t result; 674 int phy_status; 675 u32 phy_addr = phy_info->phy_addr; 676 677 result.u64 = 0; 678 /* Set to page 0 */ 679 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, 22, 0); 680 /* All the speed information can be read from register 17 in one go. */ 681 phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17); 682 683 /* If the resolve bit 11 isn't set, see if autoneg is turned off 684 * (bit 12, reg 0). The resolve bit doesn't get set properly when 685 * autoneg is off, so force it 686 */ 687 if ((phy_status & (1 << 11)) == 0) { 688 int auto_status = 689 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0); 690 if ((auto_status & (1 << 12)) == 0) 691 phy_status |= 1 << 11; 692 } 693 694 /* Link is up = Speed/Duplex Resolved + RT-Link Up + G-Link Up. */ 695 if ((phy_status & 0x0c08) == 0x0c08) { 696 result.s.link_up = 1; 697 result.s.full_duplex = ((phy_status >> 13) & 1); 698 switch ((phy_status >> 14) & 3) { 699 case 0: /* 10 Mbps */ 700 result.s.speed = 10; 701 break; 702 case 1: /* 100 Mbps */ 703 result.s.speed = 100; 704 break; 705 case 2: /* 1 Gbps */ 706 result.s.speed = 1000; 707 break; 708 case 3: /* Illegal */ 709 result.u64 = 0; 710 break; 711 } 712 } 713 return result; 714} 715 716/** 717 * @INTERNAL 718 * Get link state of broadcom PHY 719 * 720 * @param phy_info PHY information 721 */ 722static cvmx_helper_link_info_t 723__get_broadcom_phy_link_state(cvmx_phy_info_t *phy_info) 724{ 725 cvmx_helper_link_info_t result; 726 u32 phy_addr = phy_info->phy_addr; 727 int phy_status; 728 729 result.u64 = 0; 730 /* Below we are going to read SMI/MDIO register 0x19 which works 731 * on Broadcom parts 732 */ 733 phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19); 734 switch ((phy_status >> 8) & 0x7) { 735 case 0: 736 result.u64 = 0; 737 break; 738 case 1: 739 result.s.link_up = 1; 740 result.s.full_duplex = 0; 741 result.s.speed = 10; 742 break; 743 case 2: 744 result.s.link_up = 1; 745 result.s.full_duplex = 1; 746 result.s.speed = 10; 747 break; 748 case 3: 749 result.s.link_up = 1; 750 result.s.full_duplex = 0; 751 result.s.speed = 100; 752 break; 753 case 4: 754 result.s.link_up = 1; 755 result.s.full_duplex = 1; 756 result.s.speed = 100; 757 break; 758 case 5: 759 result.s.link_up = 1; 760 result.s.full_duplex = 1; 761 result.s.speed = 100; 762 break; 763 case 6: 764 result.s.link_up = 1; 765 result.s.full_duplex = 0; 766 result.s.speed = 1000; 767 break; 768 case 7: 769 result.s.link_up = 1; 770 result.s.full_duplex = 1; 771 result.s.speed = 1000; 772 break; 773 } 774 return result; 775} 776 777/** 778 * @INTERNAL 779 * Get link state of generic gigabit PHY 780 * 781 * @param phy_info - information about the PHY 782 * 783 * @returns link status of the PHY 784 */ 785static cvmx_helper_link_info_t 786__cvmx_get_generic_8023_c22_phy_link_state(cvmx_phy_info_t *phy_info) 787{ 788 cvmx_helper_link_info_t result; 789 u32 phy_addr = phy_info->phy_addr; 790 int phy_basic_control; /* Register 0x0 */ 791 int phy_basic_status; /* Register 0x1 */ 792 int phy_anog_adv; /* Register 0x4 */ 793 int phy_link_part_avail; /* Register 0x5 */ 794 int phy_control; /* Register 0x9 */ 795 int phy_status; /* Register 0xA */ 796 797 result.u64 = 0; 798 799 phy_basic_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 1); 800 if (!(phy_basic_status & 0x4)) /* Check if link is up */ 801 return result; /* Link is down, return link down */ 802 803 result.s.link_up = 1; 804 phy_basic_control = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0); 805 /* Check if autonegotiation is enabled and completed */ 806 if ((phy_basic_control & (1 << 12)) && (phy_basic_status & (1 << 5))) { 807 phy_status = 808 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0xA); 809 phy_control = 810 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x9); 811 812 phy_status &= phy_control << 2; 813 phy_link_part_avail = 814 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x5); 815 phy_anog_adv = 816 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x4); 817 phy_link_part_avail &= phy_anog_adv; 818 819 if (phy_status & 0xC00) { /* Gigabit full or half */ 820 result.s.speed = 1000; 821 result.s.full_duplex = !!(phy_status & 0x800); 822 } else if (phy_link_part_avail & 823 0x0180) { /* 100 full or half */ 824 result.s.speed = 100; 825 result.s.full_duplex = !!(phy_link_part_avail & 0x100); 826 } else if (phy_link_part_avail & 0x0060) { 827 result.s.speed = 10; 828 result.s.full_duplex = !!(phy_link_part_avail & 0x0040); 829 } 830 } else { 831 /* Not autonegotiated */ 832 result.s.full_duplex = !!(phy_basic_control & (1 << 8)); 833 834 if (phy_basic_control & (1 << 6)) 835 result.s.speed = 1000; 836 else if (phy_basic_control & (1 << 13)) 837 result.s.speed = 100; 838 else 839 result.s.speed = 10; 840 } 841 return result; 842} 843 844static cvmx_helper_link_info_t 845__cvmx_get_qualcomm_s17_phy_link_state(cvmx_phy_info_t *phy_info) 846{ 847 cvmx_helper_link_info_t result; 848 u32 phy_addr = phy_info->phy_addr; 849 int phy_status; 850 int auto_status; 851 852 result.u64 = 0; 853 854 phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17); 855 856 /* If bit 11 isn't set see if autonegotiation is turned off 857 * (bit 12, reg 0). The resolved bit doesn't get set properly when 858 * autonegotiation is off, so force it. 859 */ 860 if ((phy_status & (1 << 11)) == 0) { 861 auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0); 862 if ((auto_status & (1 << 12)) == 0) 863 phy_status |= 1 << 11; 864 } 865 /* Only return a link if the PHY has finished autonegotiation and set 866 * the resolved bit (bit 11). 867 */ 868 if (phy_status & (1 << 11)) { 869 result.s.link_up = 1; 870 result.s.full_duplex = !!(phy_status & (1 << 13)); 871 switch ((phy_status >> 14) & 3) { 872 case 0: /* 10Mbps */ 873 result.s.speed = 10; 874 break; 875 case 1: /* 100Mbps */ 876 result.s.speed = 100; 877 break; 878 case 2: /* 1Gbps */ 879 result.s.speed = 1000; 880 break; 881 default: /* Illegal */ 882 result.u64 = 0; 883 break; 884 } 885 } 886 debug(" link: %s, duplex: %s, speed: %lu\n", 887 result.s.link_up ? "up" : "down", 888 result.s.full_duplex ? "full" : "half", 889 (unsigned long)result.s.speed); 890 return result; 891} 892 893static cvmx_helper_link_info_t 894__get_generic_8023_c45_phy_link_state(cvmx_phy_info_t *phy_info) 895{ 896 cvmx_helper_link_info_t result; 897 int phy_status; 898 int pma_ctrl1; 899 u32 phy_addr = phy_info->phy_addr; 900 901 result.u64 = 0; 902 pma_ctrl1 = cvmx_mdio_45_read(phy_addr >> 8, phy_addr & 0xff, 1, 0); 903 if ((pma_ctrl1 & 0x207c) == 0x2040) 904 result.s.speed = 10000; 905 /* PMA Status 1 (1x0001) */ 906 phy_status = cvmx_mdio_45_read(phy_addr >> 8, phy_addr & 0xff, 1, 0xa); 907 if (phy_status < 0) 908 return result; 909 910 result.s.full_duplex = 1; 911 if ((phy_status & 1) == 0) 912 return result; 913 phy_status = cvmx_mdio_45_read(phy_addr >> 8, phy_addr & 0xff, 4, 0x18); 914 if (phy_status < 0) 915 return result; 916 result.s.link_up = (phy_status & 0x1000) ? 1 : 0; 917 918 return result; 919} 920 921static cvmx_helper_link_info_t 922__cvmx_get_cortina_phy_link_state(cvmx_phy_info_t *phy_info) 923{ 924 cvmx_helper_link_info_t result; 925 926 result.s.link_up = 1; 927 result.s.full_duplex = 1; 928 result.s.speed = 1000; 929 return result; 930} 931 932static cvmx_helper_link_info_t 933__get_vitesse_vsc8490_phy_link_state(cvmx_phy_info_t *phy_info) 934{ 935 cvmx_helper_link_info_t result; 936 937 result.s.link_up = 1; 938 result.s.full_duplex = 1; 939 result.s.speed = 1000; 940 return result; 941} 942 943static cvmx_helper_link_info_t 944__get_aquantia_phy_link_state(cvmx_phy_info_t *phy_info) 945{ 946 cvmx_helper_link_info_t result; 947 948 result.s.link_up = 1; 949 result.s.full_duplex = 1; 950 result.s.speed = 1000; 951 return result; 952} 953 954static int __cvmx_helper_78xx_parse_phy(struct cvmx_phy_info *phy_info, 955 int ipd_port) 956{ 957 const void *fdt_addr = CASTPTR(const void *, gd->fdt_blob); 958 const char *compat; 959 int phy; 960 int parent; 961 u64 mdio_base; 962 int node, bus; 963 int phy_addr; 964 int index = cvmx_helper_get_interface_index_num(ipd_port); 965 int xiface = cvmx_helper_get_interface_num(ipd_port); 966 int compat_len = 0; 967 968 debug("%s(0x%p, %d) ENTER\n", __func__, phy_info, ipd_port); 969 970 phy = cvmx_helper_get_phy_fdt_node_offset(xiface, index); 971 debug("%s: xiface: 0x%x, index: %d, ipd_port: %d, phy fdt offset: %d\n", 972 __func__, xiface, index, ipd_port, phy); 973 if (phy < 0) { 974 /* If this is the first time through we need to first parse the 975 * device tree to get the node offsets. 976 */ 977 debug("No config present, calling __cvmx_helper_parse_bgx_dt\n"); 978 if (__cvmx_helper_parse_bgx_dt(fdt_addr)) { 979 printf("Error: could not parse BGX device tree\n"); 980 return -1; 981 } 982 if (__cvmx_fdt_parse_vsc7224(fdt_addr)) { 983 debug("Error: could not parse Microsemi VSC7224 in DT\n"); 984 return -1; 985 } 986 if (octeon_has_feature(OCTEON_FEATURE_BGX_XCV) && 987 __cvmx_helper_parse_bgx_rgmii_dt(fdt_addr)) { 988 printf("Error: could not parse BGX XCV device tree\n"); 989 return -1; 990 } 991 phy = cvmx_helper_get_phy_fdt_node_offset(xiface, index); 992 if (phy < 0) { 993 debug("%s: Could not get PHY node offset for IPD port 0x%x, xiface: 0x%x, index: %d\n", 994 __func__, ipd_port, xiface, index); 995 return -1; 996 } 997 debug("%s: phy: %d (%s)\n", __func__, phy, 998 fdt_get_name(fdt_addr, phy, NULL)); 999 } 1000 1001 compat = (const char *)fdt_getprop(fdt_addr, phy, "compatible", 1002 &compat_len); 1003 if (!compat) { 1004 printf("ERROR: %d:%d:no compatible prop in phy\n", xiface, 1005 index); 1006 return -1; 1007 } 1008 1009 debug(" compatible: %s\n", compat); 1010 1011 phy_info->fdt_offset = phy; 1012 phy_addr = cvmx_fdt_get_int(fdt_addr, phy, "reg", -1); 1013 if (phy_addr == -1) { 1014 printf("Error: %d:%d:could not get PHY address\n", xiface, 1015 index); 1016 return -1; 1017 } 1018 debug(" PHY address: %d, compat: %s\n", phy_addr, compat); 1019 1020 if (!memcmp("marvell", compat, strlen("marvell"))) { 1021 phy_info->phy_type = MARVELL_GENERIC_PHY; 1022 phy_info->link_function = __get_marvell_phy_link_state; 1023 } else if (!memcmp("broadcom", compat, strlen("broadcom"))) { 1024 phy_info->phy_type = BROADCOM_GENERIC_PHY; 1025 phy_info->link_function = __get_broadcom_phy_link_state; 1026 } else if (!memcmp("cortina", compat, strlen("cortina"))) { 1027 phy_info->phy_type = CORTINA_PHY; 1028 phy_info->link_function = __cvmx_get_cortina_phy_link_state; 1029 } else if (!strcmp("vitesse,vsc8490", compat)) { 1030 phy_info->phy_type = VITESSE_VSC8490_PHY; 1031 phy_info->link_function = __get_vitesse_vsc8490_phy_link_state; 1032 } else if (fdt_stringlist_contains(compat, compat_len, 1033 "ethernet-phy-ieee802.3-c22")) { 1034 phy_info->phy_type = GENERIC_8023_C22_PHY; 1035 phy_info->link_function = 1036 __cvmx_get_generic_8023_c22_phy_link_state; 1037 } else if (fdt_stringlist_contains(compat, compat_len, 1038 "ethernet-phy-ieee802.3-c45")) { 1039 phy_info->phy_type = GENERIC_8023_C22_PHY; 1040 phy_info->link_function = __get_generic_8023_c45_phy_link_state; 1041 } 1042 1043 phy_info->ipd_port = ipd_port; 1044 phy_info->phy_sub_addr = 0; 1045 phy_info->direct_connect = 1; 1046 1047 parent = fdt_parent_offset(fdt_addr, phy); 1048 if (!fdt_node_check_compatible(fdt_addr, parent, 1049 "ethernet-phy-nexus")) { 1050 debug(" nexus PHY found\n"); 1051 if (phy_info->phy_type == CORTINA_PHY) { 1052 /* The Cortina CS422X uses the same PHY device for 1053 * multiple ports for XFI. In this case we use a 1054 * nexus and each PHY address is the slice or 1055 * sub-address and the actual PHY address is the 1056 * nexus address. 1057 */ 1058 phy_info->phy_sub_addr = phy_addr; 1059 phy_addr = 1060 cvmx_fdt_get_int(fdt_addr, parent, "reg", -1); 1061 debug(" Cortina PHY real address: 0x%x\n", phy_addr); 1062 } 1063 parent = fdt_parent_offset(fdt_addr, parent); 1064 } 1065 1066 debug(" Parent: %s\n", fdt_get_name(fdt_addr, parent, NULL)); 1067 if (!fdt_node_check_compatible(fdt_addr, parent, 1068 "cavium,octeon-3860-mdio")) { 1069 debug(" Found Octeon MDIO\n"); 1070 mdio_base = cvmx_fdt_get_uint64(fdt_addr, parent, "reg", 1071 FDT_ADDR_T_NONE); 1072 debug(" MDIO address: 0x%llx\n", 1073 (unsigned long long)mdio_base); 1074 1075 mdio_base = cvmx_fdt_translate_address(fdt_addr, parent, 1076 (u32 *)&mdio_base); 1077 debug(" Translated: 0x%llx\n", (unsigned long long)mdio_base); 1078 if (mdio_base == FDT_ADDR_T_NONE) { 1079 printf("Could not get MDIO base address from reg field\n"); 1080 return -1; 1081 } 1082 __cvmx_mdio_addr_to_node_bus(mdio_base, &node, &bus); 1083 if (bus < 0) { 1084 printf("Invalid MDIO address 0x%llx, could not detect bus and node\n", 1085 (unsigned long long)mdio_base); 1086 return -1; 1087 } 1088 debug(" MDIO node: %d, bus: %d\n", node, bus); 1089 phy_info->mdio_unit = (node << 2) | (bus & 3); 1090 phy_info->phy_addr = phy_addr | (phy_info->mdio_unit << 8); 1091 } else { 1092 printf("%s: Error: incompatible MDIO bus %s for IPD port %d\n", 1093 __func__, 1094 (const char *)fdt_get_name(fdt_addr, parent, NULL), 1095 ipd_port); 1096 return -1; 1097 } 1098 1099 debug("%s: EXIT 0\n", __func__); 1100 1101 return 0; 1102} 1103 1104/** 1105 * Return the MII PHY address associated with the given IPD 1106 * port. The phy address is obtained from the device tree. 1107 * 1108 * @param[out] phy_info - PHY information data structure updated 1109 * @param ipd_port Octeon IPD port to get the MII address for. 1110 * 1111 * @return MII PHY address and bus number, -1 on error, -2 if PHY info missing (OK). 1112 */ 1113static int __get_phy_info_from_dt(cvmx_phy_info_t *phy_info, int ipd_port) 1114{ 1115 const void *fdt_addr = CASTPTR(const void *, gd->fdt_blob); 1116 int aliases, eth, phy, phy_parent, ret, i; 1117 int mdio_parent; 1118 const char *phy_compatible_str; 1119 const char *host_mode_str = NULL; 1120 int interface; 1121 int phy_addr_offset = 0; 1122 1123 debug("%s(%p, %d)\n", __func__, phy_info, ipd_port); 1124 1125 if (octeon_has_feature(OCTEON_FEATURE_BGX)) 1126 return __cvmx_helper_78xx_parse_phy(phy_info, ipd_port); 1127 1128 phy_info->phy_addr = -1; 1129 phy_info->phy_sub_addr = 0; 1130 phy_info->ipd_port = ipd_port; 1131 phy_info->direct_connect = -1; 1132 phy_info->phy_type = (cvmx_phy_type_t)-1; 1133 for (i = 0; i < CVMX_PHY_MUX_MAX_GPIO; i++) 1134 phy_info->gpio[i] = -1; 1135 phy_info->mdio_unit = -1; 1136 phy_info->gpio_value = -1; 1137 phy_info->gpio_parent_mux_twsi = -1; 1138 phy_info->gpio_parent_mux_select = -1; 1139 phy_info->link_function = NULL; 1140 phy_info->fdt_offset = -1; 1141 if (!fdt_addr) { 1142 debug("No device tree found.\n"); 1143 return -1; 1144 } 1145 1146 aliases = fdt_path_offset(fdt_addr, "/aliases"); 1147 if (aliases < 0) { 1148 debug("Error: No /aliases node in device tree.\n"); 1149 return -1; 1150 } 1151 if (ipd_port < 0) { 1152 int interface_index = 1153 ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT; 1154 eth = __mix_eth_node(fdt_addr, aliases, interface_index); 1155 } else { 1156 eth = __pip_eth_node(fdt_addr, aliases, ipd_port); 1157 } 1158 if (eth < 0) { 1159 debug("ERROR : cannot find interface for ipd_port=%d\n", 1160 ipd_port); 1161 return -1; 1162 } 1163 1164 interface = cvmx_helper_get_interface_num(ipd_port); 1165 /* Get handle to phy */ 1166 phy = cvmx_fdt_lookup_phandle(fdt_addr, eth, "phy-handle"); 1167 if (phy < 0) { 1168 cvmx_helper_interface_mode_t if_mode; 1169 1170 /* Note that it's OK for RXAUI and ILK to not have a PHY 1171 * connected (i.e. EBB boards in loopback). 1172 */ 1173 debug("Cannot get phy-handle for ipd_port: %d\n", ipd_port); 1174 if_mode = cvmx_helper_interface_get_mode(interface); 1175 if (if_mode != CVMX_HELPER_INTERFACE_MODE_RXAUI && 1176 if_mode != CVMX_HELPER_INTERFACE_MODE_ILK) { 1177 debug("ERROR : phy handle not found in device tree ipd_port=%d\n", 1178 ipd_port); 1179 return -1; 1180 } else { 1181 return -2; 1182 } 1183 } 1184 1185 phy_compatible_str = 1186 (const char *)fdt_getprop(fdt_addr, phy, "compatible", NULL); 1187 if (!phy_compatible_str) { 1188 debug("ERROR: no compatible prop in phy\n"); 1189 return -1; 1190 } 1191 debug("Checking compatible string \"%s\" for ipd port %d\n", 1192 phy_compatible_str, ipd_port); 1193 phy_info->fdt_offset = phy; 1194 if (!memcmp("marvell", phy_compatible_str, strlen("marvell"))) { 1195 debug("Marvell PHY detected for ipd_port %d\n", ipd_port); 1196 phy_info->phy_type = MARVELL_GENERIC_PHY; 1197 phy_info->link_function = __get_marvell_phy_link_state; 1198 } else if (!memcmp("broadcom", phy_compatible_str, 1199 strlen("broadcom"))) { 1200 phy_info->phy_type = BROADCOM_GENERIC_PHY; 1201 phy_info->link_function = __get_broadcom_phy_link_state; 1202 debug("Broadcom PHY detected for ipd_port %d\n", ipd_port); 1203 } else if (!memcmp("vitesse", phy_compatible_str, strlen("vitesse"))) { 1204 debug("Vitesse PHY detected for ipd_port %d\n", ipd_port); 1205 if (!fdt_node_check_compatible(fdt_addr, phy, 1206 "vitesse,vsc8490")) { 1207 phy_info->phy_type = VITESSE_VSC8490_PHY; 1208 debug("Vitesse VSC8490 detected\n"); 1209 phy_info->link_function = 1210 __get_vitesse_vsc8490_phy_link_state; 1211 } else if (!fdt_node_check_compatible( 1212 fdt_addr, phy, 1213 "ethernet-phy-ieee802.3-c22")) { 1214 phy_info->phy_type = GENERIC_8023_C22_PHY; 1215 phy_info->link_function = 1216 __cvmx_get_generic_8023_c22_phy_link_state; 1217 debug("Vitesse 802.3 c22 detected\n"); 1218 } else { 1219 phy_info->phy_type = GENERIC_8023_C45_PHY; 1220 phy_info->link_function = 1221 __get_generic_8023_c45_phy_link_state; 1222 debug("Vitesse 802.3 c45 detected\n"); 1223 } 1224 } else if (!memcmp("aquantia", phy_compatible_str, 1225 strlen("aquantia"))) { 1226 phy_info->phy_type = AQUANTIA_PHY; 1227 phy_info->link_function = __get_aquantia_phy_link_state; 1228 debug("Aquantia c45 PHY detected\n"); 1229 } else if (!memcmp("cortina", phy_compatible_str, strlen("cortina"))) { 1230 phy_info->phy_type = CORTINA_PHY; 1231 phy_info->link_function = __cvmx_get_cortina_phy_link_state; 1232 host_mode_str = (const char *)fdt_getprop( 1233 fdt_addr, phy, "cortina,host-mode", NULL); 1234 debug("Cortina PHY detected for ipd_port %d\n", ipd_port); 1235 } else if (!memcmp("ti", phy_compatible_str, strlen("ti"))) { 1236 phy_info->phy_type = GENERIC_8023_C45_PHY; 1237 phy_info->link_function = __get_generic_8023_c45_phy_link_state; 1238 debug("TI PHY detected for ipd_port %d\n", ipd_port); 1239 } else if (!fdt_node_check_compatible(fdt_addr, phy, 1240 "atheros,ar8334") || 1241 !fdt_node_check_compatible(fdt_addr, phy, 1242 "qualcomm,qca8334") || 1243 !fdt_node_check_compatible(fdt_addr, phy, 1244 "atheros,ar8337") || 1245 !fdt_node_check_compatible(fdt_addr, phy, 1246 "qualcomm,qca8337")) { 1247 phy_info->phy_type = QUALCOMM_S17; 1248 phy_info->link_function = 1249 __cvmx_get_qualcomm_s17_phy_link_state; 1250 debug("Qualcomm QCA833X switch detected\n"); 1251 } else if (!fdt_node_check_compatible(fdt_addr, phy, 1252 "ethernet-phy-ieee802.3-c22")) { 1253 phy_info->phy_type = GENERIC_8023_C22_PHY; 1254 phy_info->link_function = 1255 __cvmx_get_generic_8023_c22_phy_link_state; 1256 debug("Generic 802.3 c22 PHY detected\n"); 1257 } else if (!fdt_node_check_compatible(fdt_addr, phy, 1258 "ethernet-phy-ieee802.3-c45")) { 1259 phy_info->phy_type = GENERIC_8023_C45_PHY; 1260 phy_info->link_function = __get_generic_8023_c45_phy_link_state; 1261 debug("Generic 802.3 c45 PHY detected\n"); 1262 } else { 1263 debug("Unknown PHY compatibility\n"); 1264 phy_info->phy_type = (cvmx_phy_type_t)-1; 1265 phy_info->link_function = NULL; 1266 } 1267 1268 phy_info->host_mode = CVMX_PHY_HOST_MODE_UNKNOWN; 1269 if (host_mode_str) { 1270 if (strcmp(host_mode_str, "rxaui") == 0) 1271 phy_info->host_mode = CVMX_PHY_HOST_MODE_RXAUI; 1272 else if (strcmp(host_mode_str, "xaui") == 0) 1273 phy_info->host_mode = CVMX_PHY_HOST_MODE_XAUI; 1274 else if (strcmp(host_mode_str, "sgmii") == 0) 1275 phy_info->host_mode = CVMX_PHY_HOST_MODE_SGMII; 1276 else if (strcmp(host_mode_str, "qsgmii") == 0) 1277 phy_info->host_mode = CVMX_PHY_HOST_MODE_QSGMII; 1278 else 1279 debug("Unknown PHY host mode\n"); 1280 } 1281 1282 /* Check if PHY parent is the octeon MDIO bus. Some boards are connected 1283 * though a MUX and for them direct_connect_to_phy will be 0 1284 */ 1285 phy_parent = fdt_parent_offset(fdt_addr, phy); 1286 if (phy_parent < 0) { 1287 debug("ERROR : cannot find phy parent for ipd_port=%d ret=%d\n", 1288 ipd_port, phy_parent); 1289 return -1; 1290 } 1291 /* For multi-phy devices and devices on a MUX, go to the parent */ 1292 ret = fdt_node_check_compatible(fdt_addr, phy_parent, 1293 "ethernet-phy-nexus"); 1294 if (ret == 0) { 1295 /* It's a nexus so check the grandparent. */ 1296 phy_addr_offset = 1297 cvmx_fdt_get_int(fdt_addr, phy_parent, "reg", 0); 1298 phy_parent = fdt_parent_offset(fdt_addr, phy_parent); 1299 } 1300 1301 /* Check for a muxed MDIO interface */ 1302 mdio_parent = fdt_parent_offset(fdt_addr, phy_parent); 1303 ret = fdt_node_check_compatible(fdt_addr, mdio_parent, 1304 "cavium,mdio-mux"); 1305 if (ret == 0) { 1306 ret = __get_muxed_mdio_info_from_dt(phy_info, phy_parent, 1307 mdio_parent); 1308 if (ret) { 1309 printf("Error reading mdio mux information for ipd port %d\n", 1310 ipd_port); 1311 return -1; 1312 } 1313 } 1314 ret = fdt_node_check_compatible(fdt_addr, phy_parent, 1315 "cavium,octeon-3860-mdio"); 1316 if (ret == 0) { 1317 u32 *mdio_reg_base = 1318 (u32 *)fdt_getprop(fdt_addr, phy_parent, "reg", 0); 1319 phy_info->direct_connect = 1; 1320 if (mdio_reg_base == 0) { 1321 debug("ERROR : unable to get reg property in phy mdio\n"); 1322 return -1; 1323 } 1324 phy_info->mdio_unit = 1325 __mdiobus_addr_to_unit(fdt32_to_cpu(mdio_reg_base[1])); 1326 debug("phy parent=%s reg_base=%08x mdio_unit=%d\n", 1327 fdt_get_name(fdt_addr, phy_parent, NULL), 1328 (int)mdio_reg_base[1], phy_info->mdio_unit); 1329 } else { 1330 phy_info->direct_connect = 0; 1331 /* The PHY is not directly connected to the Octeon MDIO bus. 1332 * SE doesn't have abstractions for MDIO MUX or MDIO MUX 1333 * drivers and hence for the non direct cases code will be 1334 * needed which is board specific. 1335 * For now the MDIO Unit is defaulted to 1. 1336 */ 1337 debug("%s PHY at address: %d is not directly connected\n", 1338 __func__, phy_info->phy_addr); 1339 } 1340 1341 phy_info->phy_addr = cvmx_fdt_get_int(fdt_addr, phy, "reg", -1); 1342 if (phy_info->phy_addr < 0) { 1343 debug("ERROR: Could not read phy address from reg in DT\n"); 1344 return -1; 1345 } 1346 phy_info->phy_addr += phy_addr_offset; 1347 phy_info->phy_addr |= phy_info->mdio_unit << 8; 1348 debug("%s(%p, %d) => 0x%x\n", __func__, phy_info, ipd_port, 1349 phy_info->phy_addr); 1350 return phy_info->phy_addr; 1351} 1352 1353/** 1354 * @INTERNAL 1355 * Parse the device tree and set whether a port is valid or not. 1356 * 1357 * @param fdt_addr Pointer to device tree 1358 * 1359 * @return 0 for success, -1 on error. 1360 */ 1361int __cvmx_helper_parse_bgx_dt(const void *fdt_addr) 1362{ 1363 int port_index; 1364 struct cvmx_xiface xi; 1365 int fdt_port_node = -1; 1366 int fdt_interface_node; 1367 int fdt_phy_node; 1368 u64 reg_addr; 1369 int xiface; 1370 struct cvmx_phy_info *phy_info; 1371 static bool parsed; 1372 int err; 1373 int ipd_port; 1374 1375 if (parsed) { 1376 debug("%s: Already parsed\n", __func__); 1377 return 0; 1378 } 1379 while ((fdt_port_node = fdt_node_offset_by_compatible( 1380 fdt_addr, fdt_port_node, 1381 "cavium,octeon-7890-bgx-port")) >= 0) { 1382 /* Get the port number */ 1383 port_index = 1384 cvmx_fdt_get_int(fdt_addr, fdt_port_node, "reg", -1); 1385 if (port_index < 0) { 1386 debug("Error: missing reg field for bgx port in device tree\n"); 1387 return -1; 1388 } 1389 debug("%s: Parsing BGX port %d\n", __func__, port_index); 1390 /* Get the interface number */ 1391 fdt_interface_node = fdt_parent_offset(fdt_addr, fdt_port_node); 1392 if (fdt_interface_node < 0) { 1393 debug("Error: device tree corrupt!\n"); 1394 return -1; 1395 } 1396 if (fdt_node_check_compatible(fdt_addr, fdt_interface_node, 1397 "cavium,octeon-7890-bgx")) { 1398 debug("Error: incompatible Ethernet MAC Nexus in device tree!\n"); 1399 return -1; 1400 } 1401 reg_addr = 1402 cvmx_fdt_get_addr(fdt_addr, fdt_interface_node, "reg"); 1403 debug("%s: BGX interface address: 0x%llx\n", __func__, 1404 (unsigned long long)reg_addr); 1405 if (reg_addr == FDT_ADDR_T_NONE) { 1406 debug("Device tree BGX node has invalid address 0x%llx\n", 1407 (unsigned long long)reg_addr); 1408 return -1; 1409 } 1410 reg_addr = cvmx_fdt_translate_address(fdt_addr, 1411 fdt_interface_node, 1412 (u32 *)®_addr); 1413 xi = __cvmx_bgx_reg_addr_to_xiface(reg_addr); 1414 if (xi.node < 0) { 1415 debug("Device tree BGX node has invalid address 0x%llx\n", 1416 (unsigned long long)reg_addr); 1417 return -1; 1418 } 1419 debug("%s: Found BGX node %d, interface %d\n", __func__, 1420 xi.node, xi.interface); 1421 xiface = cvmx_helper_node_interface_to_xiface(xi.node, 1422 xi.interface); 1423 cvmx_helper_set_port_fdt_node_offset(xiface, port_index, 1424 fdt_port_node); 1425 cvmx_helper_set_port_valid(xiface, port_index, true); 1426 1427 cvmx_helper_set_port_fdt_node_offset(xiface, port_index, 1428 fdt_port_node); 1429 if (fdt_getprop(fdt_addr, fdt_port_node, 1430 "cavium,sgmii-mac-phy-mode", NULL)) 1431 cvmx_helper_set_mac_phy_mode(xiface, port_index, true); 1432 else 1433 cvmx_helper_set_mac_phy_mode(xiface, port_index, false); 1434 1435 if (fdt_getprop(fdt_addr, fdt_port_node, "cavium,force-link-up", 1436 NULL)) 1437 cvmx_helper_set_port_force_link_up(xiface, port_index, 1438 true); 1439 else 1440 cvmx_helper_set_port_force_link_up(xiface, port_index, 1441 false); 1442 1443 if (fdt_getprop(fdt_addr, fdt_port_node, 1444 "cavium,sgmii-mac-1000x-mode", NULL)) 1445 cvmx_helper_set_1000x_mode(xiface, port_index, true); 1446 else 1447 cvmx_helper_set_1000x_mode(xiface, port_index, false); 1448 1449 if (fdt_getprop(fdt_addr, fdt_port_node, 1450 "cavium,disable-autonegotiation", NULL)) 1451 cvmx_helper_set_port_autonegotiation(xiface, port_index, 1452 false); 1453 else 1454 cvmx_helper_set_port_autonegotiation(xiface, port_index, 1455 true); 1456 1457 fdt_phy_node = cvmx_fdt_lookup_phandle(fdt_addr, fdt_port_node, 1458 "phy-handle"); 1459 if (fdt_phy_node >= 0) { 1460 cvmx_helper_set_phy_fdt_node_offset(xiface, port_index, 1461 fdt_phy_node); 1462 debug("%s: Setting PHY fdt node offset for interface 0x%x, port %d to %d\n", 1463 __func__, xiface, port_index, fdt_phy_node); 1464 debug("%s: PHY node name: %s\n", __func__, 1465 fdt_get_name(fdt_addr, fdt_phy_node, NULL)); 1466 cvmx_helper_set_port_phy_present(xiface, port_index, 1467 true); 1468 ipd_port = cvmx_helper_get_ipd_port(xiface, port_index); 1469 if (ipd_port >= 0) { 1470 debug("%s: Allocating phy info for 0x%x:%d\n", 1471 __func__, xiface, port_index); 1472 phy_info = 1473 (cvmx_phy_info_t *)cvmx_bootmem_alloc( 1474 sizeof(*phy_info), 0); 1475 if (!phy_info) { 1476 debug("%s: Out of memory\n", __func__); 1477 return -1; 1478 } 1479 memset(phy_info, 0, sizeof(*phy_info)); 1480 phy_info->phy_addr = -1; 1481 err = __get_phy_info_from_dt(phy_info, 1482 ipd_port); 1483 if (err) { 1484 debug("%s: Error parsing phy info for ipd port %d\n", 1485 __func__, ipd_port); 1486 return -1; 1487 } 1488 cvmx_helper_set_port_phy_info( 1489 xiface, port_index, phy_info); 1490 debug("%s: Saved phy info\n", __func__); 1491 } 1492 } else { 1493 cvmx_helper_set_phy_fdt_node_offset(xiface, port_index, 1494 -1); 1495 debug("%s: No PHY fdt node offset for interface 0x%x, port %d to %d\n", 1496 __func__, xiface, port_index, fdt_phy_node); 1497 cvmx_helper_set_port_phy_present(xiface, port_index, 1498 false); 1499 } 1500 } 1501 if (!sfp_parsed) 1502 if (cvmx_sfp_parse_device_tree(fdt_addr)) 1503 debug("%s: Error parsing SFP device tree\n", __func__); 1504 parsed = true; 1505 return 0; 1506} 1507 1508int __cvmx_helper_parse_bgx_rgmii_dt(const void *fdt_addr) 1509{ 1510 u64 reg_addr; 1511 struct cvmx_xiface xi; 1512 int fdt_port_node = -1; 1513 int fdt_interface_node; 1514 int fdt_phy_node; 1515 int port_index; 1516 int xiface; 1517 1518 /* There's only one xcv (RGMII) interface, so just search for the one 1519 * that's part of a BGX entry. 1520 */ 1521 while ((fdt_port_node = fdt_node_offset_by_compatible( 1522 fdt_addr, fdt_port_node, "cavium,octeon-7360-xcv")) >= 1523 0) { 1524 fdt_interface_node = fdt_parent_offset(fdt_addr, fdt_port_node); 1525 if (fdt_interface_node < 0) { 1526 printf("Error: device tree corrupt!\n"); 1527 return -1; 1528 } 1529 debug("%s: XCV parent node compatible: %s\n", __func__, 1530 (char *)fdt_getprop(fdt_addr, fdt_interface_node, 1531 "compatible", NULL)); 1532 if (!fdt_node_check_compatible(fdt_addr, fdt_interface_node, 1533 "cavium,octeon-7890-bgx")) 1534 break; 1535 } 1536 if (fdt_port_node == -FDT_ERR_NOTFOUND) { 1537 debug("No XCV/RGMII interface found in device tree\n"); 1538 return 0; 1539 } else if (fdt_port_node < 0) { 1540 debug("%s: Error %d parsing device tree\n", __func__, 1541 fdt_port_node); 1542 return -1; 1543 } 1544 port_index = cvmx_fdt_get_int(fdt_addr, fdt_port_node, "reg", -1); 1545 if (port_index != 0) { 1546 printf("%s: Error: port index (reg) must be 0, not %d.\n", 1547 __func__, port_index); 1548 return -1; 1549 } 1550 reg_addr = cvmx_fdt_get_addr(fdt_addr, fdt_interface_node, "reg"); 1551 if (reg_addr == FDT_ADDR_T_NONE) { 1552 printf("%s: Error: could not get BGX interface address\n", 1553 __func__); 1554 return -1; 1555 } 1556 /* We don't have to bother translating since only 78xx supports OCX and 1557 * doesn't support RGMII. 1558 */ 1559 xi = __cvmx_bgx_reg_addr_to_xiface(reg_addr); 1560 debug("%s: xi.node: %d, xi.interface: 0x%x, addr: 0x%llx\n", __func__, 1561 xi.node, xi.interface, (unsigned long long)reg_addr); 1562 if (xi.node < 0) { 1563 printf("%s: Device tree BGX node has invalid address 0x%llx\n", 1564 __func__, (unsigned long long)reg_addr); 1565 return -1; 1566 } 1567 debug("%s: Found XCV (RGMII) interface on interface %d\n", __func__, 1568 xi.interface); 1569 debug(" phy handle: 0x%x\n", 1570 cvmx_fdt_get_int(fdt_addr, fdt_port_node, "phy-handle", -1)); 1571 fdt_phy_node = 1572 cvmx_fdt_lookup_phandle(fdt_addr, fdt_port_node, "phy-handle"); 1573 debug("%s: phy-handle node: 0x%x\n", __func__, fdt_phy_node); 1574 xiface = cvmx_helper_node_interface_to_xiface(xi.node, xi.interface); 1575 1576 cvmx_helper_set_port_fdt_node_offset(xiface, port_index, fdt_port_node); 1577 if (fdt_phy_node >= 0) { 1578 debug("%s: Setting PHY fdt node offset for interface 0x%x, port %d to %d\n", 1579 __func__, xiface, port_index, fdt_phy_node); 1580 debug("%s: PHY node name: %s\n", __func__, 1581 fdt_get_name(fdt_addr, fdt_phy_node, NULL)); 1582 cvmx_helper_set_phy_fdt_node_offset(xiface, port_index, 1583 fdt_phy_node); 1584 cvmx_helper_set_port_phy_present(xiface, port_index, true); 1585 } else { 1586 cvmx_helper_set_phy_fdt_node_offset(xiface, port_index, -1); 1587 debug("%s: No PHY fdt node offset for interface 0x%x, port %d to %d\n", 1588 __func__, xiface, port_index, fdt_phy_node); 1589 cvmx_helper_set_port_phy_present(xiface, port_index, false); 1590 } 1591 1592 return 0; 1593} 1594 1595/** 1596 * Returns if a port is present on an interface 1597 * 1598 * @param fdt_addr - address fo flat device tree 1599 * @param ipd_port - IPD port number 1600 * 1601 * @return 1 if port is present, 0 if not present, -1 if error 1602 */ 1603int __cvmx_helper_board_get_port_from_dt(void *fdt_addr, int ipd_port) 1604{ 1605 int port_index; 1606 int aliases; 1607 const char *pip_path; 1608 char name_buffer[24]; 1609 int pip, iface, eth; 1610 cvmx_helper_interface_mode_t mode; 1611 int xiface = cvmx_helper_get_interface_num(ipd_port); 1612 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 1613 u32 val; 1614 int phy_node_offset; 1615 int parse_bgx_dt_err; 1616 int parse_vsc7224_err; 1617 1618 debug("%s(%p, %d)\n", __func__, fdt_addr, ipd_port); 1619 if (octeon_has_feature(OCTEON_FEATURE_BGX)) { 1620 static int fdt_ports_initialized; 1621 1622 port_index = cvmx_helper_get_interface_index_num(ipd_port); 1623 1624 if (!fdt_ports_initialized) { 1625 if (octeon_has_feature(OCTEON_FEATURE_BGX_XCV)) { 1626 if (!__cvmx_helper_parse_bgx_rgmii_dt(fdt_addr)) 1627 fdt_ports_initialized = 1; 1628 parse_bgx_dt_err = 1629 __cvmx_helper_parse_bgx_dt(fdt_addr); 1630 parse_vsc7224_err = 1631 __cvmx_fdt_parse_vsc7224(fdt_addr); 1632 if (!parse_bgx_dt_err && !parse_vsc7224_err) 1633 fdt_ports_initialized = 1; 1634 } else { 1635 debug("%s: Error parsing FDT\n", __func__); 1636 return -1; 1637 } 1638 } 1639 1640 return cvmx_helper_is_port_valid(xiface, port_index); 1641 } 1642 1643 mode = cvmx_helper_interface_get_mode(xiface); 1644 1645 switch (mode) { 1646 /* Device tree has information about the following mode types. */ 1647 case CVMX_HELPER_INTERFACE_MODE_RGMII: 1648 case CVMX_HELPER_INTERFACE_MODE_GMII: 1649 case CVMX_HELPER_INTERFACE_MODE_SPI: 1650 case CVMX_HELPER_INTERFACE_MODE_XAUI: 1651 case CVMX_HELPER_INTERFACE_MODE_SGMII: 1652 case CVMX_HELPER_INTERFACE_MODE_QSGMII: 1653 case CVMX_HELPER_INTERFACE_MODE_RXAUI: 1654 case CVMX_HELPER_INTERFACE_MODE_AGL: 1655 case CVMX_HELPER_INTERFACE_MODE_XLAUI: 1656 case CVMX_HELPER_INTERFACE_MODE_XFI: 1657 aliases = 1; 1658 break; 1659 default: 1660 aliases = 0; 1661 break; 1662 } 1663 1664 /* The device tree information is present on interfaces that have phy */ 1665 if (!aliases) 1666 return 1; 1667 1668 port_index = cvmx_helper_get_interface_index_num(ipd_port); 1669 1670 aliases = fdt_path_offset(fdt_addr, "/aliases"); 1671 if (aliases < 0) { 1672 debug("%s: ERROR: /aliases not found in device tree fdt_addr=%p\n", 1673 __func__, fdt_addr); 1674 return -1; 1675 } 1676 1677 pip_path = (const char *)fdt_getprop(fdt_addr, aliases, "pip", NULL); 1678 if (!pip_path) { 1679 debug("%s: ERROR: interface %x pip path not found in device tree\n", 1680 __func__, xiface); 1681 return -1; 1682 } 1683 pip = fdt_path_offset(fdt_addr, pip_path); 1684 if (pip < 0) { 1685 debug("%s: ERROR: interface %x pip not found in device tree\n", 1686 __func__, xiface); 1687 return -1; 1688 } 1689 snprintf(name_buffer, sizeof(name_buffer), "interface@%d", 1690 xi.interface); 1691 iface = fdt_subnode_offset(fdt_addr, pip, name_buffer); 1692 if (iface < 0) 1693 return 0; 1694 snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", port_index); 1695 eth = fdt_subnode_offset(fdt_addr, iface, name_buffer); 1696 debug("%s: eth subnode offset %d from %s\n", __func__, eth, 1697 name_buffer); 1698 1699 if (eth < 0) 1700 return -1; 1701 1702 cvmx_helper_set_port_fdt_node_offset(xiface, port_index, eth); 1703 1704 phy_node_offset = cvmx_fdt_get_int(fdt_addr, eth, "phy", -1); 1705 cvmx_helper_set_phy_fdt_node_offset(xiface, port_index, 1706 phy_node_offset); 1707 1708 if (fdt_getprop(fdt_addr, eth, "cavium,sgmii-mac-phy-mode", NULL)) 1709 cvmx_helper_set_mac_phy_mode(xiface, port_index, true); 1710 else 1711 cvmx_helper_set_mac_phy_mode(xiface, port_index, false); 1712 1713 if (fdt_getprop(fdt_addr, eth, "cavium,force-link-up", NULL)) 1714 cvmx_helper_set_port_force_link_up(xiface, port_index, true); 1715 else 1716 cvmx_helper_set_port_force_link_up(xiface, port_index, false); 1717 1718 if (fdt_getprop(fdt_addr, eth, "cavium,sgmii-mac-1000x-mode", NULL)) 1719 cvmx_helper_set_1000x_mode(xiface, port_index, true); 1720 else 1721 cvmx_helper_set_1000x_mode(xiface, port_index, false); 1722 1723 if (fdt_getprop(fdt_addr, eth, "cavium,disable-autonegotiation", NULL)) 1724 cvmx_helper_set_port_autonegotiation(xiface, port_index, false); 1725 else 1726 cvmx_helper_set_port_autonegotiation(xiface, port_index, true); 1727 1728 if (mode == CVMX_HELPER_INTERFACE_MODE_AGL) { 1729 bool tx_bypass = false; 1730 1731 if (fdt_getprop(fdt_addr, eth, "cavium,rx-clk-delay-bypass", 1732 NULL)) 1733 cvmx_helper_set_agl_rx_clock_delay_bypass( 1734 xiface, port_index, true); 1735 else 1736 cvmx_helper_set_agl_rx_clock_delay_bypass( 1737 xiface, port_index, false); 1738 1739 val = cvmx_fdt_get_int(fdt_addr, eth, "cavium,rx-clk-skew", 0); 1740 cvmx_helper_set_agl_rx_clock_skew(xiface, port_index, val); 1741 1742 if (fdt_getprop(fdt_addr, eth, "cavium,tx-clk-delay-bypass", 1743 NULL)) 1744 tx_bypass = true; 1745 1746 val = cvmx_fdt_get_int(fdt_addr, eth, "tx-clk-delay", 0); 1747 cvmx_helper_cfg_set_rgmii_tx_clk_delay(xiface, port_index, 1748 tx_bypass, val); 1749 1750 val = cvmx_fdt_get_int(fdt_addr, eth, "cavium,refclk-sel", 0); 1751 cvmx_helper_set_agl_refclk_sel(xiface, port_index, val); 1752 } 1753 1754 return (eth >= 0); 1755} 1756 1757/** 1758 * Given the address of the MDIO registers, output the CPU node and MDIO bus 1759 * 1760 * @param addr 64-bit address of MDIO registers (from device tree) 1761 * @param[out] node CPU node number (78xx) 1762 * @param[out] bus MDIO bus number 1763 */ 1764void __cvmx_mdio_addr_to_node_bus(u64 addr, int *node, int *bus) 1765{ 1766 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) { 1767 if (node) 1768 *node = cvmx_csr_addr_to_node(addr); 1769 addr = cvmx_csr_addr_strip_node(addr); 1770 } else { 1771 if (node) 1772 *node = 0; 1773 } 1774 if (OCTEON_IS_MODEL(OCTEON_CN68XX) || OCTEON_IS_MODEL(OCTEON_CN78XX)) { 1775 switch (addr) { 1776 case 0x0001180000003800: 1777 *bus = 0; 1778 break; 1779 case 0x0001180000003880: 1780 *bus = 1; 1781 break; 1782 case 0x0001180000003900: 1783 *bus = 2; 1784 break; 1785 case 0x0001180000003980: 1786 *bus = 3; 1787 break; 1788 default: 1789 *bus = -1; 1790 printf("%s: Invalid SMI bus address 0x%llx\n", __func__, 1791 (unsigned long long)addr); 1792 break; 1793 } 1794 } else if (OCTEON_IS_MODEL(OCTEON_CN73XX) || 1795 OCTEON_IS_MODEL(OCTEON_CNF75XX)) { 1796 switch (addr) { 1797 case 0x0001180000003800: 1798 *bus = 0; 1799 break; 1800 case 0x0001180000003880: 1801 *bus = 1; 1802 break; 1803 default: 1804 *bus = -1; 1805 printf("%s: Invalid SMI bus address 0x%llx\n", __func__, 1806 (unsigned long long)addr); 1807 break; 1808 } 1809 } else { 1810 switch (addr) { 1811 case 0x0001180000001800: 1812 *bus = 0; 1813 break; 1814 case 0x0001180000001900: 1815 *bus = 1; 1816 break; 1817 default: 1818 *bus = -1; 1819 printf("%s: Invalid SMI bus address 0x%llx\n", __func__, 1820 (unsigned long long)addr); 1821 break; 1822 } 1823 } 1824} 1825