1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2 /* Copyright 2020 NXP 3 * Lynx PCS MDIO helpers 4 */ 5 6 #include <linux/mdio.h> 7 #include <linux/phylink.h> 8 #include <linux/pcs-lynx.h> 9 #include <linux/property.h> 10 11 #define SGMII_CLOCK_PERIOD_NS 8 /* PCS is clocked at 125 MHz */ 12 #define LINK_TIMER_VAL(ns) ((u32)((ns) / SGMII_CLOCK_PERIOD_NS)) 13 14 #define LINK_TIMER_LO 0x12 15 #define LINK_TIMER_HI 0x13 16 #define IF_MODE 0x14 17 #define IF_MODE_SGMII_EN BIT(0) 18 #define IF_MODE_USE_SGMII_AN BIT(1) 19 #define IF_MODE_SPEED(x) (((x) << 2) & GENMASK(3, 2)) 20 #define IF_MODE_SPEED_MSK GENMASK(3, 2) 21 #define IF_MODE_HALF_DUPLEX BIT(4) 22 23 struct lynx_pcs { 24 struct phylink_pcs pcs; 25 struct mdio_device *mdio; 26 }; 27 28 enum sgmii_speed { 29 SGMII_SPEED_10 = 0, 30 SGMII_SPEED_100 = 1, 31 SGMII_SPEED_1000 = 2, 32 SGMII_SPEED_2500 = 2, 33 }; 34 35 #define phylink_pcs_to_lynx(pl_pcs) container_of((pl_pcs), struct lynx_pcs, pcs) 36 #define lynx_to_phylink_pcs(lynx) (&(lynx)->pcs) 37 38 static unsigned int lynx_pcs_inband_caps(struct phylink_pcs *pcs, 39 phy_interface_t interface) 40 { 41 switch (interface) { 42 case PHY_INTERFACE_MODE_1000BASEX: 43 case PHY_INTERFACE_MODE_SGMII: 44 case PHY_INTERFACE_MODE_QSGMII: 45 return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; 46 47 case PHY_INTERFACE_MODE_10GBASER: 48 case PHY_INTERFACE_MODE_2500BASEX: 49 return LINK_INBAND_DISABLE; 50 51 case PHY_INTERFACE_MODE_USXGMII: 52 return LINK_INBAND_ENABLE; 53 54 default: 55 return 0; 56 } 57 } 58 59 static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs, 60 struct phylink_link_state *state) 61 { 62 struct mii_bus *bus = pcs->bus; 63 int addr = pcs->addr; 64 int status, lpa; 65 66 status = mdiobus_c45_read(bus, addr, MDIO_MMD_VEND2, MII_BMSR); 67 if (status < 0) 68 return; 69 70 state->link = !!(status & MDIO_STAT1_LSTATUS); 71 state->an_complete = !!(status & MDIO_AN_STAT1_COMPLETE); 72 if (!state->link || !state->an_complete) 73 return; 74 75 lpa = mdiobus_c45_read(bus, addr, MDIO_MMD_VEND2, MII_LPA); 76 if (lpa < 0) 77 return; 78 79 phylink_decode_usxgmii_word(state, lpa); 80 } 81 82 static void lynx_pcs_get_state_2500basex(struct mdio_device *pcs, 83 struct phylink_link_state *state) 84 { 85 int bmsr; 86 87 bmsr = mdiodev_read(pcs, MII_BMSR); 88 if (bmsr < 0) { 89 state->link = false; 90 return; 91 } 92 93 state->link = !!(bmsr & BMSR_LSTATUS); 94 state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); 95 if (!state->link) 96 return; 97 98 state->speed = SPEED_2500; 99 state->pause |= MLO_PAUSE_TX | MLO_PAUSE_RX; 100 state->duplex = DUPLEX_FULL; 101 } 102 103 static void lynx_pcs_get_state(struct phylink_pcs *pcs, 104 struct phylink_link_state *state) 105 { 106 struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs); 107 108 switch (state->interface) { 109 case PHY_INTERFACE_MODE_1000BASEX: 110 case PHY_INTERFACE_MODE_SGMII: 111 case PHY_INTERFACE_MODE_QSGMII: 112 phylink_mii_c22_pcs_get_state(lynx->mdio, state); 113 break; 114 case PHY_INTERFACE_MODE_2500BASEX: 115 lynx_pcs_get_state_2500basex(lynx->mdio, state); 116 break; 117 case PHY_INTERFACE_MODE_USXGMII: 118 lynx_pcs_get_state_usxgmii(lynx->mdio, state); 119 break; 120 case PHY_INTERFACE_MODE_10GBASER: 121 phylink_mii_c45_pcs_get_state(lynx->mdio, state); 122 break; 123 default: 124 break; 125 } 126 127 dev_dbg(&lynx->mdio->dev, 128 "mode=%s/%s/%s link=%u an_complete=%u\n", 129 phy_modes(state->interface), 130 phy_speed_to_str(state->speed), 131 phy_duplex_to_str(state->duplex), 132 state->link, state->an_complete); 133 } 134 135 static int lynx_pcs_config_giga(struct mdio_device *pcs, 136 phy_interface_t interface, 137 const unsigned long *advertising, 138 unsigned int neg_mode) 139 { 140 int link_timer_ns; 141 u32 link_timer; 142 u16 if_mode; 143 int err; 144 145 link_timer_ns = phylink_get_link_timer_ns(interface); 146 if (link_timer_ns > 0) { 147 link_timer = LINK_TIMER_VAL(link_timer_ns); 148 149 mdiodev_write(pcs, LINK_TIMER_LO, link_timer & 0xffff); 150 mdiodev_write(pcs, LINK_TIMER_HI, link_timer >> 16); 151 } 152 153 if (interface == PHY_INTERFACE_MODE_1000BASEX) { 154 if_mode = 0; 155 } else { 156 /* SGMII and QSGMII */ 157 if_mode = IF_MODE_SGMII_EN; 158 if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) 159 if_mode |= IF_MODE_USE_SGMII_AN; 160 } 161 162 err = mdiodev_modify(pcs, IF_MODE, 163 IF_MODE_SGMII_EN | IF_MODE_USE_SGMII_AN, 164 if_mode); 165 if (err) 166 return err; 167 168 return phylink_mii_c22_pcs_config(pcs, interface, advertising, 169 neg_mode); 170 } 171 172 static int lynx_pcs_config_usxgmii(struct mdio_device *pcs, 173 const unsigned long *advertising, 174 unsigned int neg_mode) 175 { 176 struct mii_bus *bus = pcs->bus; 177 int addr = pcs->addr; 178 179 if (neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED) { 180 dev_err(&pcs->dev, "USXGMII only supports in-band AN for now\n"); 181 return -EOPNOTSUPP; 182 } 183 184 /* Configure device ability for the USXGMII Replicator */ 185 return mdiobus_c45_write(bus, addr, MDIO_MMD_VEND2, MII_ADVERTISE, 186 MDIO_USXGMII_10G | MDIO_USXGMII_LINK | 187 MDIO_USXGMII_FULL_DUPLEX | 188 ADVERTISE_SGMII | ADVERTISE_LPACK); 189 } 190 191 static int lynx_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, 192 phy_interface_t ifmode, 193 const unsigned long *advertising, bool permit) 194 { 195 struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs); 196 197 switch (ifmode) { 198 case PHY_INTERFACE_MODE_1000BASEX: 199 case PHY_INTERFACE_MODE_SGMII: 200 case PHY_INTERFACE_MODE_QSGMII: 201 return lynx_pcs_config_giga(lynx->mdio, ifmode, advertising, 202 neg_mode); 203 case PHY_INTERFACE_MODE_2500BASEX: 204 if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { 205 dev_err(&lynx->mdio->dev, 206 "AN not supported on 3.125GHz SerDes lane\n"); 207 return -EOPNOTSUPP; 208 } 209 break; 210 case PHY_INTERFACE_MODE_USXGMII: 211 return lynx_pcs_config_usxgmii(lynx->mdio, advertising, 212 neg_mode); 213 case PHY_INTERFACE_MODE_10GBASER: 214 /* Nothing to do here for 10GBASER */ 215 break; 216 default: 217 return -EOPNOTSUPP; 218 } 219 220 return 0; 221 } 222 223 static void lynx_pcs_an_restart(struct phylink_pcs *pcs) 224 { 225 struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs); 226 227 phylink_mii_c22_pcs_an_restart(lynx->mdio); 228 } 229 230 static void lynx_pcs_link_up_sgmii(struct mdio_device *pcs, 231 unsigned int neg_mode, 232 int speed, int duplex) 233 { 234 u16 if_mode = 0, sgmii_speed; 235 236 /* The PCS needs to be configured manually only 237 * when not operating on in-band mode 238 */ 239 if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) 240 return; 241 242 if (duplex == DUPLEX_HALF) 243 if_mode |= IF_MODE_HALF_DUPLEX; 244 245 switch (speed) { 246 case SPEED_1000: 247 sgmii_speed = SGMII_SPEED_1000; 248 break; 249 case SPEED_100: 250 sgmii_speed = SGMII_SPEED_100; 251 break; 252 case SPEED_10: 253 sgmii_speed = SGMII_SPEED_10; 254 break; 255 case SPEED_UNKNOWN: 256 /* Silently don't do anything */ 257 return; 258 default: 259 dev_err(&pcs->dev, "Invalid PCS speed %d\n", speed); 260 return; 261 } 262 if_mode |= IF_MODE_SPEED(sgmii_speed); 263 264 mdiodev_modify(pcs, IF_MODE, 265 IF_MODE_HALF_DUPLEX | IF_MODE_SPEED_MSK, 266 if_mode); 267 } 268 269 /* 2500Base-X is SerDes protocol 7 on Felix and 6 on ENETC. It is a SerDes lane 270 * clocked at 3.125 GHz which encodes symbols with 8b/10b and does not have 271 * auto-negotiation of any link parameters. Electrically it is compatible with 272 * a single lane of XAUI. 273 * The hardware reference manual wants to call this mode SGMII, but it isn't 274 * really, since the fundamental features of SGMII: 275 * - Downgrading the link speed by duplicating symbols 276 * - Auto-negotiation 277 * are not there. 278 * The speed is configured at 1000 in the IF_MODE because the clock frequency 279 * is actually given by a PLL configured in the Reset Configuration Word (RCW). 280 * Since there is no difference between fixed speed SGMII w/o AN and 802.3z w/o 281 * AN, we call this PHY interface type 2500Base-X. In case a PHY negotiates a 282 * lower link speed on line side, the system-side interface remains fixed at 283 * 2500 Mbps and we do rate adaptation through pause frames. 284 */ 285 static void lynx_pcs_link_up_2500basex(struct mdio_device *pcs, 286 unsigned int neg_mode, 287 int speed, int duplex) 288 { 289 u16 if_mode = 0; 290 291 if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { 292 dev_err(&pcs->dev, "AN not supported for 2500BaseX\n"); 293 return; 294 } 295 296 if (duplex == DUPLEX_HALF) 297 if_mode |= IF_MODE_HALF_DUPLEX; 298 if_mode |= IF_MODE_SPEED(SGMII_SPEED_2500); 299 300 mdiodev_modify(pcs, IF_MODE, 301 IF_MODE_HALF_DUPLEX | IF_MODE_SPEED_MSK, 302 if_mode); 303 } 304 305 static void lynx_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, 306 phy_interface_t interface, 307 int speed, int duplex) 308 { 309 struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs); 310 311 switch (interface) { 312 case PHY_INTERFACE_MODE_SGMII: 313 case PHY_INTERFACE_MODE_QSGMII: 314 lynx_pcs_link_up_sgmii(lynx->mdio, neg_mode, speed, duplex); 315 break; 316 case PHY_INTERFACE_MODE_2500BASEX: 317 lynx_pcs_link_up_2500basex(lynx->mdio, neg_mode, speed, duplex); 318 break; 319 case PHY_INTERFACE_MODE_USXGMII: 320 /* At the moment, only in-band AN is supported for USXGMII 321 * so nothing to do in link_up 322 */ 323 break; 324 default: 325 break; 326 } 327 } 328 329 static const struct phylink_pcs_ops lynx_pcs_phylink_ops = { 330 .pcs_inband_caps = lynx_pcs_inband_caps, 331 .pcs_get_state = lynx_pcs_get_state, 332 .pcs_config = lynx_pcs_config, 333 .pcs_an_restart = lynx_pcs_an_restart, 334 .pcs_link_up = lynx_pcs_link_up, 335 }; 336 337 static const phy_interface_t lynx_interfaces[] = { 338 PHY_INTERFACE_MODE_SGMII, 339 PHY_INTERFACE_MODE_QSGMII, 340 PHY_INTERFACE_MODE_1000BASEX, 341 PHY_INTERFACE_MODE_2500BASEX, 342 PHY_INTERFACE_MODE_10GBASER, 343 PHY_INTERFACE_MODE_USXGMII, 344 }; 345 346 static struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio) 347 { 348 struct lynx_pcs *lynx; 349 int i; 350 351 lynx = kzalloc(sizeof(*lynx), GFP_KERNEL); 352 if (!lynx) 353 return ERR_PTR(-ENOMEM); 354 355 mdio_device_get(mdio); 356 lynx->mdio = mdio; 357 lynx->pcs.ops = &lynx_pcs_phylink_ops; 358 lynx->pcs.neg_mode = true; 359 lynx->pcs.poll = true; 360 361 for (i = 0; i < ARRAY_SIZE(lynx_interfaces); i++) 362 __set_bit(lynx_interfaces[i], lynx->pcs.supported_interfaces); 363 364 return lynx_to_phylink_pcs(lynx); 365 } 366 367 struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr) 368 { 369 struct mdio_device *mdio; 370 struct phylink_pcs *pcs; 371 372 mdio = mdio_device_create(bus, addr); 373 if (IS_ERR(mdio)) 374 return ERR_CAST(mdio); 375 376 pcs = lynx_pcs_create(mdio); 377 378 /* lynx_create() has taken a refcount on the mdiodev if it was 379 * successful. If lynx_create() fails, this will free the mdio 380 * device here. In any case, we don't need to hold our reference 381 * anymore, and putting it here will allow mdio_device_put() in 382 * lynx_destroy() to automatically free the mdio device. 383 */ 384 mdio_device_put(mdio); 385 386 return pcs; 387 } 388 EXPORT_SYMBOL(lynx_pcs_create_mdiodev); 389 390 /* 391 * lynx_pcs_create_fwnode() creates a lynx PCS instance from the fwnode 392 * device indicated by node. 393 * 394 * Returns: 395 * -ENODEV if the fwnode is marked unavailable 396 * -EPROBE_DEFER if we fail to find the device 397 * -ENOMEM if we fail to allocate memory 398 * pointer to a phylink_pcs on success 399 */ 400 struct phylink_pcs *lynx_pcs_create_fwnode(struct fwnode_handle *node) 401 { 402 struct mdio_device *mdio; 403 struct phylink_pcs *pcs; 404 405 if (!fwnode_device_is_available(node)) 406 return ERR_PTR(-ENODEV); 407 408 mdio = fwnode_mdio_find_device(node); 409 if (!mdio) 410 return ERR_PTR(-EPROBE_DEFER); 411 412 pcs = lynx_pcs_create(mdio); 413 414 /* lynx_create() has taken a refcount on the mdiodev if it was 415 * successful. If lynx_create() fails, this will free the mdio 416 * device here. In any case, we don't need to hold our reference 417 * anymore, and putting it here will allow mdio_device_put() in 418 * lynx_destroy() to automatically free the mdio device. 419 */ 420 mdio_device_put(mdio); 421 422 return pcs; 423 } 424 EXPORT_SYMBOL_GPL(lynx_pcs_create_fwnode); 425 426 void lynx_pcs_destroy(struct phylink_pcs *pcs) 427 { 428 struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs); 429 430 mdio_device_put(lynx->mdio); 431 kfree(lynx); 432 } 433 EXPORT_SYMBOL(lynx_pcs_destroy); 434 435 MODULE_DESCRIPTION("NXP Lynx PCS phylink library"); 436 MODULE_LICENSE("Dual BSD/GPL"); 437