phy8040.c (42778B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: phy8040.c 8 * Purpose: Phy Driver supports for Broadcom 8040 multiplexer/retimer 9 * Note: The driver is written in a way to support the mux configuration. 10 * It always assumes one port connects to the switch side. 11 * other three ports (called mux port) may or may not connect to a phy 12 * device on the line side. 13 * Only one link(switch side port <---> line side port) is active in 14 * any given time. 15 */ 16 17 #include <sal/types.h> 18 #include <shared/bsl.h> 19 #include <soc/drv.h> 20 #include <soc/debug.h> 21 #include <soc/error.h> 22 #include <soc/phyreg.h> 23 24 #include <soc/phy.h> 25 #include <soc/phy/phyctrl.h> 26 #include <soc/phy/drv.h> 27 28 #if defined(INCLUDE_PHY_8040) 29 #include "phydefs.h" /* Must include before other phy related includes */ 30 #include "phyconfig.h" /* Must be the first phy include after phydefs.h */ 31 #include "phyident.h" 32 #include "phyreg.h" 33 #include "phynull.h" 34 #include "phyxehg.h" 35 #include "phy8040.h" 36 37 #define MAX_MPORTS 3 /* max number of mux ports on the device*/ 38 #define MAX_8040_PORTS 4 /* number of total xgxs ports on the device */ 39 #define PHY8040_MUX_PORT_INVALID 0x7f 40 #define PHY_ADDR_NONE 0xFF 41 #define PHY87X6_ID1_REVA 0x6034 42 #define PHY87X6_ID1_REVB 0x6035 43 #define PHY87X6_ID0 0x20 44 45 /* 8040 device specific data descriptor. */ 46 #define PHY8040_DEV_DESC(pc) ((phy8040_ctrl_t *)((pc)->driver_data)) 47 48 #define PHYDRV_CALL_NOARG(pc,dc,name,rv) \ 49 do { \ 50 if ((dc)->lp[(dc)->inx].nxt_pc) { \ 51 phy_ctrl_t * tmp_pc = EXT_PHY_SW_STATE((pc)->unit, (pc)->port); \ 52 EXT_PHY_SW_STATE((pc)->unit,(pc)->port)=(dc)->lp[(dc)->inx].nxt_pc; \ 53 rv = name((dc)->lp[(dc)->inx].nxt_pc->pd,(pc)->unit,(pc)->port); \ 54 EXT_PHY_SW_STATE((pc)->unit, (pc)->port) = tmp_pc; \ 55 } \ 56 } while(0) 57 58 #define PHYDRV_CALL_ARG1(pc,dc,name,arg0,rv) \ 59 do { \ 60 if ((dc)->lp[(dc)->inx].nxt_pc) { \ 61 phy_ctrl_t * tmp_pc = EXT_PHY_SW_STATE((pc)->unit, (pc)->port); \ 62 EXT_PHY_SW_STATE((pc)->unit,(pc)->port)=(dc)->lp[(dc)->inx].nxt_pc; \ 63 rv = name((dc)->lp[(dc)->inx].nxt_pc->pd,(pc)->unit,(pc)->port,arg0); \ 64 EXT_PHY_SW_STATE((pc)->unit, (pc)->port) = tmp_pc; \ 65 } \ 66 } while(0) 67 68 #define PHYDRV_CALL_ARG2(pc,dc,name,arg0,arg1,rv) \ 69 do { \ 70 if ((dc)->lp[(dc)->inx].nxt_pc) { \ 71 phy_ctrl_t * tmp_pc = EXT_PHY_SW_STATE((pc)->unit, (pc)->port); \ 72 EXT_PHY_SW_STATE((pc)->unit,(pc)->port)=(dc)->lp[(dc)->inx].nxt_pc; \ 73 rv = name((dc)->lp[(dc)->inx].nxt_pc->pd,(pc)->unit,(pc)->port, \ 74 arg0,arg1); \ 75 EXT_PHY_SW_STATE((pc)->unit, (pc)->port) = tmp_pc; \ 76 } \ 77 } while(0) 78 79 #define PHYDRV_CALL_ARG3(pc,dc,name,arg0,arg1,arg2,rv) \ 80 do { \ 81 if ((dc)->lp[(dc)->inx].nxt_pc) { \ 82 phy_ctrl_t * tmp_pc = EXT_PHY_SW_STATE((pc)->unit, (pc)->port); \ 83 EXT_PHY_SW_STATE((pc)->unit,(pc)->port)=(dc)->lp[(dc)->inx].nxt_pc; \ 84 rv = name((dc)->lp[(dc)->inx].nxt_pc->pd,(pc)->unit,(pc)->port, \ 85 arg0,arg1,arg2); \ 86 EXT_PHY_SW_STATE((pc)->unit, (pc)->port) = tmp_pc; \ 87 } \ 88 } while(0) 89 90 /* mux_port_desc_t describes each mux port configuration. The value of each 91 * element must match the actual hardware configuration. For example, if the 92 * mux port 0 connects a 8726 phy device with the mdio address 0x56, then the 93 * port should be 0 and phy_addr should be 0x56. 94 * The port is configured through spn_PHY_8040_MUX_PORT[x], x=0-2. 95 * The phy_addr is configured through spn_PORT_PHY_ADDR1. 96 * Make sure all the configuration values match up the actual hardware configuration. 97 */ 98 typedef struct { 99 phy_ctrl_t *nxt_pc; /* the driver to handle the connected phy device */ 100 uint16 port; /* the 8040 port connecting to the phy device */ 101 uint8 phy_addr; /* the mdio address of the phy device */ 102 } mux_port_desc_t; 103 104 /* device specific info descriptor */ 105 106 typedef struct { 107 /* The logical port map. Array index represents the logic port number. 108 * Each entry describes each mux port configuration. See comment on 109 * mux_port_desc_t. 110 */ 111 mux_port_desc_t lp[MAX_MPORTS]; 112 uint16 switch_port; /* switch port */ 113 uint16 num_mports; /* number of mux port used */ 114 uint8 devids[MAX_8040_PORTS]; /* device ids, index is physical port number */ 115 uint8 inx; /* active logic port number */ 116 uint8 sp_10g[MAX_MPORTS]; /* logical port speed */ 117 } phy8040_ctrl_t; 118 119 /* default MDIO addresses of phy devices on the mux ports, per port based*/ 120 static uint8 ext_phy_dft_addr1[][MAX_MPORTS] = { 121 /* first phy second phy third phy */ 122 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 0 */ 123 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 1 */ 124 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 2 */ 125 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 3 */ 126 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 4 */ 127 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 5 */ 128 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 6 */ 129 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 7 */ 130 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 8 */ 131 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 9 */ 132 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 10 */ 133 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 11 */ 134 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 12 */ 135 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 13 */ 136 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 14 */ 137 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 15 */ 138 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 16 */ 139 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 17 */ 140 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 18 */ 141 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 19 */ 142 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 20 */ 143 {0x56, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 21 */ 144 {0x57, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 22 */ 145 {0x58, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 23 */ 146 {0x59, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 24 */ 147 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 25 */ 148 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 26 */ 149 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 27 */ 150 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 28 */ 151 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 29 */ 152 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 30 */ 153 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 31 */ 154 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 32 */ 155 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 33 */ 156 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 34 */ 157 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 35 */ 158 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 36 */ 159 {PHY_ADDR_NONE, PHY_ADDR_NONE, PHY_ADDR_NONE}, /* 37 */ 160 }; 161 162 #define MAX_DFT_ADDR_ENTRY \ 163 ((sizeof(ext_phy_dft_addr1)/sizeof(ext_phy_dft_addr1[0][0]))/MAX_MPORTS) 164 165 /* local function prototypes */ 166 STATIC int _phy8040_speed_set(int unit, soc_port_t port, int speed); 167 STATIC int _phy8040_speed_get(int unit, soc_port_t port, int *speed); 168 169 170 static int 171 _phy_8040_mux(int unit, soc_port_t port) 172 { 173 int switch_port; 174 int active_mport; 175 phy8040_ctrl_t * dc; 176 phy_ctrl_t *pc; 177 178 pc = EXT_PHY_SW_STATE(unit, port); 179 180 dc = PHY8040_DEV_DESC(pc); 181 182 active_mport = dc->lp[dc->inx].port; 183 switch_port = dc->switch_port; 184 185 LOG_INFO(BSL_LS_SOC_PHY, 186 (BSL_META_U(unit, 187 "8040: u=%d port=%d primary=%d secondary=%d.\n"), 188 pc->unit, pc->port, switch_port, active_mport)); 189 190 /* Power down other two blocks. */ 191 SOC_IF_ERROR_RETURN 192 (WRITE_PHY8040_PWR_CTRLr(pc->unit, pc, 193 (PHY8040_PWRCTRL_RSVD| 194 (0xf & 195 ~((1<<switch_port)| 196 (1<<active_mport)))))); 197 198 /* Set source for primary <---> secondary ports */ 199 SOC_IF_ERROR_RETURN 200 (MODIFY_PHY8040_XGXSn_CTRLr(pc->unit, pc, switch_port, 201 PHY8040_XGXS_CTRL_SRC(active_mport), 202 PHY8040_XGXS_CTRL_SRC(0xf))); 203 SOC_IF_ERROR_RETURN 204 (MODIFY_PHY8040_XGXSn_CTRLr(pc->unit, pc, active_mport, 205 PHY8040_XGXS_CTRL_SRC(switch_port), 206 PHY8040_XGXS_CTRL_SRC(0xf))); 207 208 /* Soft reset primary & secondary ports */ 209 SOC_IF_ERROR_RETURN 210 (MODIFY_PHY8040_XGXSn_REG(pc->unit, pc, dc->devids[switch_port], 211 MII_CTRL_REG, MII_CTRL_RESET, MII_CTRL_RESET)); 212 SOC_IF_ERROR_RETURN 213 (MODIFY_PHY8040_XGXSn_REG(pc->unit, pc, dc->devids[active_mport], 214 MII_CTRL_REG, MII_CTRL_RESET, MII_CTRL_RESET)); 215 216 return SOC_E_NONE; 217 } 218 219 /* 220 * Function: 221 * phy_8040_init 222 * Purpose: 223 * Initialize 8040 phys. Configure each XGXS block with a unique device ID. 224 * The MDIO addressing is to use a single MDIO address and a different device 225 * id for each of the five device blocks. The top block's device ID is hardwired. 226 * The driver is written to only support the MDIO clause 45 protocol. 227 * Set up a valid link(switch port <---> mux port) and disable the unused mux 228 * ports. 229 * 230 * Parameters: 231 * unit - StrataSwitch unit #. 232 * port - StrataSwitch port #. 233 * Returns: 234 * SOC_E_NONE 235 */ 236 STATIC int 237 phy_8040_init(int unit, soc_port_t port) 238 { 239 phy8040_ctrl_t * dc; 240 phy8040_ctrl_t * new_dc; 241 int i; 242 int rv = SOC_E_NONE; 243 phy_ctrl_t *pc; 244 phy_ctrl_t *new_pc; 245 uint32 mdio_adrs; 246 void *tmp_holder; /* temporary place holder */ 247 int size; 248 int num_pc; 249 soc_phy_info_t phy_info; 250 extern int _ext_phy_probe(int unit, soc_port_t port,soc_phy_info_t *pi, 251 phy_ctrl_t *ext_pc); 252 253 pc = EXT_PHY_SW_STATE(unit, port); 254 255 /* allocate a temp storage to hold fixed number of control structures */ 256 size = sizeof(phy8040_ctrl_t) + MAX_MPORTS * sizeof (phy_ctrl_t); 257 tmp_holder = sal_alloc(size, "PHY8040"); 258 if (tmp_holder == NULL) { 259 return SOC_E_MEMORY; 260 } 261 sal_memset(tmp_holder, 0, size); 262 263 dc = (phy8040_ctrl_t *)tmp_holder; 264 265 dc->devids[0] =PHY8040_C45_DEV_XGXS0; 266 dc->devids[1] =PHY8040_C45_DEV_XGXS1; 267 dc->devids[2] =PHY8040_C45_DEV_XGXS2; 268 dc->devids[3] =PHY8040_C45_DEV_XGXS3; 269 270 dc->switch_port = soc_property_port_get(pc->unit, pc->port, 271 spn_PHY_8040_SWITCH_PORT, 272 PHY8040_DFLT_SWITCH_PORT); 273 dc->lp[0].port = soc_property_port_get(pc->unit, pc->port, 274 spn_PHY_8040_MUX_PORT0, 275 PHY8040_DFLT_MUX_PORT0); 276 dc->lp[1].port = soc_property_port_get(pc->unit, pc->port, 277 spn_PHY_8040_MUX_PORT1, 278 PHY8040_DFLT_MUX_PORT1); 279 dc->lp[2].port = soc_property_port_get(pc->unit, pc->port, 280 spn_PHY_8040_MUX_PORT2, 281 PHY8040_MUX_PORT_INVALID); 282 283 /* spn_PORT_PHY_ADDR1 configures 3 additional MDIO addresses for 284 * the mux port with 8040 type phy 285 * bit 31 -- 24 23 -- 16 15 -- 8 7 -- 0 286 * mdioAdrs phy 3 phy 2 phy 1 287 * phy 1 --> mux port 0 288 * phy 2 --> mux port 1 289 * phy 3 --> mux port 2 290 */ 291 mdio_adrs = soc_property_port_get(pc->unit, pc->port, 292 spn_PORT_PHY_ADDR1, 0); 293 294 for (i = 0; i < MAX_MPORTS; i++) { 295 if ((mdio_adrs >> (i * 8)) & 0xFF) { /* use configured value */ 296 dc->lp[i].phy_addr = (mdio_adrs >> (i * 8)) & 0xFF; 297 } else { /* use default value */ 298 if (pc->port < MAX_DFT_ADDR_ENTRY) { 299 dc->lp[i].phy_addr = ext_phy_dft_addr1[pc->port][i]; 300 } 301 } 302 } 303 304 for (i = 0; i < MAX_MPORTS; i++) { 305 if (dc->lp[i].port == PHY8040_MUX_PORT_INVALID) { 306 break; 307 } 308 } 309 dc->num_mports = i; 310 311 /* probe the mux ports for the connected phys. */ 312 313 new_pc = (phy_ctrl_t *)(dc + 1); 314 for (num_pc = 0,i = 0; i < dc->num_mports; i++) { 315 new_pc->unit = unit; 316 new_pc->port = port; 317 new_pc->speed_max = pc->speed_max; 318 new_pc->read = pc->read; /* use same MDIO read as this device's */ 319 new_pc->write = pc->write; /*use same MDIO write as this device's */ 320 new_pc->phy_id = dc->lp[i].phy_addr; 321 322 /* probe the next device at the given address */ 323 SOC_IF_ERROR_RETURN 324 (_ext_phy_probe(unit, port, &phy_info, new_pc)); 325 326 if (new_pc->pd != NULL) { 327 dc->lp[i].nxt_pc = new_pc; 328 num_pc += 1; 329 LOG_INFO(BSL_LS_SOC_PHY, 330 (BSL_META_U(unit, 331 "_phy_8040_init: found next phy device" 332 " u=%d p=%d id0=0x%x id1=0x%x\n"), 333 unit, port,new_pc->phy_id0,new_pc->phy_id1)); 334 } 335 new_pc += 1; 336 } 337 338 /* device probe done, allocate memory for control structures */ 339 340 size = sizeof(phy8040_ctrl_t) + num_pc * sizeof (phy_ctrl_t); 341 pc->driver_data = (void *)sal_alloc (size, pc->pd->drv_name); 342 if (pc->driver_data == NULL) { 343 sal_free(tmp_holder); 344 return SOC_E_MEMORY; 345 } 346 347 /* copy control descriptors from temporary storage */ 348 new_dc = (phy8040_ctrl_t *)pc->driver_data; 349 sal_memcpy(new_dc, dc, sizeof(phy8040_ctrl_t)); 350 new_pc = (phy_ctrl_t *)(new_dc + 1); 351 for (i = 0; i < dc->num_mports; i++) { 352 if (dc->lp[i].nxt_pc) { 353 sal_memcpy(new_pc, dc->lp[i].nxt_pc, sizeof(phy_ctrl_t)); 354 new_dc->lp[i].nxt_pc = new_pc; 355 new_pc += 1; 356 } 357 } 358 359 /* done copy, free temp storage */ 360 sal_free(tmp_holder); 361 362 PHY_FLAGS_SET(pc->unit, pc->port, PHY_FLAGS_FIBER | PHY_FLAGS_C45); 363 364 /* Set our 4 internal XGXS block phy and dev addresses */ 365 for (i=0; i<MAX_8040_PORTS; i++) 366 { 367 SOC_IF_ERROR_RETURN 368 (MODIFY_PHY8040_XGXSn_CTRLr(pc->unit, pc, i, 369 PHY8040_XGXS_CTRL_DEVID(new_dc->devids[i])| 370 PHY8040_XGXS_CTRL_PRTAD(pc->phy_id), 371 PHY8040_XGXS_CTRL_DEVID(0x1f)| 372 PHY8040_XGXS_CTRL_PRTAD(0x1f))); 373 } 374 375 /* determine the default active phy_ctrl desc */ 376 new_dc->inx = 0; 377 378 _phy_8040_mux(pc->unit,pc->port); 379 380 /* all logical ports default speed to 10G */ 381 for (i = 0; i < new_dc->num_mports; i++) { 382 new_dc->sp_10g[i] = TRUE; 383 } 384 PHYDRV_CALL_NOARG(pc,new_dc,PHY_INIT,rv); 385 return rv; 386 } 387 388 389 /* 390 * Function: 391 * phy_8040_link_get 392 * Purpose: 393 * Get layer2 connection status. 394 * Parameters: 395 * unit - StrataSwitch unit #. 396 * port - StrataSwitch port #. 397 * link - address of memory to store link up/down state. 398 * Returns: 399 * SOC_E_NONE 400 */ 401 402 STATIC int 403 phy_8040_link_get(int unit, soc_port_t port, int *link) 404 { 405 int switch_port; 406 int active_mport; 407 uint16 switch_port_stat, mux_port_stat; 408 uint16 sp_sync_stat, mp_sync_stat,rx_status; 409 phy8040_ctrl_t * dc; 410 phy_ctrl_t *pc; 411 int rv = SOC_E_NONE; 412 int an = 0; 413 int an_done = 0; 414 int speed = 0; 415 int speed_local = 0; 416 417 pc = EXT_PHY_SW_STATE(unit, port); 418 419 dc = PHY8040_DEV_DESC(pc); 420 421 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) { 422 *link = FALSE; 423 return SOC_E_NONE; 424 } 425 426 switch_port = dc->switch_port; 427 active_mport = dc->lp[dc->inx].port; 428 429 *link=FALSE; 430 431 if (NULL != dc->lp[dc->inx].nxt_pc) { 432 /* When the connected phy is in AN mode, its negotiated speed needs to be 433 * propagated to this device. Sync up here since this function is periodically 434 * called by a dedicated linkscan task. 435 */ 436 PHYDRV_CALL_ARG1(pc,dc,PHY_LINK_GET,link,rv); 437 438 if (*link == TRUE) { 439 /* check if in an mode */ 440 PHYDRV_CALL_ARG2(pc,dc,PHY_AUTO_NEGOTIATE_GET,&an,&an_done,rv); 441 442 if (an == TRUE && an_done == TRUE) { 443 /* get the speed */ 444 PHYDRV_CALL_ARG1(pc,dc,PHY_SPEED_GET,&speed,rv); 445 _phy8040_speed_get(unit, port, &speed_local); 446 447 if (speed && (speed != speed_local)) { 448 /* set this device's speed accordingly */ 449 _phy8040_speed_set(unit,port,speed); 450 } 451 } 452 } else { 453 return rv; 454 } 455 } 456 457 if (dc->sp_10g[dc->inx] == FALSE) { 458 /* check 1G linkup status */ 459 SOC_IF_ERROR_RETURN 460 (READ_PHY8040_XGXSn_REG(pc->unit, pc, dc->devids[active_mport], 461 PHY8040_RX_STATUS_REG,&rx_status)); 462 463 if ((rx_status & PHY8040_1G_LINKUP_MASK) == PHY8040_1G_LINKUP_MASK) { 464 *link=TRUE; 465 } 466 SOC_IF_ERROR_RETURN 467 (READ_PHY8040_XGXSn_REG(pc->unit, pc, dc->devids[switch_port], 468 PHY8040_RX_STATUS_REG,&rx_status)); 469 if ((rx_status & PHY8040_1G_LINKUP_MASK) == PHY8040_1G_LINKUP_MASK) { 470 *link=TRUE; 471 } 472 } else { 473 /* check 10G link */ 474 475 SOC_IF_ERROR_RETURN 476 (READ_PHY8040_XGXSn_REG(pc->unit, pc, 477 dc->devids[switch_port], 478 MII_STAT_REG, &switch_port_stat)); 479 SOC_IF_ERROR_RETURN 480 (READ_PHY8040_XGXSn_REG(pc->unit, pc, 481 dc->devids[active_mport], 482 MII_STAT_REG, &mux_port_stat)); 483 484 *link = MII_STAT_LA & (switch_port_stat & mux_port_stat); 485 486 SOC_IF_ERROR_RETURN 487 (READ_PHY8040_XGXSn_REG(pc->unit, pc, 488 dc->devids[switch_port], 489 PHY8040_LANE_STATUS_REG, 490 &sp_sync_stat)); 491 492 SOC_IF_ERROR_RETURN 493 (READ_PHY8040_XGXSn_REG(pc->unit, pc, 494 dc->devids[active_mport], 495 PHY8040_LANE_STATUS_REG, 496 &mp_sync_stat)); 497 if (*link) { 498 *link &= (((sp_sync_stat & mp_sync_stat) & 0xf) == 0xf) ? 499 MII_STAT_LA : 0; 500 if (!*link) { 501 LOG_INFO(BSL_LS_SOC_PHY, 502 (BSL_META_U(unit, 503 "8040: Link set but no sync.\n" 504 " u=%d port=%d primary lane status=%X secondary lane" 505 " status=%X.\n"), 506 pc->unit, pc->port, sp_sync_stat, mp_sync_stat)); 507 } 508 } else { 509 LOG_VERBOSE(BSL_LS_SOC_PHY, 510 (BSL_META_U(unit, 511 "8040: u=%d port=%d switch port=%X mux port=%X.\n"), 512 pc->unit, pc->port, switch_port_stat, mux_port_stat)); 513 } 514 } 515 516 /* check the connected device */ 517 if (*link) { 518 PHYDRV_CALL_ARG1(pc,dc,PHY_LINK_GET,link,rv); 519 } 520 return rv; 521 } 522 523 /* 524 * Function: 525 * phy_8040_enable_set 526 * Purpose: 527 * Enable/Disable phy 528 * Parameters: 529 * unit - StrataSwitch unit #. 530 * port - StrataSwitch port #. 531 * enable - on/off state to set 532 * Returns: 533 * SOC_E_NONE 534 */ 535 536 STATIC int 537 phy_8040_enable_set(int unit, soc_port_t port, int enable) 538 { 539 phy8040_ctrl_t * dc; 540 uint16 data; 541 int rv = SOC_E_NONE; 542 phy_ctrl_t *pc; 543 544 pc = EXT_PHY_SW_STATE(unit, port); 545 dc = PHY8040_DEV_DESC(pc); 546 547 if (enable) { 548 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE); 549 } else { 550 PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE); 551 } 552 553 data = enable ? 0:MII_CTRL_PD; 554 555 SOC_IF_ERROR_RETURN 556 (MODIFY_PHY8040_XGXSn_REG(pc->unit, pc, dc->devids[dc->lp[dc->inx].port], 557 MII_CTRL_REG, data, MII_CTRL_PD)); 558 559 PHYDRV_CALL_ARG1(pc,dc,PHY_ENABLE_SET,enable,rv); 560 561 return (rv); 562 } 563 564 STATIC int 565 _phy8040_speed_set(int unit, soc_port_t port, int speed) 566 { 567 phy8040_ctrl_t * dc; 568 int rv = SOC_E_NONE; 569 phy_ctrl_t *pc; 570 uint8 devid[2]; 571 int i; 572 573 pc = EXT_PHY_SW_STATE(unit, port); 574 dc = PHY8040_DEV_DESC(pc); 575 576 devid[0] = dc->devids[dc->lp[dc->inx].port]; 577 devid[1] = dc->devids[dc->switch_port]; 578 579 if (speed == 10000) { /* 10G */ 580 dc->sp_10g[dc->inx] = TRUE; 581 582 /* various register configuration for 10G speed, powerup default values */ 583 for (i = 0; i < 2; i++) { 584 SOC_IF_ERROR_RETURN 585 (WRITE_PHY8040_XGXSn_REG(pc->unit, pc, devid[i], 586 PHY8040_TX0A_CTRL1_REG, 0x0dd0)); 587 588 SOC_IF_ERROR_RETURN 589 (WRITE_PHY8040_XGXSn_REG(pc->unit, pc, devid[i], 590 PHY8040_XGXS_CTRL_REG,0x202e)); 591 SOC_IF_ERROR_RETURN 592 (WRITE_PHY8040_XGXSn_REG(pc->unit, pc, devid[i], 593 PHY8040_LANE_CTRL1_REG,0x0000)); 594 595 SOC_IF_ERROR_RETURN 596 (WRITE_PHY8040_XGXSn_REG(pc->unit, pc, devid[i], 597 PHY8040_LANE_CTRL2_REG,0xf000)); 598 599 SOC_IF_ERROR_RETURN 600 (WRITE_PHY8040_XGXSn_REG(pc->unit, pc, devid[i], 601 PHY8040_RX_CTRL_REG,0x1c0a)); 602 } 603 } else if (speed == 1000) { /* 1G */ 604 605 dc->sp_10g[dc->inx] = FALSE; 606 /* various register configuration for 1G speed */ 607 for (i = 0; i < 2; i++) { 608 SOC_IF_ERROR_RETURN 609 (WRITE_PHY8040_XGXSn_REG(pc->unit, pc, devid[i], 610 PHY8040_TX0A_CTRL1_REG,0x0dd0)); 611 612 SOC_IF_ERROR_RETURN 613 (WRITE_PHY8040_XGXSn_REG(pc->unit, pc, devid[i], 614 PHY8040_XGXS_CTRL_REG, 0x263a)); 615 SOC_IF_ERROR_RETURN 616 (WRITE_PHY8040_XGXSn_REG(pc->unit, pc, devid[i], 617 PHY8040_LANE_CTRL1_REG,0xffff)); 618 619 SOC_IF_ERROR_RETURN 620 (WRITE_PHY8040_XGXSn_REG(pc->unit, pc, devid[i], 621 PHY8040_LANE_CTRL2_REG,0x0000)); 622 623 SOC_IF_ERROR_RETURN 624 (WRITE_PHY8040_XGXSn_REG(pc->unit, pc, devid[i], 625 PHY8040_RX_CTRL_REG,0x1c00)); 626 } 627 } 628 629 return (rv); 630 } 631 632 /* 633 * Function: 634 * phy_8040_speed_set 635 * Purpose: 636 * Set PHY speed 637 * Parameters: 638 * unit - StrataSwitch unit #. 639 * port - StrataSwitch port #. 640 * speed - link speed in Mbps 641 * Returns: 642 * SOC_E_NONE 643 */ 644 645 STATIC int 646 phy_8040_speed_set(int unit, soc_port_t port, int speed) 647 { 648 phy8040_ctrl_t * dc; 649 int rv = SOC_E_NONE; 650 phy_ctrl_t *pc; 651 652 pc = EXT_PHY_SW_STATE(unit, port); 653 dc = PHY8040_DEV_DESC(pc); 654 655 _phy8040_speed_set(unit,port,speed); 656 657 rv = SOC_E_UNAVAIL; 658 PHYDRV_CALL_ARG1(pc,dc,PHY_SPEED_SET,speed,rv); 659 660 if (rv == SOC_E_UNAVAIL) { 661 phy_ctrl_t *int_pc; 662 int_pc = INT_PHY_SW_STATE(unit, port); 663 664 if (NULL != int_pc) { 665 rv = PHY_SPEED_SET(int_pc->pd, unit, port, speed); 666 } 667 } 668 return (rv); 669 } 670 671 STATIC int 672 _phy8040_speed_get(int unit, soc_port_t port, int *speed) 673 { 674 phy8040_ctrl_t * dc; 675 int rv = SOC_E_NONE; 676 phy_ctrl_t *pc; 677 678 pc = EXT_PHY_SW_STATE(unit, port); 679 dc = PHY8040_DEV_DESC(pc); 680 if (dc->sp_10g[dc->inx] == FALSE) { 681 *speed = 1000; 682 } else { 683 *speed = 10000; 684 } 685 686 return (rv); 687 } 688 689 /* 690 * Function: 691 * phy_8040_speed_get 692 * Purpose: 693 * Get PHY speed 694 * Parameters: 695 * unit - StrataSwitch unit #. 696 * port - StrataSwitch port #. 697 * speed - current link speed in Mbps 698 * Returns: 699 * SOC_E_NONE 700 */ 701 702 STATIC int 703 phy_8040_speed_get(int unit, soc_port_t port, int *speed) 704 { 705 phy8040_ctrl_t * dc; 706 int rv = SOC_E_NONE; 707 phy_ctrl_t *pc; 708 709 pc = EXT_PHY_SW_STATE(unit, port); 710 dc = PHY8040_DEV_DESC(pc); 711 712 _phy8040_speed_get(unit, port, speed); 713 PHYDRV_CALL_ARG1(pc,dc,PHY_SPEED_GET,speed,rv); 714 715 return (rv); 716 } 717 718 /* 719 * Function: 720 * phy_8040_an_get 721 * Purpose: 722 * Get the current auto-negotiation status (enabled/busy) 723 * Parameters: 724 * unit - StrataSwitch unit #. 725 * port - StrataSwitch port #. 726 * an - (OUT) if true, auto-negotiation is enabled. 727 * an_done - (OUT) if true, auto-negotiation is complete. This 728 * value is undefined if an == false. 729 * Returns: 730 * SOC_E_XXX 731 */ 732 733 STATIC int 734 phy_8040_an_get(int unit, soc_port_t port, int *an, int *an_done) 735 { 736 phy8040_ctrl_t * dc; 737 int rv = SOC_E_NONE; 738 phy_ctrl_t *pc; 739 740 pc = EXT_PHY_SW_STATE(unit, port); 741 dc = PHY8040_DEV_DESC(pc); 742 *an= 0; 743 *an_done = 0; 744 PHYDRV_CALL_ARG2(pc,dc,PHY_AUTO_NEGOTIATE_GET,an,an_done,rv); 745 return (rv); 746 } 747 748 /* 749 * Function: 750 * phy_8040_an_set 751 * Purpose: 752 * Enable or disabled auto-negotiation on the specified port. 753 * Parameters: 754 * unit - StrataSwitch unit #. 755 * port - StrataSwitch port #. 756 * an - Boolean, if true, auto-negotiation is enabled 757 * (and/or restarted). If false, autonegotiation is disabled. 758 * Returns: 759 * SOC_E_XXX 760 */ 761 762 STATIC int 763 phy_8040_an_set(int unit, soc_port_t port, int an) 764 { 765 phy8040_ctrl_t * dc; 766 int rv = SOC_E_NONE; 767 phy_ctrl_t *pc; 768 769 pc = EXT_PHY_SW_STATE(unit, port); 770 dc = PHY8040_DEV_DESC(pc); 771 PHYDRV_CALL_ARG1(pc,dc,PHY_AUTO_NEGOTIATE_SET,an,rv); 772 return (rv); 773 } 774 775 /* 776 * Function: 777 * phy_8040_lb_set 778 * Purpose: 779 * Put 8040 in PHY PCS/PMA/PMD loopback 780 * Parameters: 781 * unit - StrataSwitch unit #. 782 * port - StrataSwitch port #. 783 * enable - binary value for on/off (1/0) 784 * Returns: 785 * SOC_E_NONE 786 */ 787 788 STATIC int 789 phy_8040_lb_set(int unit, soc_port_t port, int enable) 790 { 791 uint16 tmp; 792 phy8040_ctrl_t * dc; 793 phy_ctrl_t *pc; 794 int rv = SOC_E_UNAVAIL; 795 pc = EXT_PHY_SW_STATE(unit, port); 796 797 dc = PHY8040_DEV_DESC(pc); 798 799 /* do the loopback from outmost phy if available */ 800 PHYDRV_CALL_ARG1(pc,dc,PHY_LOOPBACK_SET,enable,rv); 801 802 if (rv != SOC_E_NONE) { 803 tmp = enable ? MII_CTRL_LE : 0; 804 805 SOC_IF_ERROR_RETURN 806 (MODIFY_PHY8040_XGXSn_REG(pc->unit, pc, dc->devids[dc->lp[dc->inx].port], 807 MII_CTRL_REG, tmp, MII_CTRL_LE)); 808 } 809 810 return SOC_E_NONE; 811 } 812 813 /* 814 * Function: 815 * phy_8040_lb_get 816 * Purpose: 817 * Get 8040 PHY loopback state 818 * Parameters: 819 * unit - StrataSwitch unit #. 820 * port - StrataSwitch port #. 821 * enable - address of location to store binary value for on/off (1/0) 822 * Returns: 823 * SOC_E_NONE 824 */ 825 826 STATIC int 827 phy_8040_lb_get(int unit, soc_port_t port, int *enable) 828 { 829 uint16 tmp; 830 int rv = SOC_E_UNAVAIL; 831 phy8040_ctrl_t * dc; 832 phy_ctrl_t *pc; 833 834 pc = EXT_PHY_SW_STATE(unit, port); 835 836 dc = PHY8040_DEV_DESC(pc); 837 838 /* check the loopback from outmost phy if available */ 839 PHYDRV_CALL_ARG1(pc,dc,PHY_LOOPBACK_GET,enable,rv); 840 841 if (rv != SOC_E_NONE) { 842 SOC_IF_ERROR_RETURN 843 (READ_PHY8040_XGXSn_REG(pc->unit, pc, dc->devids[dc->lp[dc->inx].port], 844 MII_CTRL_REG,&tmp)); 845 846 *enable = (tmp & MII_CTRL_LE) ? TRUE : FALSE; 847 } 848 return SOC_E_NONE; 849 } 850 851 /* 852 * Function: 853 * phy_8040_control_set 854 * Purpose: 855 * Configure PHY device specific control fucntion. 856 * Parameters: 857 * unit - StrataSwitch unit #. 858 * port - StrataSwitch port #. 859 * type - Control to update 860 * value - New setting for the control 861 * type SOC_PHY_CONTROL_INTERFACE controls which mux port to use. 862 * The associated value specifies the logical mux port number 0,1 and 2 863 * Returns: 864 * SOC_E_NONE 865 */ 866 STATIC int 867 phy_8040_control_set(int unit, soc_port_t port, 868 soc_phy_control_t type, uint32 value) 869 { 870 int rv; 871 phy8040_ctrl_t * dc; 872 int logic_port; 873 phy_ctrl_t *pc; 874 int speed; 875 876 pc = EXT_PHY_SW_STATE(unit, port); 877 878 dc = PHY8040_DEV_DESC(pc); 879 880 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 881 return SOC_E_PARAM; 882 } 883 884 rv = SOC_E_NONE; 885 886 switch(type) { 887 /* chose which physical port, value contains the selected 8040 port */ 888 case SOC_PHY_CONTROL_INTERFACE: 889 logic_port = value; 890 if (logic_port != dc->inx) { 891 892 if (logic_port < dc->num_mports) { 893 /* before changing to the new selected port, disable the 894 * the current active port to prevent the false link 895 */ 896 phy_8040_enable_set(pc->unit, pc->port, FALSE); 897 speed = dc->sp_10g[dc->inx]; /* remember previous speed*/ 898 899 /* activate the new mux port */ 900 dc->inx = logic_port; 901 902 _phy_8040_mux(pc->unit,pc->port); 903 phy_8040_enable_set(pc->unit, pc->port, TRUE); 904 905 /* the switch port speed may be changed in the previous 906 * link. Make sure it has the right speed 907 */ 908 if (speed != dc->sp_10g[dc->inx]) { 909 phy_ctrl_t *int_pc; 910 911 speed = dc->sp_10g[dc->inx]? 10000:1000; 912 _phy8040_speed_set(unit,port,speed); 913 914 int_pc = INT_PHY_SW_STATE(unit, port); 915 916 /* in case the linkscan doesn't detect the linkup event 917 * and set the serdes speed accordingly. we do it here 918 */ 919 if (NULL != int_pc) { 920 rv = PHY_SPEED_SET(int_pc->pd, unit, port, speed); 921 } 922 } 923 } 924 } 925 break; 926 927 case SOC_PHY_CONTROL_PREEMPHASIS: 928 /* Write PRE-EMPHASIS */ 929 SOC_IF_ERROR_RETURN 930 (MODIFY_PHY8040_XGXSn_REG(pc->unit, pc, 931 dc->devids[dc->lp[dc->inx].port], 932 PHY8040_PRE_EMPHASIS_REG, 933 PHY8040_PRE_EMPHASIS(value), 934 PHY8040_PRE_EMPHASIS(0xf))); 935 break; 936 case SOC_PHY_CONTROL_DRIVER_CURRENT: 937 /* Write DRIVER Current */ 938 SOC_IF_ERROR_RETURN 939 (MODIFY_PHY8040_XGXSn_REG(pc->unit, pc, 940 dc->devids[dc->lp[dc->inx].port], 941 PHY8040_PRE_EMPHASIS_REG, 942 PHY8040_DRIVER_STRENGTH(value), 943 PHY8040_DRIVER_STRENGTH(0xf))); 944 break; 945 default: 946 rv = SOC_E_UNAVAIL; 947 break; 948 } 949 if (((soc_phy_control_t)type != SOC_PHY_CONTROL_INTERFACE) && 950 ((soc_phy_control_t)type != SOC_PHY_CONTROL_INTERFACE_MAX)) { 951 PHYDRV_CALL_ARG2(pc,dc,PHY_CONTROL_SET,type,value,rv); 952 } 953 return rv; 954 } 955 /* 956 * Function: 957 * phy_8040_control_get 958 * Purpose: 959 * Get current control settign of the PHY. 960 * Parameters: 961 * unit - StrataSwitch unit #. 962 * port - StrataSwitch port #. 963 * type - Control to update 964 * value - (OUT)Current setting for the control 965 * Returns: 966 * SOC_E_NONE 967 */ 968 STATIC int 969 phy_8040_control_get(int unit, soc_port_t port, 970 soc_phy_control_t type, uint32 *value) 971 { 972 int rv; 973 uint16 val; 974 phy8040_ctrl_t * dc; 975 phy_ctrl_t *pc; 976 977 pc = EXT_PHY_SW_STATE(unit, port); 978 dc = PHY8040_DEV_DESC(pc); 979 980 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 981 return SOC_E_PARAM; 982 } 983 984 rv = SOC_E_NONE; 985 986 switch(type) { 987 case SOC_PHY_CONTROL_PREEMPHASIS: 988 /* Read PRE-EMPHASIS */ 989 SOC_IF_ERROR_RETURN 990 (READ_PHY8040_XGXSn_REG(pc->unit, pc, 991 dc->devids[dc->lp[dc->inx].port], 992 PHY8040_PRE_EMPHASIS_REG, 993 &val)); 994 *value = (val >> 12) & 0xf; 995 break; 996 case SOC_PHY_CONTROL_DRIVER_CURRENT: 997 /* Read DRIVER Current */ 998 SOC_IF_ERROR_RETURN 999 (READ_PHY8040_XGXSn_REG(pc->unit, pc, 1000 dc->devids[dc->lp[dc->inx].port], 1001 PHY8040_PRE_EMPHASIS_REG, 1002 &val)); 1003 *value = (val >> 8) & 0xf; 1004 break; 1005 case SOC_PHY_CONTROL_INTERFACE: 1006 *value = dc->inx; 1007 break; 1008 1009 case SOC_PHY_CONTROL_INTERFACE_MAX: 1010 *value = dc->num_mports - 1; 1011 break; 1012 default: 1013 rv = SOC_E_UNAVAIL; 1014 break; 1015 } 1016 1017 if (((soc_phy_control_t)type != SOC_PHY_CONTROL_INTERFACE) && 1018 ((soc_phy_control_t)type != SOC_PHY_CONTROL_INTERFACE_MAX)) { 1019 PHYDRV_CALL_ARG2(pc,dc,PHY_CONTROL_GET,type,value,rv); 1020 } 1021 return rv; 1022 } 1023 1024 /* 1025 * Function: 1026 * phy_8040_interface_get 1027 * Purpose: 1028 * Get the device's interface. 1029 * Parameters: 1030 * unit - StrataSwitch unit #. 1031 * port - StrataSwitch port #. 1032 * pif - return device's interface. 1033 * Returns: 1034 * SOC_E_XXX 1035 */ 1036 STATIC int 1037 phy_8040_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 1038 { 1039 int rv = SOC_E_UNAVAIL; 1040 phy8040_ctrl_t * dc; 1041 phy_ctrl_t *pc; 1042 1043 pc = EXT_PHY_SW_STATE(unit, port); 1044 dc = PHY8040_DEV_DESC(pc); 1045 1046 /* check the outmost phy first */ 1047 PHYDRV_CALL_ARG1(pc,dc,PHY_INTERFACE_GET,pif,rv); 1048 if (rv != SOC_E_NONE) { 1049 *pif = SOC_PORT_IF_XAUI; 1050 } 1051 return SOC_E_NONE; 1052 } 1053 1054 /* 1055 * Function: 1056 * phy_8040_ability_local_get 1057 * Purpose: 1058 * Get the device's complete abilities. 1059 * Parameters: 1060 * unit - StrataSwitch unit #. 1061 * port - StrataSwitch port #. 1062 * ability - return device's abilities. 1063 * Returns: 1064 * SOC_E_XXX 1065 */ 1066 STATIC 1067 int phy_8040_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 1068 { 1069 int rv = SOC_E_UNAVAIL; 1070 phy8040_ctrl_t * dc; 1071 phy_ctrl_t *pc; 1072 1073 pc = EXT_PHY_SW_STATE(unit, port); 1074 dc = PHY8040_DEV_DESC(pc); 1075 1076 LOG_INFO(BSL_LS_SOC_PHY, 1077 (BSL_META_U(unit, 1078 "phy_8040_ability_local_get: u=%d p=%d\n"), 1079 pc->unit, pc->port)); 1080 if (NULL == ability) { 1081 return SOC_E_PARAM; 1082 } 1083 /* check the outmost phy first */ 1084 PHYDRV_CALL_ARG1(pc,dc,PHY_ABILITY_LOCAL_GET,ability,rv); 1085 if (rv != SOC_E_NONE) { 1086 ability->speed_half_duplex = SOC_PA_ABILITY_NONE; 1087 ability->speed_full_duplex = SOC_PA_SPEED_10GB | SOC_PA_SPEED_1000MB; 1088 ability->pause = 0; 1089 ability->interface = SOC_PA_INTF_XGMII; 1090 ability->medium = SOC_PA_MEDIUM_FIBER; 1091 ability->loopback = SOC_PA_LB_PHY; 1092 ability->flags = 0; 1093 LOG_INFO(BSL_LS_SOC_PHY, 1094 (BSL_META_U(unit, 1095 "phy_8040_ability_local_get: u=%d p=%d speed=0x%x\n"), 1096 pc->unit, pc->port, ability->speed_full_duplex)); 1097 } 1098 return (SOC_E_NONE); 1099 } 1100 1101 /* 1102 * Function: 1103 * phy_8040_ability_advert_get 1104 * Purpose: 1105 * Get the current advertisement for auto-negotiation. 1106 * Parameters: 1107 * unit - StrataSwitch unit #. 1108 * port - StrataSwitch port #. 1109 * mode - (OUT) Port mode mask indicating supported options/speeds. 1110 * Returns: 1111 * SOC_E_XXX 1112 * Notes: 1113 * The advertisement is retrieved for the ACTIVE medium. 1114 * No synchronization performed at this level. 1115 */ 1116 1117 STATIC int 1118 phy_8040_ability_advert_get(int unit, soc_port_t port, soc_port_ability_t *ability) 1119 { 1120 int rv = SOC_E_UNAVAIL; 1121 phy8040_ctrl_t * dc; 1122 phy_ctrl_t *pc; 1123 1124 pc = EXT_PHY_SW_STATE(unit, port); 1125 dc = PHY8040_DEV_DESC(pc); 1126 1127 PHYDRV_CALL_ARG1(pc,dc,PHY_ABILITY_ADVERT_GET,ability,rv); 1128 if (rv != SOC_E_NONE) { 1129 ability->speed_full_duplex = 0; 1130 } 1131 return (SOC_E_NONE); 1132 } 1133 1134 /* 1135 * Function: 1136 * phy_8040_ability_advert_remote_get 1137 * Purpose: 1138 * Get the remote device's current advertisement for auto-negotiation. 1139 * Parameters: 1140 * unit - StrataSwitch unit #. 1141 * port - StrataSwitch port #. 1142 * mode - (OUT) Port mode mask indicating supported options/speeds. 1143 * Returns: 1144 * SOC_E_XXX 1145 * Notes: 1146 * The advertisement is retrieved for the ACTIVE medium. 1147 * No synchronization performed at this level. 1148 */ 1149 1150 STATIC int 1151 phy_8040_ability_advert_remote_get(int unit, soc_port_t port, soc_port_ability_t *ability) 1152 { 1153 int rv = SOC_E_UNAVAIL; 1154 phy8040_ctrl_t * dc; 1155 phy_ctrl_t *pc; 1156 1157 pc = EXT_PHY_SW_STATE(unit, port); 1158 dc = PHY8040_DEV_DESC(pc); 1159 1160 PHYDRV_CALL_ARG1(pc,dc,PHY_ABILITY_REMOTE_GET,ability,rv); 1161 if (rv != SOC_E_NONE) { 1162 ability->speed_full_duplex = 0; 1163 } 1164 return (SOC_E_NONE); 1165 } 1166 1167 /* 1168 * Function: 1169 * phy_8040_ability_advert_set 1170 * Purpose: 1171 * Set the current advertisement for auto-negotiation. 1172 * Parameters: 1173 * unit - StrataSwitch unit #. 1174 * port - StrataSwitch port #. 1175 * mode - Port mode mask indicating supported options/speeds. 1176 * Returns: 1177 * SOC_E_XXX 1178 * Notes: 1179 * The advertisement is set only for the ACTIVE medium. 1180 * No synchronization performed at this level. 1181 */ 1182 1183 STATIC int 1184 phy_8040_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability) 1185 { 1186 int rv = SOC_E_NONE; 1187 phy8040_ctrl_t * dc; 1188 phy_ctrl_t *pc; 1189 1190 pc = EXT_PHY_SW_STATE(unit, port); 1191 dc = PHY8040_DEV_DESC(pc); 1192 1193 PHYDRV_CALL_ARG1(pc,dc,PHY_ABILITY_ADVERT_SET,ability,rv); 1194 return (rv); 1195 } 1196 1197 /* 1198 * Function: 1199 * phy_8481_firmware_set 1200 * Purpose: 1201 * program the given firmware into the SPI-ROM 1202 * Parameters: 1203 * unit - StrataSwitch unit #. 1204 * port - StrataSwitch port #. 1205 * offset - offset to the data stream 1206 * array - the given data 1207 * datalen- the data length 1208 * Returns: 1209 * SOC_E_NONE 1210 */ 1211 1212 STATIC int 1213 phy_8040_firmware_set(int unit, int port, int offset, uint8 *data,int len) 1214 { 1215 phy8040_ctrl_t * dc; 1216 phy_ctrl_t *pc; 1217 int rv = SOC_E_NONE; 1218 1219 pc = EXT_PHY_SW_STATE(unit, port); 1220 dc = PHY8040_DEV_DESC(pc); 1221 1222 if (NULL != dc->lp[dc->inx].nxt_pc) { 1223 PHYDRV_CALL_ARG3(pc,dc,PHY_FIRMWARE_SET,offset,data,len,rv); 1224 return rv; 1225 } 1226 return SOC_E_UNAVAIL; 1227 } 1228 1229 /* 1230 * Variable: 1231 * phy_8040_drv 1232 * Purpose: 1233 * Phy Driver for 10G (XAUI x 4) Serdes PHY. 1234 */ 1235 1236 phy_driver_t phy_8040drv_xe = { 1237 "8040 10-Gigabit PHY Driver", 1238 phy_8040_init, /* Init */ 1239 phy_null_reset, /* Reset (dummy) */ 1240 phy_8040_link_get, /* Link get: XXX: talk to Bob */ 1241 phy_8040_enable_set, /* Enable set: : XXX: talk to Bob */ 1242 phy_null_enable_get, /* Enable get */ 1243 phy_null_set, /* Duplex set */ 1244 phy_null_one_get, /* Duplex get */ 1245 phy_8040_speed_set, /* Speed set */ 1246 phy_8040_speed_get, /* Speed get */ 1247 phy_null_set, /* Master set */ 1248 phy_null_zero_get, /* Master get */ 1249 phy_8040_an_set, /* ANA set */ 1250 phy_8040_an_get, /* ANA get */ 1251 phy_null_mode_set, /* Local Advert set */ 1252 phy_null_mode_get, /* Local Advert get */ 1253 phy_null_mode_get, /* Remote Advert get */ 1254 phy_8040_lb_set, /* PHY loopback set: XXX: talk to Bob */ 1255 phy_8040_lb_get, /* PHY loopback set: XXX: talk to Bob */ 1256 phy_null_interface_set, /* IO Interface set */ 1257 phy_8040_interface_get, /* IO Interface get */ 1258 NULL, /* PHY abilities mask */ 1259 NULL, 1260 NULL, 1261 phy_null_mdix_set, 1262 phy_null_mdix_get, 1263 phy_null_mdix_status_get, 1264 NULL, 1265 NULL, 1266 phy_null_medium_get, 1267 NULL, /* phy_cable_diag */ 1268 NULL, /* phy_link_change */ 1269 phy_8040_control_set, /* phy_control_set */ 1270 phy_8040_control_get, /* phy_control_get */ 1271 NULL, /* phy_reg_read */ 1272 NULL, /* phy_reg_write */ 1273 NULL, /* phy_reg_modify */ 1274 NULL, /* phy_notify */ 1275 NULL, /* pd_probe */ 1276 phy_8040_ability_advert_set, /* pd_ability_advert_set */ 1277 phy_8040_ability_advert_get, /* pd_ability_advert_get */ 1278 phy_8040_ability_advert_remote_get, /* pd_ability_remote_get */ 1279 phy_8040_ability_local_get, /* pd_ability_local_get */ 1280 phy_8040_firmware_set 1281 }; 1282 #else /* INCLUDE_PHY_8040 */ 1283 int _phy_8040_not_empty; 1284 #endif /* INCLUDE_PHY_8040 */ 1285