1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * PHY driver for Maxlinear MXL86110 4 * 5 * Copyright 2023 MaxLinear Inc. 6 * 7 */ 8 9 #include <linux/bitfield.h> 10 #include <linux/etherdevice.h> 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/phy.h> 15 16 /* PHY ID */ 17 #define PHY_ID_MXL86110 0xc1335580 18 19 /* required to access extended registers */ 20 #define MXL86110_EXTD_REG_ADDR_OFFSET 0x1E 21 #define MXL86110_EXTD_REG_ADDR_DATA 0x1F 22 #define PHY_IRQ_ENABLE_REG 0x12 23 #define PHY_IRQ_ENABLE_REG_WOL BIT(6) 24 25 /* SyncE Configuration Register - COM_EXT SYNCE_CFG */ 26 #define MXL86110_EXT_SYNCE_CFG_REG 0xA012 27 #define MXL86110_EXT_SYNCE_CFG_CLK_FRE_SEL BIT(4) 28 #define MXL86110_EXT_SYNCE_CFG_EN_SYNC_E_DURING_LNKDN BIT(5) 29 #define MXL86110_EXT_SYNCE_CFG_EN_SYNC_E BIT(6) 30 #define MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_MASK GENMASK(3, 1) 31 #define MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_125M_PLL 0 32 #define MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_25M 4 33 34 /* MAC Address registers */ 35 #define MXL86110_EXT_MAC_ADDR_CFG1 0xA007 36 #define MXL86110_EXT_MAC_ADDR_CFG2 0xA008 37 #define MXL86110_EXT_MAC_ADDR_CFG3 0xA009 38 39 #define MXL86110_EXT_WOL_CFG_REG 0xA00A 40 #define MXL86110_WOL_CFG_WOL_MASK BIT(3) 41 42 /* RGMII register */ 43 #define MXL86110_EXT_RGMII_CFG1_REG 0xA003 44 /* delay can be adjusted in steps of about 150ps */ 45 #define MXL86110_EXT_RGMII_CFG1_RX_NO_DELAY (0x0 << 10) 46 /* Closest value to 2000 ps */ 47 #define MXL86110_EXT_RGMII_CFG1_RX_DELAY_1950PS (0xD << 10) 48 #define MXL86110_EXT_RGMII_CFG1_RX_DELAY_MASK GENMASK(13, 10) 49 50 #define MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_1950PS (0xD << 0) 51 #define MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_MASK GENMASK(3, 0) 52 53 #define MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_1950PS (0xD << 4) 54 #define MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_MASK GENMASK(7, 4) 55 56 #define MXL86110_EXT_RGMII_CFG1_FULL_MASK \ 57 ((MXL86110_EXT_RGMII_CFG1_RX_DELAY_MASK) | \ 58 (MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_MASK) | \ 59 (MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_MASK)) 60 61 /* EXT Sleep Control register */ 62 #define MXL86110_UTP_EXT_SLEEP_CTRL_REG 0x27 63 #define MXL86110_UTP_EXT_SLEEP_CTRL_EN_SLEEP_SW_OFF 0 64 #define MXL86110_UTP_EXT_SLEEP_CTRL_EN_SLEEP_SW_MASK BIT(15) 65 66 /* RGMII In-Band Status and MDIO Configuration Register */ 67 #define MXL86110_EXT_RGMII_MDIO_CFG 0xA005 68 #define MXL86110_RGMII_MDIO_CFG_EPA0_MASK GENMASK(6, 6) 69 #define MXL86110_EXT_RGMII_MDIO_CFG_EBA_MASK GENMASK(5, 5) 70 #define MXL86110_EXT_RGMII_MDIO_CFG_BA_MASK GENMASK(4, 0) 71 72 #define MXL86110_MAX_LEDS 3 73 /* LED registers and defines */ 74 #define MXL86110_LED0_CFG_REG 0xA00C 75 #define MXL86110_LED1_CFG_REG 0xA00D 76 #define MXL86110_LED2_CFG_REG 0xA00E 77 78 #define MXL86110_LEDX_CFG_BLINK BIT(13) 79 #define MXL86110_LEDX_CFG_LINK_UP_FULL_DUPLEX_ON BIT(12) 80 #define MXL86110_LEDX_CFG_LINK_UP_HALF_DUPLEX_ON BIT(11) 81 #define MXL86110_LEDX_CFG_LINK_UP_TX_ACT_ON BIT(10) 82 #define MXL86110_LEDX_CFG_LINK_UP_RX_ACT_ON BIT(9) 83 #define MXL86110_LEDX_CFG_LINK_UP_TX_ON BIT(8) 84 #define MXL86110_LEDX_CFG_LINK_UP_RX_ON BIT(7) 85 #define MXL86110_LEDX_CFG_LINK_UP_1GB_ON BIT(6) 86 #define MXL86110_LEDX_CFG_LINK_UP_100MB_ON BIT(5) 87 #define MXL86110_LEDX_CFG_LINK_UP_10MB_ON BIT(4) 88 #define MXL86110_LEDX_CFG_LINK_UP_COLLISION BIT(3) 89 #define MXL86110_LEDX_CFG_LINK_UP_1GB_BLINK BIT(2) 90 #define MXL86110_LEDX_CFG_LINK_UP_100MB_BLINK BIT(1) 91 #define MXL86110_LEDX_CFG_LINK_UP_10MB_BLINK BIT(0) 92 93 #define MXL86110_LED_BLINK_CFG_REG 0xA00F 94 #define MXL86110_LED_BLINK_CFG_FREQ_MODE1_2HZ 0 95 #define MXL86110_LED_BLINK_CFG_FREQ_MODE1_4HZ BIT(0) 96 #define MXL86110_LED_BLINK_CFG_FREQ_MODE1_8HZ BIT(1) 97 #define MXL86110_LED_BLINK_CFG_FREQ_MODE1_16HZ (BIT(1) | BIT(0)) 98 #define MXL86110_LED_BLINK_CFG_FREQ_MODE2_2HZ 0 99 #define MXL86110_LED_BLINK_CFG_FREQ_MODE2_4HZ BIT(2) 100 #define MXL86110_LED_BLINK_CFG_FREQ_MODE2_8HZ BIT(3) 101 #define MXL86110_LED_BLINK_CFG_FREQ_MODE2_16HZ (BIT(3) | BIT(2)) 102 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_50_ON 0 103 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_67_ON (BIT(4)) 104 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_75_ON (BIT(5)) 105 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_83_ON (BIT(5) | BIT(4)) 106 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_50_OFF (BIT(6)) 107 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_33_ON (BIT(6) | BIT(4)) 108 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_25_ON (BIT(6) | BIT(5)) 109 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_17_ON (BIT(6) | BIT(5) | BIT(4)) 110 111 /* Chip Configuration Register - COM_EXT_CHIP_CFG */ 112 #define MXL86110_EXT_CHIP_CFG_REG 0xA001 113 #define MXL86110_EXT_CHIP_CFG_RXDLY_ENABLE BIT(8) 114 #define MXL86110_EXT_CHIP_CFG_SW_RST_N_MODE BIT(15) 115 116 /** 117 * __mxl86110_write_extended_reg() - write to a PHY's extended register 118 * @phydev: pointer to the PHY device structure 119 * @regnum: register number to write 120 * @val: value to write to @regnum 121 * 122 * Unlocked version of mxl86110_write_extended_reg 123 * 124 * Note: This function assumes the caller already holds the MDIO bus lock 125 * or otherwise has exclusive access to the PHY. 126 * 127 * Return: 0 or negative error code 128 */ 129 static int __mxl86110_write_extended_reg(struct phy_device *phydev, 130 u16 regnum, u16 val) 131 { 132 int ret; 133 134 ret = __phy_write(phydev, MXL86110_EXTD_REG_ADDR_OFFSET, regnum); 135 if (ret < 0) 136 return ret; 137 138 return __phy_write(phydev, MXL86110_EXTD_REG_ADDR_DATA, val); 139 } 140 141 /** 142 * __mxl86110_read_extended_reg - Read a PHY's extended register 143 * @phydev: pointer to the PHY device structure 144 * @regnum: extended register number to read (address written to reg 30) 145 * 146 * Unlocked version of mxl86110_read_extended_reg 147 * 148 * Reads the content of a PHY extended register using the MaxLinear 149 * 2-step access mechanism: write the register address to reg 30 (0x1E), 150 * then read the value from reg 31 (0x1F). 151 * 152 * Note: This function assumes the caller already holds the MDIO bus lock 153 * or otherwise has exclusive access to the PHY. 154 * 155 * Return: 16-bit register value on success, or negative errno code on failure. 156 */ 157 static int __mxl86110_read_extended_reg(struct phy_device *phydev, u16 regnum) 158 { 159 int ret; 160 161 ret = __phy_write(phydev, MXL86110_EXTD_REG_ADDR_OFFSET, regnum); 162 if (ret < 0) 163 return ret; 164 return __phy_read(phydev, MXL86110_EXTD_REG_ADDR_DATA); 165 } 166 167 /** 168 * __mxl86110_modify_extended_reg() - modify bits of a PHY's extended register 169 * @phydev: pointer to the PHY device structure 170 * @regnum: register number to write 171 * @mask: bit mask of bits to clear 172 * @set: bit mask of bits to set 173 * 174 * Note: register value = (old register value & ~mask) | set. 175 * This function assumes the caller already holds the MDIO bus lock 176 * or otherwise has exclusive access to the PHY. 177 * 178 * Return: 0 or negative error code 179 */ 180 static int __mxl86110_modify_extended_reg(struct phy_device *phydev, 181 u16 regnum, u16 mask, u16 set) 182 { 183 int ret; 184 185 ret = __phy_write(phydev, MXL86110_EXTD_REG_ADDR_OFFSET, regnum); 186 if (ret < 0) 187 return ret; 188 189 return __phy_modify(phydev, MXL86110_EXTD_REG_ADDR_DATA, mask, set); 190 } 191 192 /** 193 * mxl86110_write_extended_reg() - Write to a PHY's extended register 194 * @phydev: pointer to the PHY device structure 195 * @regnum: register number to write 196 * @val: value to write to @regnum 197 * 198 * This function writes to an extended register of the PHY using the 199 * MaxLinear two-step access method (reg 0x1E/0x1F). It handles acquiring 200 * and releasing the MDIO bus lock internally. 201 * 202 * Return: 0 or negative error code 203 */ 204 static int mxl86110_write_extended_reg(struct phy_device *phydev, 205 u16 regnum, u16 val) 206 { 207 int ret; 208 209 phy_lock_mdio_bus(phydev); 210 ret = __mxl86110_write_extended_reg(phydev, regnum, val); 211 phy_unlock_mdio_bus(phydev); 212 213 return ret; 214 } 215 216 /** 217 * mxl86110_read_extended_reg() - Read a PHY's extended register 218 * @phydev: pointer to the PHY device structure 219 * @regnum: extended register number to read 220 * 221 * This function reads from an extended register of the PHY using the 222 * MaxLinear two-step access method (reg 0x1E/0x1F). It handles acquiring 223 * and releasing the MDIO bus lock internally. 224 * 225 * Return: 16-bit register value on success, or negative errno code on failure 226 */ 227 static int mxl86110_read_extended_reg(struct phy_device *phydev, u16 regnum) 228 { 229 int ret; 230 231 phy_lock_mdio_bus(phydev); 232 ret = __mxl86110_read_extended_reg(phydev, regnum); 233 phy_unlock_mdio_bus(phydev); 234 235 return ret; 236 } 237 238 /** 239 * mxl86110_get_wol() - report if wake-on-lan is enabled 240 * @phydev: pointer to the phy_device 241 * @wol: a pointer to a &struct ethtool_wolinfo 242 */ 243 static void mxl86110_get_wol(struct phy_device *phydev, 244 struct ethtool_wolinfo *wol) 245 { 246 int val; 247 248 wol->supported = WAKE_MAGIC; 249 wol->wolopts = 0; 250 val = mxl86110_read_extended_reg(phydev, MXL86110_EXT_WOL_CFG_REG); 251 if (val >= 0 && (val & MXL86110_WOL_CFG_WOL_MASK)) 252 wol->wolopts |= WAKE_MAGIC; 253 } 254 255 /** 256 * mxl86110_set_wol() - enable/disable wake-on-lan 257 * @phydev: pointer to the phy_device 258 * @wol: a pointer to a &struct ethtool_wolinfo 259 * 260 * Configures the WOL Magic Packet MAC 261 * 262 * Return: 0 or negative errno code 263 */ 264 static int mxl86110_set_wol(struct phy_device *phydev, 265 struct ethtool_wolinfo *wol) 266 { 267 struct net_device *netdev; 268 const unsigned char *mac; 269 int ret = 0; 270 271 phy_lock_mdio_bus(phydev); 272 273 if (wol->wolopts & WAKE_MAGIC) { 274 netdev = phydev->attached_dev; 275 if (!netdev) { 276 ret = -ENODEV; 277 goto out; 278 } 279 280 /* Configure the MAC address of the WOL magic packet */ 281 mac = netdev->dev_addr; 282 ret = __mxl86110_write_extended_reg(phydev, 283 MXL86110_EXT_MAC_ADDR_CFG1, 284 ((mac[0] << 8) | mac[1])); 285 if (ret < 0) 286 goto out; 287 288 ret = __mxl86110_write_extended_reg(phydev, 289 MXL86110_EXT_MAC_ADDR_CFG2, 290 ((mac[2] << 8) | mac[3])); 291 if (ret < 0) 292 goto out; 293 294 ret = __mxl86110_write_extended_reg(phydev, 295 MXL86110_EXT_MAC_ADDR_CFG3, 296 ((mac[4] << 8) | mac[5])); 297 if (ret < 0) 298 goto out; 299 300 ret = __mxl86110_modify_extended_reg(phydev, 301 MXL86110_EXT_WOL_CFG_REG, 302 MXL86110_WOL_CFG_WOL_MASK, 303 MXL86110_WOL_CFG_WOL_MASK); 304 if (ret < 0) 305 goto out; 306 307 /* Enables Wake-on-LAN interrupt in the PHY. */ 308 ret = __phy_modify(phydev, PHY_IRQ_ENABLE_REG, 0, 309 PHY_IRQ_ENABLE_REG_WOL); 310 if (ret < 0) 311 goto out; 312 313 phydev_dbg(phydev, 314 "%s, MAC Addr: %02X:%02X:%02X:%02X:%02X:%02X\n", 315 __func__, 316 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 317 } else { 318 ret = __mxl86110_modify_extended_reg(phydev, 319 MXL86110_EXT_WOL_CFG_REG, 320 MXL86110_WOL_CFG_WOL_MASK, 321 0); 322 if (ret < 0) 323 goto out; 324 325 /* Disables Wake-on-LAN interrupt in the PHY. */ 326 ret = __phy_modify(phydev, PHY_IRQ_ENABLE_REG, 327 PHY_IRQ_ENABLE_REG_WOL, 0); 328 } 329 330 out: 331 phy_unlock_mdio_bus(phydev); 332 return ret; 333 } 334 335 static const unsigned long supported_trgs = (BIT(TRIGGER_NETDEV_LINK_10) | 336 BIT(TRIGGER_NETDEV_LINK_100) | 337 BIT(TRIGGER_NETDEV_LINK_1000) | 338 BIT(TRIGGER_NETDEV_HALF_DUPLEX) | 339 BIT(TRIGGER_NETDEV_FULL_DUPLEX) | 340 BIT(TRIGGER_NETDEV_TX) | 341 BIT(TRIGGER_NETDEV_RX)); 342 343 static int mxl86110_led_hw_is_supported(struct phy_device *phydev, u8 index, 344 unsigned long rules) 345 { 346 if (index >= MXL86110_MAX_LEDS) 347 return -EINVAL; 348 349 /* All combinations of the supported triggers are allowed */ 350 if (rules & ~supported_trgs) 351 return -EOPNOTSUPP; 352 353 return 0; 354 } 355 356 static int mxl86110_led_hw_control_get(struct phy_device *phydev, u8 index, 357 unsigned long *rules) 358 { 359 int val; 360 361 if (index >= MXL86110_MAX_LEDS) 362 return -EINVAL; 363 364 val = mxl86110_read_extended_reg(phydev, 365 MXL86110_LED0_CFG_REG + index); 366 if (val < 0) 367 return val; 368 369 if (val & MXL86110_LEDX_CFG_LINK_UP_TX_ACT_ON) 370 *rules |= BIT(TRIGGER_NETDEV_TX); 371 372 if (val & MXL86110_LEDX_CFG_LINK_UP_RX_ACT_ON) 373 *rules |= BIT(TRIGGER_NETDEV_RX); 374 375 if (val & MXL86110_LEDX_CFG_LINK_UP_HALF_DUPLEX_ON) 376 *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX); 377 378 if (val & MXL86110_LEDX_CFG_LINK_UP_FULL_DUPLEX_ON) 379 *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX); 380 381 if (val & MXL86110_LEDX_CFG_LINK_UP_10MB_ON) 382 *rules |= BIT(TRIGGER_NETDEV_LINK_10); 383 384 if (val & MXL86110_LEDX_CFG_LINK_UP_100MB_ON) 385 *rules |= BIT(TRIGGER_NETDEV_LINK_100); 386 387 if (val & MXL86110_LEDX_CFG_LINK_UP_1GB_ON) 388 *rules |= BIT(TRIGGER_NETDEV_LINK_1000); 389 390 return 0; 391 } 392 393 static int mxl86110_led_hw_control_set(struct phy_device *phydev, u8 index, 394 unsigned long rules) 395 { 396 u16 val = 0; 397 398 if (index >= MXL86110_MAX_LEDS) 399 return -EINVAL; 400 401 if (rules & BIT(TRIGGER_NETDEV_LINK_10)) 402 val |= MXL86110_LEDX_CFG_LINK_UP_10MB_ON; 403 404 if (rules & BIT(TRIGGER_NETDEV_LINK_100)) 405 val |= MXL86110_LEDX_CFG_LINK_UP_100MB_ON; 406 407 if (rules & BIT(TRIGGER_NETDEV_LINK_1000)) 408 val |= MXL86110_LEDX_CFG_LINK_UP_1GB_ON; 409 410 if (rules & BIT(TRIGGER_NETDEV_TX)) 411 val |= MXL86110_LEDX_CFG_LINK_UP_TX_ACT_ON; 412 413 if (rules & BIT(TRIGGER_NETDEV_RX)) 414 val |= MXL86110_LEDX_CFG_LINK_UP_RX_ACT_ON; 415 416 if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) 417 val |= MXL86110_LEDX_CFG_LINK_UP_HALF_DUPLEX_ON; 418 419 if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) 420 val |= MXL86110_LEDX_CFG_LINK_UP_FULL_DUPLEX_ON; 421 422 if (rules & BIT(TRIGGER_NETDEV_TX) || 423 rules & BIT(TRIGGER_NETDEV_RX)) 424 val |= MXL86110_LEDX_CFG_BLINK; 425 426 return mxl86110_write_extended_reg(phydev, 427 MXL86110_LED0_CFG_REG + index, val); 428 } 429 430 /** 431 * mxl86110_synce_clk_cfg() - applies syncE/clk output configuration 432 * @phydev: pointer to the phy_device 433 * 434 * Note: This function assumes the caller already holds the MDIO bus lock 435 * or otherwise has exclusive access to the PHY. 436 * 437 * Return: 0 or negative errno code 438 */ 439 static int mxl86110_synce_clk_cfg(struct phy_device *phydev) 440 { 441 u16 mask = 0, val = 0; 442 443 /* 444 * Configures the clock output to its default 445 * setting as per the datasheet. 446 * This results in a 25MHz clock output being selected in the 447 * COM_EXT_SYNCE_CFG register for SyncE configuration. 448 */ 449 val = MXL86110_EXT_SYNCE_CFG_EN_SYNC_E | 450 FIELD_PREP(MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_MASK, 451 MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_25M); 452 mask = MXL86110_EXT_SYNCE_CFG_EN_SYNC_E | 453 MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_MASK | 454 MXL86110_EXT_SYNCE_CFG_CLK_FRE_SEL; 455 456 /* Write clock output configuration */ 457 return __mxl86110_modify_extended_reg(phydev, 458 MXL86110_EXT_SYNCE_CFG_REG, 459 mask, val); 460 } 461 462 /** 463 * mxl86110_broadcast_cfg - Configure MDIO broadcast setting for PHY 464 * @phydev: Pointer to the PHY device structure 465 * 466 * This function configures the MDIO broadcast behavior of the MxL86110 PHY. 467 * Currently, broadcast mode is explicitly disabled by clearing the EPA0 bit 468 * in the RGMII_MDIO_CFG extended register. 469 * 470 * Note: This function assumes the caller already holds the MDIO bus lock 471 * or otherwise has exclusive access to the PHY. 472 * 473 * Return: 0 on success or a negative errno code on failure. 474 */ 475 static int mxl86110_broadcast_cfg(struct phy_device *phydev) 476 { 477 return __mxl86110_modify_extended_reg(phydev, 478 MXL86110_EXT_RGMII_MDIO_CFG, 479 MXL86110_RGMII_MDIO_CFG_EPA0_MASK, 480 0); 481 } 482 483 /** 484 * mxl86110_enable_led_activity_blink - Enable LEDs activity blink on PHY 485 * @phydev: Pointer to the PHY device structure 486 * 487 * Configure all PHY LEDs to blink on traffic activity regardless of whether 488 * they are ON or OFF. This behavior allows each LED to serve as a pure activity 489 * indicator, independently of its use as a link status indicator. 490 * 491 * By default, each LED blinks only when it is also in the ON state. 492 * This function modifies the appropriate registers (LABx fields) 493 * to enable blinking even when the LEDs are OFF, to allow the LED to be used 494 * as a traffic indicator without requiring it to also serve 495 * as a link status LED. 496 * 497 * Note: Any further LED customization can be performed via the 498 * /sys/class/leds interface; the functions led_hw_is_supported, 499 * led_hw_control_get, and led_hw_control_set are used 500 * to support this mechanism. 501 * 502 * This function assumes the caller already holds the MDIO bus lock 503 * or otherwise has exclusive access to the PHY. 504 * 505 * Return: 0 on success or a negative errno code on failure. 506 */ 507 static int mxl86110_enable_led_activity_blink(struct phy_device *phydev) 508 { 509 int i, ret = 0; 510 511 for (i = 0; i < MXL86110_MAX_LEDS; i++) { 512 ret = __mxl86110_modify_extended_reg(phydev, 513 MXL86110_LED0_CFG_REG + i, 514 0, 515 MXL86110_LEDX_CFG_BLINK); 516 if (ret < 0) 517 break; 518 } 519 520 return ret; 521 } 522 523 /** 524 * mxl86110_config_init() - initialize the PHY 525 * @phydev: pointer to the phy_device 526 * 527 * Return: 0 or negative errno code 528 */ 529 static int mxl86110_config_init(struct phy_device *phydev) 530 { 531 u16 val = 0; 532 int ret; 533 534 phy_lock_mdio_bus(phydev); 535 536 /* configure syncE / clk output */ 537 ret = mxl86110_synce_clk_cfg(phydev); 538 if (ret < 0) 539 goto out; 540 541 switch (phydev->interface) { 542 case PHY_INTERFACE_MODE_RGMII: 543 val = 0; 544 break; 545 case PHY_INTERFACE_MODE_RGMII_RXID: 546 val = MXL86110_EXT_RGMII_CFG1_RX_DELAY_1950PS; 547 break; 548 case PHY_INTERFACE_MODE_RGMII_TXID: 549 val = MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_1950PS | 550 MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_1950PS; 551 break; 552 case PHY_INTERFACE_MODE_RGMII_ID: 553 val = MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_1950PS | 554 MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_1950PS | 555 MXL86110_EXT_RGMII_CFG1_RX_DELAY_1950PS; 556 break; 557 default: 558 ret = -EINVAL; 559 goto out; 560 } 561 562 ret = __mxl86110_modify_extended_reg(phydev, 563 MXL86110_EXT_RGMII_CFG1_REG, 564 MXL86110_EXT_RGMII_CFG1_FULL_MASK, 565 val); 566 if (ret < 0) 567 goto out; 568 569 /* Configure RXDLY (RGMII Rx Clock Delay) to disable 570 * the default additional delay value on RX_CLK 571 * (2 ns for 125 MHz, 8 ns for 25 MHz/2.5 MHz) 572 * and use just the digital one selected before 573 */ 574 ret = __mxl86110_modify_extended_reg(phydev, 575 MXL86110_EXT_CHIP_CFG_REG, 576 MXL86110_EXT_CHIP_CFG_RXDLY_ENABLE, 577 0); 578 if (ret < 0) 579 goto out; 580 581 ret = mxl86110_enable_led_activity_blink(phydev); 582 if (ret < 0) 583 goto out; 584 585 ret = mxl86110_broadcast_cfg(phydev); 586 587 out: 588 phy_unlock_mdio_bus(phydev); 589 return ret; 590 } 591 592 static struct phy_driver mxl_phy_drvs[] = { 593 { 594 PHY_ID_MATCH_EXACT(PHY_ID_MXL86110), 595 .name = "MXL86110 Gigabit Ethernet", 596 .config_init = mxl86110_config_init, 597 .get_wol = mxl86110_get_wol, 598 .set_wol = mxl86110_set_wol, 599 .led_hw_is_supported = mxl86110_led_hw_is_supported, 600 .led_hw_control_get = mxl86110_led_hw_control_get, 601 .led_hw_control_set = mxl86110_led_hw_control_set, 602 }, 603 }; 604 605 module_phy_driver(mxl_phy_drvs); 606 607 static const struct mdio_device_id __maybe_unused mxl_tbl[] = { 608 { PHY_ID_MATCH_EXACT(PHY_ID_MXL86110) }, 609 { } 610 }; 611 612 MODULE_DEVICE_TABLE(mdio, mxl_tbl); 613 614 MODULE_DESCRIPTION("MaxLinear MXL86110 PHY driver"); 615 MODULE_AUTHOR("Stefano Radaelli"); 616 MODULE_LICENSE("GPL"); 617