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 #define PHY_ID_MXL86111 0xc1335588 19 20 /* required to access extended registers */ 21 #define MXL86110_EXTD_REG_ADDR_OFFSET 0x1E 22 #define MXL86110_EXTD_REG_ADDR_DATA 0x1F 23 #define PHY_IRQ_ENABLE_REG 0x12 24 #define PHY_IRQ_ENABLE_REG_WOL BIT(6) 25 26 /* different pages for EXTD access for MXL86111 */ 27 /* SerDes/PHY Control Access Register - COM_EXT_SMI_SDS_PHY */ 28 #define MXL86111_EXT_SMI_SDS_PHY_REG 0xA000 29 #define MXL86111_EXT_SMI_SDS_PHYSPACE_MASK BIT(1) 30 #define MXL86111_EXT_SMI_SDS_PHYFIBER_SPACE (0x1 << 1) 31 #define MXL86111_EXT_SMI_SDS_PHYUTP_SPACE (0x0 << 1) 32 #define MXL86111_EXT_SMI_SDS_PHY_AUTO 0xff 33 34 /* SyncE Configuration Register - COM_EXT_SYNCE_CFG */ 35 #define MXL86110_EXT_SYNCE_CFG_REG 0xA012 36 #define MXL86110_EXT_SYNCE_CFG_CLK_FRE_SEL BIT(4) 37 #define MXL86110_EXT_SYNCE_CFG_EN_SYNC_E_DURING_LNKDN BIT(5) 38 #define MXL86110_EXT_SYNCE_CFG_EN_SYNC_E BIT(6) 39 #define MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_MASK GENMASK(3, 1) 40 #define MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_125M_PLL 0 41 #define MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_25M 4 42 43 /* MAC Address registers */ 44 #define MXL86110_EXT_MAC_ADDR_CFG1 0xA007 45 #define MXL86110_EXT_MAC_ADDR_CFG2 0xA008 46 #define MXL86110_EXT_MAC_ADDR_CFG3 0xA009 47 48 #define MXL86110_EXT_WOL_CFG_REG 0xA00A 49 #define MXL86110_WOL_CFG_WOL_MASK BIT(3) 50 51 /* RGMII register */ 52 #define MXL86110_EXT_RGMII_CFG1_REG 0xA003 53 /* delay can be adjusted in steps of about 150ps */ 54 #define MXL86110_EXT_RGMII_CFG1_RX_NO_DELAY (0x0 << 10) 55 /* Closest value to 2000 ps */ 56 #define MXL86110_EXT_RGMII_CFG1_RX_DELAY_1950PS (0xD << 10) 57 #define MXL86110_EXT_RGMII_CFG1_RX_DELAY_MASK GENMASK(13, 10) 58 59 #define MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_1950PS (0xD << 0) 60 #define MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_MASK GENMASK(3, 0) 61 62 #define MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_1950PS (0xD << 4) 63 #define MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_MASK GENMASK(7, 4) 64 65 #define MXL86110_EXT_RGMII_CFG1_FULL_MASK \ 66 ((MXL86110_EXT_RGMII_CFG1_RX_DELAY_MASK) | \ 67 (MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_MASK) | \ 68 (MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_MASK)) 69 70 /* EXT Sleep Control register */ 71 #define MXL86110_UTP_EXT_SLEEP_CTRL_REG 0x27 72 #define MXL86110_UTP_EXT_SLEEP_CTRL_EN_SLEEP_SW_OFF 0 73 #define MXL86110_UTP_EXT_SLEEP_CTRL_EN_SLEEP_SW_MASK BIT(15) 74 75 /* RGMII In-Band Status and MDIO Configuration Register */ 76 #define MXL86110_EXT_RGMII_MDIO_CFG 0xA005 77 #define MXL86110_RGMII_MDIO_CFG_EPA0_MASK GENMASK(6, 6) 78 #define MXL86110_EXT_RGMII_MDIO_CFG_EBA_MASK GENMASK(5, 5) 79 #define MXL86110_EXT_RGMII_MDIO_CFG_BA_MASK GENMASK(4, 0) 80 81 #define MXL86110_MAX_LEDS 3 82 /* LED registers and defines */ 83 #define MXL86110_COM_EXT_LED_GEN_CFG 0xA00B 84 # define MXL86110_COM_EXT_LED_GEN_CFG_LFM(x) ((BIT(0) | BIT(1)) << (3 * (x))) 85 # define MXL86110_COM_EXT_LED_GEN_CFG_LFME(x) (BIT(0) << (3 * (x))) 86 # define MXL86110_COM_EXT_LED_GEN_CFG_LFE(x) (BIT(2) << (3 * (x))) 87 88 #define MXL86110_LED0_CFG_REG 0xA00C 89 #define MXL86110_LED1_CFG_REG 0xA00D 90 #define MXL86110_LED2_CFG_REG 0xA00E 91 92 #define MXL86110_LEDX_CFG_BLINK BIT(13) 93 #define MXL86110_LEDX_CFG_LINK_UP_FULL_DUPLEX_ON BIT(12) 94 #define MXL86110_LEDX_CFG_LINK_UP_HALF_DUPLEX_ON BIT(11) 95 #define MXL86110_LEDX_CFG_LINK_UP_TX_ACT_ON BIT(10) 96 #define MXL86110_LEDX_CFG_LINK_UP_RX_ACT_ON BIT(9) 97 #define MXL86110_LEDX_CFG_LINK_UP_TX_ON BIT(8) 98 #define MXL86110_LEDX_CFG_LINK_UP_RX_ON BIT(7) 99 #define MXL86110_LEDX_CFG_LINK_UP_1GB_ON BIT(6) 100 #define MXL86110_LEDX_CFG_LINK_UP_100MB_ON BIT(5) 101 #define MXL86110_LEDX_CFG_LINK_UP_10MB_ON BIT(4) 102 #define MXL86110_LEDX_CFG_LINK_UP_COLLISION BIT(3) 103 #define MXL86110_LEDX_CFG_LINK_UP_1GB_BLINK BIT(2) 104 #define MXL86110_LEDX_CFG_LINK_UP_100MB_BLINK BIT(1) 105 #define MXL86110_LEDX_CFG_LINK_UP_10MB_BLINK BIT(0) 106 107 #define MXL86110_LED_BLINK_CFG_REG 0xA00F 108 #define MXL86110_LED_BLINK_CFG_FREQ_MODE1_2HZ 0 109 #define MXL86110_LED_BLINK_CFG_FREQ_MODE1_4HZ BIT(0) 110 #define MXL86110_LED_BLINK_CFG_FREQ_MODE1_8HZ BIT(1) 111 #define MXL86110_LED_BLINK_CFG_FREQ_MODE1_16HZ (BIT(1) | BIT(0)) 112 #define MXL86110_LED_BLINK_CFG_FREQ_MODE2_2HZ 0 113 #define MXL86110_LED_BLINK_CFG_FREQ_MODE2_4HZ BIT(2) 114 #define MXL86110_LED_BLINK_CFG_FREQ_MODE2_8HZ BIT(3) 115 #define MXL86110_LED_BLINK_CFG_FREQ_MODE2_16HZ (BIT(3) | BIT(2)) 116 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_50_ON 0 117 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_67_ON (BIT(4)) 118 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_75_ON (BIT(5)) 119 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_83_ON (BIT(5) | BIT(4)) 120 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_50_OFF (BIT(6)) 121 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_33_ON (BIT(6) | BIT(4)) 122 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_25_ON (BIT(6) | BIT(5)) 123 #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_17_ON (BIT(6) | BIT(5) | BIT(4)) 124 125 /* Chip Configuration Register - COM_EXT_CHIP_CFG */ 126 #define MXL86110_EXT_CHIP_CFG_REG 0xA001 127 #define MXL86111_EXT_CHIP_CFG_MODE_SEL_MASK GENMASK(2, 0) 128 #define MXL86111_EXT_CHIP_CFG_MODE_UTP_TO_RGMII 0 129 #define MXL86111_EXT_CHIP_CFG_MODE_FIBER_TO_RGMII 1 130 #define MXL86111_EXT_CHIP_CFG_MODE_UTP_FIBER_TO_RGMII 2 131 #define MXL86111_EXT_CHIP_CFG_MODE_UTP_TO_SGMII 3 132 #define MXL86111_EXT_CHIP_CFG_MODE_SGPHY_TO_RGMAC 4 133 #define MXL86111_EXT_CHIP_CFG_MODE_SGMAC_TO_RGPHY 5 134 #define MXL86111_EXT_CHIP_CFG_MODE_UTP_TO_FIBER_AUTO 6 135 #define MXL86111_EXT_CHIP_CFG_MODE_UTP_TO_FIBER_FORCE 7 136 137 #define MXL86111_EXT_CHIP_CFG_CLDO_MASK GENMASK(5, 4) 138 #define MXL86111_EXT_CHIP_CFG_CLDO_3V3 0 139 #define MXL86111_EXT_CHIP_CFG_CLDO_2V5 1 140 #define MXL86111_EXT_CHIP_CFG_CLDO_1V8_2 2 141 #define MXL86111_EXT_CHIP_CFG_CLDO_1V8_3 3 142 #define MXL86111_EXT_CHIP_CFG_CLDO_SHIFT 4 143 #define MXL86111_EXT_CHIP_CFG_ELDO BIT(6) 144 #define MXL86110_EXT_CHIP_CFG_RXDLY_ENABLE BIT(8) 145 #define MXL86110_EXT_CHIP_CFG_SW_RST_N_MODE BIT(15) 146 147 /* Specific Status Register - PHY_STAT */ 148 #define MXL86111_PHY_STAT_REG 0x11 149 #define MXL86111_PHY_STAT_SPEED_MASK GENMASK(15, 14) 150 #define MXL86111_PHY_STAT_SPEED_OFFSET 14 151 #define MXL86111_PHY_STAT_SPEED_10M 0x0 152 #define MXL86111_PHY_STAT_SPEED_100M 0x1 153 #define MXL86111_PHY_STAT_SPEED_1000M 0x2 154 #define MXL86111_PHY_STAT_DPX_OFFSET 13 155 #define MXL86111_PHY_STAT_DPX BIT(13) 156 #define MXL86111_PHY_STAT_LSRT BIT(10) 157 158 /* 3 phy reg page modes,auto mode combines utp and fiber mode*/ 159 #define MXL86111_MODE_FIBER 0x1 160 #define MXL86111_MODE_UTP 0x2 161 #define MXL86111_MODE_AUTO 0x3 162 163 /* FIBER Auto-Negotiation link partner ability - SDS_AN_LPA */ 164 #define MXL86111_SDS_AN_LPA_PAUSE (0x3 << 7) 165 #define MXL86111_SDS_AN_LPA_ASYM_PAUSE (0x2 << 7) 166 167 /* Miscellaneous Control Register - COM_EXT _MISC_CFG */ 168 #define MXL86111_EXT_MISC_CONFIG_REG 0xa006 169 #define MXL86111_EXT_MISC_CONFIG_FIB_SPEED_SEL BIT(0) 170 #define MXL86111_EXT_MISC_CONFIG_FIB_SPEED_SEL_1000BX (0x1 << 0) 171 #define MXL86111_EXT_MISC_CONFIG_FIB_SPEED_SEL_100BX (0x0 << 0) 172 173 /* Phy fiber Link timer cfg2 Register - EXT_SDS_LINK_TIMER_CFG2 */ 174 #define MXL86111_EXT_SDS_LINK_TIMER_CFG2_REG 0xA5 175 #define MXL86111_EXT_SDS_LINK_TIMER_CFG2_EN_AUTOSEN BIT(15) 176 177 /* default values of PHY register, required for Dual Media mode */ 178 #define MII_BMSR_DEFAULT_VAL 0x7949 179 #define MII_ESTATUS_DEFAULT_VAL 0x2000 180 181 /* Timeout in ms for PHY SW reset check in STD_CTRL/SDS_CTRL */ 182 #define BMCR_RESET_TIMEOUT 500 183 184 /* PL P1 requires optimized RGMII timing for 1.8V RGMII voltage 185 */ 186 #define MXL86111_PL_P1 0x500 187 188 /** 189 * __mxl86110_write_extended_reg() - write to a PHY's extended register 190 * @phydev: pointer to the PHY device structure 191 * @regnum: register number to write 192 * @val: value to write to @regnum 193 * 194 * Unlocked version of mxl86110_write_extended_reg 195 * 196 * Note: This function assumes the caller already holds the MDIO bus lock 197 * or otherwise has exclusive access to the PHY. 198 * 199 * Return: 0 or negative error code 200 */ 201 static int __mxl86110_write_extended_reg(struct phy_device *phydev, 202 u16 regnum, u16 val) 203 { 204 int ret; 205 206 ret = __phy_write(phydev, MXL86110_EXTD_REG_ADDR_OFFSET, regnum); 207 if (ret < 0) 208 return ret; 209 210 return __phy_write(phydev, MXL86110_EXTD_REG_ADDR_DATA, val); 211 } 212 213 /** 214 * __mxl86110_read_extended_reg - Read a PHY's extended register 215 * @phydev: pointer to the PHY device structure 216 * @regnum: extended register number to read (address written to reg 30) 217 * 218 * Unlocked version of mxl86110_read_extended_reg 219 * 220 * Reads the content of a PHY extended register using the MaxLinear 221 * 2-step access mechanism: write the register address to reg 30 (0x1E), 222 * then read the value from reg 31 (0x1F). 223 * 224 * Note: This function assumes the caller already holds the MDIO bus lock 225 * or otherwise has exclusive access to the PHY. 226 * 227 * Return: 16-bit register value on success, or negative errno code on failure. 228 */ 229 static int __mxl86110_read_extended_reg(struct phy_device *phydev, u16 regnum) 230 { 231 int ret; 232 233 ret = __phy_write(phydev, MXL86110_EXTD_REG_ADDR_OFFSET, regnum); 234 if (ret < 0) 235 return ret; 236 return __phy_read(phydev, MXL86110_EXTD_REG_ADDR_DATA); 237 } 238 239 /** 240 * __mxl86110_modify_extended_reg() - modify bits of a PHY's extended register 241 * @phydev: pointer to the PHY device structure 242 * @regnum: register number to write 243 * @mask: bit mask of bits to clear 244 * @set: bit mask of bits to set 245 * 246 * Note: register value = (old register value & ~mask) | set. 247 * This function assumes the caller already holds the MDIO bus lock 248 * or otherwise has exclusive access to the PHY. 249 * 250 * Return: 0 or negative error code 251 */ 252 static int __mxl86110_modify_extended_reg(struct phy_device *phydev, 253 u16 regnum, u16 mask, u16 set) 254 { 255 int ret; 256 257 ret = __phy_write(phydev, MXL86110_EXTD_REG_ADDR_OFFSET, regnum); 258 if (ret < 0) 259 return ret; 260 261 return __phy_modify(phydev, MXL86110_EXTD_REG_ADDR_DATA, mask, set); 262 } 263 264 /** 265 * mxl86110_write_extended_reg() - Write to a PHY's extended register 266 * @phydev: pointer to the PHY device structure 267 * @regnum: register number to write 268 * @val: value to write to @regnum 269 * 270 * This function writes to an extended register of the PHY using the 271 * MaxLinear two-step access method (reg 0x1E/0x1F). It handles acquiring 272 * and releasing the MDIO bus lock internally. 273 * 274 * Return: 0 or negative error code 275 */ 276 static int mxl86110_write_extended_reg(struct phy_device *phydev, 277 u16 regnum, u16 val) 278 { 279 int ret; 280 281 phy_lock_mdio_bus(phydev); 282 ret = __mxl86110_write_extended_reg(phydev, regnum, val); 283 phy_unlock_mdio_bus(phydev); 284 285 return ret; 286 } 287 288 /** 289 * mxl86110_read_extended_reg() - Read a PHY's extended register 290 * @phydev: pointer to the PHY device structure 291 * @regnum: extended register number to read 292 * 293 * This function reads from an extended register of the PHY using the 294 * MaxLinear two-step access method (reg 0x1E/0x1F). It handles acquiring 295 * and releasing the MDIO bus lock internally. 296 * 297 * Return: 16-bit register value on success, or negative errno code on failure 298 */ 299 static int mxl86110_read_extended_reg(struct phy_device *phydev, u16 regnum) 300 { 301 int ret; 302 303 phy_lock_mdio_bus(phydev); 304 ret = __mxl86110_read_extended_reg(phydev, regnum); 305 phy_unlock_mdio_bus(phydev); 306 307 return ret; 308 } 309 310 /** 311 * mxl86110_modify_extended_reg() - modify bits of a PHY's extended register 312 * @phydev: pointer to the PHY device structure 313 * @regnum: register number to write 314 * @mask: bit mask of bits to clear 315 * @set: bit mask of bits to set 316 * 317 * Note: register value = (old register value & ~mask) | set. 318 * 319 * Return: 0 or negative error code 320 */ 321 static int mxl86110_modify_extended_reg(struct phy_device *phydev, 322 u16 regnum, u16 mask, u16 set) 323 { 324 int ret; 325 326 phy_lock_mdio_bus(phydev); 327 ret = __mxl86110_modify_extended_reg(phydev, regnum, mask, set); 328 phy_unlock_mdio_bus(phydev); 329 330 return ret; 331 } 332 333 /** 334 * mxl86110_get_wol() - report if wake-on-lan is enabled 335 * @phydev: pointer to the phy_device 336 * @wol: a pointer to a &struct ethtool_wolinfo 337 */ 338 static void mxl86110_get_wol(struct phy_device *phydev, 339 struct ethtool_wolinfo *wol) 340 { 341 int val; 342 343 wol->supported = WAKE_MAGIC; 344 wol->wolopts = 0; 345 val = mxl86110_read_extended_reg(phydev, MXL86110_EXT_WOL_CFG_REG); 346 if (val >= 0 && (val & MXL86110_WOL_CFG_WOL_MASK)) 347 wol->wolopts |= WAKE_MAGIC; 348 } 349 350 /** 351 * mxl86110_set_wol() - enable/disable wake-on-lan 352 * @phydev: pointer to the phy_device 353 * @wol: a pointer to a &struct ethtool_wolinfo 354 * 355 * Configures the WOL Magic Packet MAC 356 * 357 * Return: 0 or negative errno code 358 */ 359 static int mxl86110_set_wol(struct phy_device *phydev, 360 struct ethtool_wolinfo *wol) 361 { 362 struct net_device *netdev; 363 const unsigned char *mac; 364 int ret = 0; 365 366 phy_lock_mdio_bus(phydev); 367 368 if (wol->wolopts & WAKE_MAGIC) { 369 netdev = phydev->attached_dev; 370 if (!netdev) { 371 ret = -ENODEV; 372 goto out; 373 } 374 375 /* Configure the MAC address of the WOL magic packet */ 376 mac = netdev->dev_addr; 377 ret = __mxl86110_write_extended_reg(phydev, 378 MXL86110_EXT_MAC_ADDR_CFG1, 379 ((mac[0] << 8) | mac[1])); 380 if (ret < 0) 381 goto out; 382 383 ret = __mxl86110_write_extended_reg(phydev, 384 MXL86110_EXT_MAC_ADDR_CFG2, 385 ((mac[2] << 8) | mac[3])); 386 if (ret < 0) 387 goto out; 388 389 ret = __mxl86110_write_extended_reg(phydev, 390 MXL86110_EXT_MAC_ADDR_CFG3, 391 ((mac[4] << 8) | mac[5])); 392 if (ret < 0) 393 goto out; 394 395 ret = __mxl86110_modify_extended_reg(phydev, 396 MXL86110_EXT_WOL_CFG_REG, 397 MXL86110_WOL_CFG_WOL_MASK, 398 MXL86110_WOL_CFG_WOL_MASK); 399 if (ret < 0) 400 goto out; 401 402 /* Enables Wake-on-LAN interrupt in the PHY. */ 403 ret = __phy_modify(phydev, PHY_IRQ_ENABLE_REG, 0, 404 PHY_IRQ_ENABLE_REG_WOL); 405 if (ret < 0) 406 goto out; 407 408 phydev_dbg(phydev, 409 "%s, MAC Addr: %02X:%02X:%02X:%02X:%02X:%02X\n", 410 __func__, 411 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 412 } else { 413 ret = __mxl86110_modify_extended_reg(phydev, 414 MXL86110_EXT_WOL_CFG_REG, 415 MXL86110_WOL_CFG_WOL_MASK, 416 0); 417 if (ret < 0) 418 goto out; 419 420 /* Disables Wake-on-LAN interrupt in the PHY. */ 421 ret = __phy_modify(phydev, PHY_IRQ_ENABLE_REG, 422 PHY_IRQ_ENABLE_REG_WOL, 0); 423 } 424 425 out: 426 phy_unlock_mdio_bus(phydev); 427 return ret; 428 } 429 430 static const unsigned long supported_trgs = (BIT(TRIGGER_NETDEV_LINK_10) | 431 BIT(TRIGGER_NETDEV_LINK_100) | 432 BIT(TRIGGER_NETDEV_LINK_1000) | 433 BIT(TRIGGER_NETDEV_HALF_DUPLEX) | 434 BIT(TRIGGER_NETDEV_FULL_DUPLEX) | 435 BIT(TRIGGER_NETDEV_TX) | 436 BIT(TRIGGER_NETDEV_RX)); 437 438 static int mxl86110_led_hw_is_supported(struct phy_device *phydev, u8 index, 439 unsigned long rules) 440 { 441 if (index >= MXL86110_MAX_LEDS) 442 return -EINVAL; 443 444 /* All combinations of the supported triggers are allowed */ 445 if (rules & ~supported_trgs) 446 return -EOPNOTSUPP; 447 448 return 0; 449 } 450 451 static int mxl86110_led_hw_control_get(struct phy_device *phydev, u8 index, 452 unsigned long *rules) 453 { 454 int val; 455 456 if (index >= MXL86110_MAX_LEDS) 457 return -EINVAL; 458 459 val = mxl86110_read_extended_reg(phydev, 460 MXL86110_LED0_CFG_REG + index); 461 if (val < 0) 462 return val; 463 464 if (val & MXL86110_LEDX_CFG_LINK_UP_TX_ACT_ON) 465 *rules |= BIT(TRIGGER_NETDEV_TX); 466 467 if (val & MXL86110_LEDX_CFG_LINK_UP_RX_ACT_ON) 468 *rules |= BIT(TRIGGER_NETDEV_RX); 469 470 if (val & MXL86110_LEDX_CFG_LINK_UP_HALF_DUPLEX_ON) 471 *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX); 472 473 if (val & MXL86110_LEDX_CFG_LINK_UP_FULL_DUPLEX_ON) 474 *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX); 475 476 if (val & MXL86110_LEDX_CFG_LINK_UP_10MB_ON) 477 *rules |= BIT(TRIGGER_NETDEV_LINK_10); 478 479 if (val & MXL86110_LEDX_CFG_LINK_UP_100MB_ON) 480 *rules |= BIT(TRIGGER_NETDEV_LINK_100); 481 482 if (val & MXL86110_LEDX_CFG_LINK_UP_1GB_ON) 483 *rules |= BIT(TRIGGER_NETDEV_LINK_1000); 484 485 return 0; 486 } 487 488 static int mxl86110_led_hw_control_set(struct phy_device *phydev, u8 index, 489 unsigned long rules) 490 { 491 u16 val = 0; 492 int ret; 493 494 if (index >= MXL86110_MAX_LEDS) 495 return -EINVAL; 496 497 if (rules & BIT(TRIGGER_NETDEV_LINK_10)) 498 val |= MXL86110_LEDX_CFG_LINK_UP_10MB_ON; 499 500 if (rules & BIT(TRIGGER_NETDEV_LINK_100)) 501 val |= MXL86110_LEDX_CFG_LINK_UP_100MB_ON; 502 503 if (rules & BIT(TRIGGER_NETDEV_LINK_1000)) 504 val |= MXL86110_LEDX_CFG_LINK_UP_1GB_ON; 505 506 if (rules & BIT(TRIGGER_NETDEV_TX)) 507 val |= MXL86110_LEDX_CFG_LINK_UP_TX_ACT_ON; 508 509 if (rules & BIT(TRIGGER_NETDEV_RX)) 510 val |= MXL86110_LEDX_CFG_LINK_UP_RX_ACT_ON; 511 512 if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) 513 val |= MXL86110_LEDX_CFG_LINK_UP_HALF_DUPLEX_ON; 514 515 if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) 516 val |= MXL86110_LEDX_CFG_LINK_UP_FULL_DUPLEX_ON; 517 518 if (rules & BIT(TRIGGER_NETDEV_TX) || 519 rules & BIT(TRIGGER_NETDEV_RX)) 520 val |= MXL86110_LEDX_CFG_BLINK; 521 522 ret = mxl86110_write_extended_reg(phydev, 523 MXL86110_LED0_CFG_REG + index, val); 524 if (ret) 525 return ret; 526 527 /* clear manual control bit */ 528 ret = mxl86110_modify_extended_reg(phydev, 529 MXL86110_COM_EXT_LED_GEN_CFG, 530 MXL86110_COM_EXT_LED_GEN_CFG_LFE(index), 531 0); 532 533 return ret; 534 } 535 536 static int mxl86110_led_brightness_set(struct phy_device *phydev, 537 u8 index, enum led_brightness value) 538 { 539 u16 mask, set; 540 int ret; 541 542 if (index >= MXL86110_MAX_LEDS) 543 return -EINVAL; 544 545 /* force manual control */ 546 set = MXL86110_COM_EXT_LED_GEN_CFG_LFE(index); 547 /* clear previous force mode */ 548 mask = MXL86110_COM_EXT_LED_GEN_CFG_LFM(index); 549 550 /* force LED to be permanently on */ 551 if (value != LED_OFF) 552 set |= MXL86110_COM_EXT_LED_GEN_CFG_LFME(index); 553 554 ret = mxl86110_modify_extended_reg(phydev, 555 MXL86110_COM_EXT_LED_GEN_CFG, 556 mask, set); 557 558 return ret; 559 } 560 561 /** 562 * mxl86110_synce_clk_cfg() - applies syncE/clk output configuration 563 * @phydev: pointer to the phy_device 564 * 565 * Note: This function assumes the caller already holds the MDIO bus lock 566 * or otherwise has exclusive access to the PHY. 567 * 568 * Return: 0 or negative errno code 569 */ 570 static int mxl86110_synce_clk_cfg(struct phy_device *phydev) 571 { 572 u16 mask = 0, val = 0; 573 574 /* 575 * Configures the clock output to its default 576 * setting as per the datasheet. 577 * This results in a 25MHz clock output being selected in the 578 * COM_EXT_SYNCE_CFG register for SyncE configuration. 579 */ 580 val = MXL86110_EXT_SYNCE_CFG_EN_SYNC_E | 581 FIELD_PREP(MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_MASK, 582 MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_25M); 583 mask = MXL86110_EXT_SYNCE_CFG_EN_SYNC_E | 584 MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_MASK | 585 MXL86110_EXT_SYNCE_CFG_CLK_FRE_SEL; 586 587 /* Write clock output configuration */ 588 return __mxl86110_modify_extended_reg(phydev, 589 MXL86110_EXT_SYNCE_CFG_REG, 590 mask, val); 591 } 592 593 /** 594 * mxl86110_broadcast_cfg - Configure MDIO broadcast setting for PHY 595 * @phydev: Pointer to the PHY device structure 596 * 597 * This function configures the MDIO broadcast behavior of the MxL86110 PHY. 598 * Currently, broadcast mode is explicitly disabled by clearing the EPA0 bit 599 * in the RGMII_MDIO_CFG extended register. 600 * 601 * Note: This function assumes the caller already holds the MDIO bus lock 602 * or otherwise has exclusive access to the PHY. 603 * 604 * Return: 0 on success or a negative errno code on failure. 605 */ 606 static int mxl86110_broadcast_cfg(struct phy_device *phydev) 607 { 608 return __mxl86110_modify_extended_reg(phydev, 609 MXL86110_EXT_RGMII_MDIO_CFG, 610 MXL86110_RGMII_MDIO_CFG_EPA0_MASK, 611 0); 612 } 613 614 /** 615 * mxl86110_enable_led_activity_blink - Enable LEDs activity blink on PHY 616 * @phydev: Pointer to the PHY device structure 617 * 618 * Configure all PHY LEDs to blink on traffic activity regardless of whether 619 * they are ON or OFF. This behavior allows each LED to serve as a pure activity 620 * indicator, independently of its use as a link status indicator. 621 * 622 * By default, each LED blinks only when it is also in the ON state. 623 * This function modifies the appropriate registers (LABx fields) 624 * to enable blinking even when the LEDs are OFF, to allow the LED to be used 625 * as a traffic indicator without requiring it to also serve 626 * as a link status LED. 627 * 628 * Note: Any further LED customization can be performed via the 629 * /sys/class/leds interface; the functions led_hw_is_supported, 630 * led_hw_control_get, and led_hw_control_set are used 631 * to support this mechanism. 632 * 633 * This function assumes the caller already holds the MDIO bus lock 634 * or otherwise has exclusive access to the PHY. 635 * 636 * Return: 0 on success or a negative errno code on failure. 637 */ 638 static int mxl86110_enable_led_activity_blink(struct phy_device *phydev) 639 { 640 int i, ret = 0; 641 642 for (i = 0; i < MXL86110_MAX_LEDS; i++) { 643 ret = __mxl86110_modify_extended_reg(phydev, 644 MXL86110_LED0_CFG_REG + i, 645 0, 646 MXL86110_LEDX_CFG_BLINK); 647 if (ret < 0) 648 break; 649 } 650 651 return ret; 652 } 653 654 /** 655 * mxl86110_config_rgmii_delay() - configure RGMII delays 656 * @phydev: pointer to the phy_device 657 * 658 * Return: 0 or negative errno code 659 */ 660 static int mxl86110_config_rgmii_delay(struct phy_device *phydev) 661 { 662 int ret; 663 u16 val; 664 665 switch (phydev->interface) { 666 case PHY_INTERFACE_MODE_RGMII: 667 val = 0; 668 break; 669 case PHY_INTERFACE_MODE_RGMII_RXID: 670 val = MXL86110_EXT_RGMII_CFG1_RX_DELAY_1950PS; 671 break; 672 case PHY_INTERFACE_MODE_RGMII_TXID: 673 val = MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_1950PS | 674 MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_1950PS; 675 break; 676 case PHY_INTERFACE_MODE_RGMII_ID: 677 val = MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_1950PS | 678 MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_1950PS | 679 MXL86110_EXT_RGMII_CFG1_RX_DELAY_1950PS; 680 break; 681 default: 682 ret = -EINVAL; 683 goto out; 684 } 685 686 ret = __mxl86110_modify_extended_reg(phydev, 687 MXL86110_EXT_RGMII_CFG1_REG, 688 MXL86110_EXT_RGMII_CFG1_FULL_MASK, 689 val); 690 if (ret < 0) 691 goto out; 692 693 /* Configure RXDLY (RGMII Rx Clock Delay) to disable 694 * the default additional delay value on RX_CLK 695 * (2 ns for 125 MHz, 8 ns for 25 MHz/2.5 MHz) 696 * and use just the digital one selected before 697 */ 698 ret = __mxl86110_modify_extended_reg(phydev, 699 MXL86110_EXT_CHIP_CFG_REG, 700 MXL86110_EXT_CHIP_CFG_RXDLY_ENABLE, 701 0); 702 if (ret < 0) 703 goto out; 704 705 out: 706 return ret; 707 } 708 709 /** 710 * mxl86110_config_init() - initialize the MXL86110 PHY 711 * @phydev: pointer to the phy_device 712 * 713 * Return: 0 or negative errno code 714 */ 715 static int mxl86110_config_init(struct phy_device *phydev) 716 { 717 int ret; 718 719 phy_lock_mdio_bus(phydev); 720 721 /* configure syncE / clk output */ 722 ret = mxl86110_synce_clk_cfg(phydev); 723 if (ret < 0) 724 goto out; 725 726 ret = mxl86110_config_rgmii_delay(phydev); 727 if (ret < 0) 728 goto out; 729 730 ret = mxl86110_enable_led_activity_blink(phydev); 731 if (ret < 0) 732 goto out; 733 734 ret = mxl86110_broadcast_cfg(phydev); 735 736 out: 737 phy_unlock_mdio_bus(phydev); 738 return ret; 739 } 740 741 /** 742 * mxl86111_probe() - validate bootstrap chip config and set UTP page 743 * @phydev: pointer to the phy_device 744 * 745 * Return: 0 or negative errno code 746 */ 747 static int mxl86111_probe(struct phy_device *phydev) 748 { 749 int chip_config; 750 u16 reg_page; 751 int ret; 752 753 chip_config = mxl86110_read_extended_reg(phydev, MXL86110_EXT_CHIP_CFG_REG); 754 if (chip_config < 0) 755 return chip_config; 756 757 switch (chip_config & MXL86111_EXT_CHIP_CFG_MODE_SEL_MASK) { 758 case MXL86111_EXT_CHIP_CFG_MODE_UTP_TO_SGMII: 759 case MXL86111_EXT_CHIP_CFG_MODE_UTP_TO_RGMII: 760 phydev->port = PORT_TP; 761 reg_page = MXL86111_EXT_SMI_SDS_PHYUTP_SPACE; 762 break; 763 default: 764 return -EOPNOTSUPP; 765 } 766 767 ret = mxl86110_write_extended_reg(phydev, 768 MXL86111_EXT_SMI_SDS_PHY_REG, 769 reg_page); 770 if (ret < 0) 771 return ret; 772 773 return 0; 774 } 775 776 /** 777 * mxl86111_config_init() - initialize the MXL86111 PHY 778 * @phydev: pointer to the phy_device 779 * 780 * Return: 0 or negative errno code 781 */ 782 static int mxl86111_config_init(struct phy_device *phydev) 783 { 784 int ret; 785 786 phy_lock_mdio_bus(phydev); 787 788 /* configure syncE / clk output */ 789 ret = mxl86110_synce_clk_cfg(phydev); 790 if (ret < 0) 791 goto out; 792 793 switch (phydev->interface) { 794 case PHY_INTERFACE_MODE_100BASEX: 795 ret = __mxl86110_modify_extended_reg(phydev, 796 MXL86111_EXT_MISC_CONFIG_REG, 797 MXL86111_EXT_MISC_CONFIG_FIB_SPEED_SEL, 798 MXL86111_EXT_MISC_CONFIG_FIB_SPEED_SEL_100BX); 799 if (ret < 0) 800 goto out; 801 break; 802 case PHY_INTERFACE_MODE_1000BASEX: 803 case PHY_INTERFACE_MODE_SGMII: 804 ret = __mxl86110_modify_extended_reg(phydev, 805 MXL86111_EXT_MISC_CONFIG_REG, 806 MXL86111_EXT_MISC_CONFIG_FIB_SPEED_SEL, 807 MXL86111_EXT_MISC_CONFIG_FIB_SPEED_SEL_1000BX); 808 if (ret < 0) 809 goto out; 810 break; 811 default: 812 /* RGMII modes */ 813 ret = mxl86110_config_rgmii_delay(phydev); 814 if (ret < 0) 815 goto out; 816 ret = __mxl86110_modify_extended_reg(phydev, MXL86110_EXT_RGMII_CFG1_REG, 817 MXL86110_EXT_RGMII_CFG1_FULL_MASK, ret); 818 819 /* PL P1 requires optimized RGMII timing for 1.8V RGMII voltage 820 */ 821 ret = __mxl86110_read_extended_reg(phydev, 0xf); 822 if (ret < 0) 823 goto out; 824 825 if (ret == MXL86111_PL_P1) { 826 ret = __mxl86110_read_extended_reg(phydev, MXL86110_EXT_CHIP_CFG_REG); 827 if (ret < 0) 828 goto out; 829 830 /* check if LDO is in 1.8V mode */ 831 switch (FIELD_GET(MXL86111_EXT_CHIP_CFG_CLDO_MASK, ret)) { 832 case MXL86111_EXT_CHIP_CFG_CLDO_1V8_3: 833 case MXL86111_EXT_CHIP_CFG_CLDO_1V8_2: 834 ret = __mxl86110_write_extended_reg(phydev, 0xa010, 0xabff); 835 if (ret < 0) 836 goto out; 837 break; 838 default: 839 break; 840 } 841 } 842 break; 843 } 844 845 ret = mxl86110_enable_led_activity_blink(phydev); 846 if (ret < 0) 847 goto out; 848 849 ret = mxl86110_broadcast_cfg(phydev); 850 out: 851 phy_unlock_mdio_bus(phydev); 852 853 return ret; 854 } 855 856 /** 857 * mxl86111_read_page() - read reg page 858 * @phydev: pointer to the phy_device 859 * 860 * Return: current reg space of mxl86111 or negative errno code 861 */ 862 static int mxl86111_read_page(struct phy_device *phydev) 863 { 864 int page; 865 866 page = __mxl86110_read_extended_reg(phydev, MXL86111_EXT_SMI_SDS_PHY_REG); 867 if (page < 0) 868 return page; 869 870 return page & MXL86111_EXT_SMI_SDS_PHYSPACE_MASK; 871 }; 872 873 /** 874 * mxl86111_write_page() - Set reg page 875 * @phydev: pointer to the phy_device 876 * @page: The reg page to set 877 * 878 * Return: 0 or negative errno code 879 */ 880 static int mxl86111_write_page(struct phy_device *phydev, int page) 881 { 882 return __mxl86110_modify_extended_reg(phydev, MXL86111_EXT_SMI_SDS_PHY_REG, 883 MXL86111_EXT_SMI_SDS_PHYSPACE_MASK, page); 884 }; 885 886 static int mxl86111_config_inband(struct phy_device *phydev, unsigned int modes) 887 { 888 int ret; 889 890 ret = phy_modify_paged(phydev, MXL86111_EXT_SMI_SDS_PHYFIBER_SPACE, 891 MII_BMCR, BMCR_ANENABLE, 892 (modes == LINK_INBAND_DISABLE) ? 0 : BMCR_ANENABLE); 893 if (ret < 0) 894 goto out; 895 896 phy_lock_mdio_bus(phydev); 897 898 ret = __mxl86110_modify_extended_reg(phydev, MXL86111_EXT_SDS_LINK_TIMER_CFG2_REG, 899 MXL86111_EXT_SDS_LINK_TIMER_CFG2_EN_AUTOSEN, 900 (modes == LINK_INBAND_DISABLE) ? 0 : 901 MXL86111_EXT_SDS_LINK_TIMER_CFG2_EN_AUTOSEN); 902 if (ret < 0) 903 goto out; 904 905 ret = __mxl86110_modify_extended_reg(phydev, MXL86110_EXT_CHIP_CFG_REG, 906 MXL86110_EXT_CHIP_CFG_SW_RST_N_MODE, 0); 907 if (ret < 0) 908 goto out; 909 910 /* For fiber forced mode, power down/up to re-aneg */ 911 if (modes != LINK_INBAND_DISABLE) { 912 __phy_modify(phydev, MII_BMCR, 0, BMCR_PDOWN); 913 usleep_range(1000, 1050); 914 __phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0); 915 } 916 917 out: 918 phy_unlock_mdio_bus(phydev); 919 920 return ret; 921 } 922 923 static unsigned int mxl86111_inband_caps(struct phy_device *phydev, 924 phy_interface_t interface) 925 { 926 switch (interface) { 927 case PHY_INTERFACE_MODE_100BASEX: 928 case PHY_INTERFACE_MODE_1000BASEX: 929 case PHY_INTERFACE_MODE_SGMII: 930 return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; 931 default: 932 return 0; 933 } 934 } 935 936 static struct phy_driver mxl_phy_drvs[] = { 937 { 938 PHY_ID_MATCH_EXACT(PHY_ID_MXL86110), 939 .name = "MXL86110 Gigabit Ethernet", 940 .config_init = mxl86110_config_init, 941 .get_wol = mxl86110_get_wol, 942 .set_wol = mxl86110_set_wol, 943 .led_brightness_set = mxl86110_led_brightness_set, 944 .led_hw_is_supported = mxl86110_led_hw_is_supported, 945 .led_hw_control_get = mxl86110_led_hw_control_get, 946 .led_hw_control_set = mxl86110_led_hw_control_set, 947 }, 948 { 949 PHY_ID_MATCH_EXACT(PHY_ID_MXL86111), 950 .name = "MXL86111 Gigabit Ethernet", 951 .probe = mxl86111_probe, 952 .config_init = mxl86111_config_init, 953 .get_wol = mxl86110_get_wol, 954 .set_wol = mxl86110_set_wol, 955 .inband_caps = mxl86111_inband_caps, 956 .config_inband = mxl86111_config_inband, 957 .read_page = mxl86111_read_page, 958 .write_page = mxl86111_write_page, 959 .led_brightness_set = mxl86110_led_brightness_set, 960 .led_hw_is_supported = mxl86110_led_hw_is_supported, 961 .led_hw_control_get = mxl86110_led_hw_control_get, 962 .led_hw_control_set = mxl86110_led_hw_control_set, 963 }, 964 }; 965 966 module_phy_driver(mxl_phy_drvs); 967 968 static const struct mdio_device_id __maybe_unused mxl_tbl[] = { 969 { PHY_ID_MATCH_EXACT(PHY_ID_MXL86110) }, 970 { PHY_ID_MATCH_EXACT(PHY_ID_MXL86111) }, 971 { } 972 }; 973 974 MODULE_DEVICE_TABLE(mdio, mxl_tbl); 975 976 MODULE_DESCRIPTION("MaxLinear MXL86110/MXL86111 PHY driver"); 977 MODULE_AUTHOR("Stefano Radaelli"); 978 MODULE_LICENSE("GPL"); 979