1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for the Texas Instruments DP83TC811 PHY 4 * 5 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ 6 * 7 */ 8 9 #include <linux/ethtool.h> 10 #include <linux/etherdevice.h> 11 #include <linux/kernel.h> 12 #include <linux/mii.h> 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/phy.h> 16 #include <linux/netdevice.h> 17 18 #define DP83TC811_PHY_ID 0x2000a253 19 #define DP83811_DEVADDR 0x1f 20 21 #define MII_DP83811_SGMII_CTRL 0x09 22 #define MII_DP83811_INT_STAT1 0x12 23 #define MII_DP83811_INT_STAT2 0x13 24 #define MII_DP83811_RESET_CTRL 0x1f 25 26 #define DP83811_HW_RESET BIT(15) 27 #define DP83811_SW_RESET BIT(14) 28 29 /* INT_STAT1 bits */ 30 #define DP83811_RX_ERR_HF_INT_EN BIT(0) 31 #define DP83811_MS_TRAINING_INT_EN BIT(1) 32 #define DP83811_ANEG_COMPLETE_INT_EN BIT(2) 33 #define DP83811_ESD_EVENT_INT_EN BIT(3) 34 #define DP83811_WOL_INT_EN BIT(4) 35 #define DP83811_LINK_STAT_INT_EN BIT(5) 36 #define DP83811_ENERGY_DET_INT_EN BIT(6) 37 #define DP83811_LINK_QUAL_INT_EN BIT(7) 38 39 /* INT_STAT2 bits */ 40 #define DP83811_JABBER_DET_INT_EN BIT(0) 41 #define DP83811_POLARITY_INT_EN BIT(1) 42 #define DP83811_SLEEP_MODE_INT_EN BIT(2) 43 #define DP83811_OVERTEMP_INT_EN BIT(3) 44 #define DP83811_OVERVOLTAGE_INT_EN BIT(6) 45 #define DP83811_UNDERVOLTAGE_INT_EN BIT(7) 46 47 #define MII_DP83811_RXSOP1 0x04a5 48 #define MII_DP83811_RXSOP2 0x04a6 49 #define MII_DP83811_RXSOP3 0x04a7 50 51 /* WoL Registers */ 52 #define MII_DP83811_WOL_CFG 0x04a0 53 #define MII_DP83811_WOL_STAT 0x04a1 54 #define MII_DP83811_WOL_DA1 0x04a2 55 #define MII_DP83811_WOL_DA2 0x04a3 56 #define MII_DP83811_WOL_DA3 0x04a4 57 58 /* WoL bits */ 59 #define DP83811_WOL_MAGIC_EN BIT(0) 60 #define DP83811_WOL_SECURE_ON BIT(5) 61 #define DP83811_WOL_EN BIT(7) 62 #define DP83811_WOL_INDICATION_SEL BIT(8) 63 #define DP83811_WOL_CLR_INDICATION BIT(11) 64 65 /* SGMII CTRL bits */ 66 #define DP83811_TDR_AUTO BIT(8) 67 #define DP83811_SGMII_EN BIT(12) 68 #define DP83811_SGMII_AUTO_NEG_EN BIT(13) 69 #define DP83811_SGMII_TX_ERR_DIS BIT(14) 70 #define DP83811_SGMII_SOFT_RESET BIT(15) 71 72 static int dp83811_ack_interrupt(struct phy_device *phydev) 73 { 74 int err; 75 76 err = phy_read(phydev, MII_DP83811_INT_STAT1); 77 if (err < 0) 78 return err; 79 80 err = phy_read(phydev, MII_DP83811_INT_STAT2); 81 if (err < 0) 82 return err; 83 84 return 0; 85 } 86 87 static int dp83811_set_wol(struct phy_device *phydev, 88 struct ethtool_wolinfo *wol) 89 { 90 struct net_device *ndev = phydev->attached_dev; 91 const u8 *mac; 92 u16 value; 93 94 if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) { 95 mac = (const u8 *)ndev->dev_addr; 96 97 if (!is_valid_ether_addr(mac)) 98 return -EINVAL; 99 100 /* MAC addresses start with byte 5, but stored in mac[0]. 101 * 811 PHYs store bytes 4|5, 2|3, 0|1 102 */ 103 phy_write_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_DA1, 104 (mac[1] << 8) | mac[0]); 105 phy_write_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_DA2, 106 (mac[3] << 8) | mac[2]); 107 phy_write_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_DA3, 108 (mac[5] << 8) | mac[4]); 109 110 value = phy_read_mmd(phydev, DP83811_DEVADDR, 111 MII_DP83811_WOL_CFG); 112 if (wol->wolopts & WAKE_MAGIC) 113 value |= DP83811_WOL_MAGIC_EN; 114 else 115 value &= ~DP83811_WOL_MAGIC_EN; 116 117 if (wol->wolopts & WAKE_MAGICSECURE) { 118 phy_write_mmd(phydev, DP83811_DEVADDR, 119 MII_DP83811_RXSOP1, 120 (wol->sopass[1] << 8) | wol->sopass[0]); 121 phy_write_mmd(phydev, DP83811_DEVADDR, 122 MII_DP83811_RXSOP2, 123 (wol->sopass[3] << 8) | wol->sopass[2]); 124 phy_write_mmd(phydev, DP83811_DEVADDR, 125 MII_DP83811_RXSOP3, 126 (wol->sopass[5] << 8) | wol->sopass[4]); 127 value |= DP83811_WOL_SECURE_ON; 128 } else { 129 value &= ~DP83811_WOL_SECURE_ON; 130 } 131 132 value |= (DP83811_WOL_EN | DP83811_WOL_INDICATION_SEL | 133 DP83811_WOL_CLR_INDICATION); 134 phy_write_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_CFG, 135 value); 136 } else { 137 value = phy_read_mmd(phydev, DP83811_DEVADDR, 138 MII_DP83811_WOL_CFG); 139 value &= ~DP83811_WOL_EN; 140 phy_write_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_CFG, 141 value); 142 } 143 144 return 0; 145 } 146 147 static void dp83811_get_wol(struct phy_device *phydev, 148 struct ethtool_wolinfo *wol) 149 { 150 u16 sopass_val; 151 int value; 152 153 wol->supported = (WAKE_MAGIC | WAKE_MAGICSECURE); 154 wol->wolopts = 0; 155 156 value = phy_read_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_CFG); 157 158 if (value & DP83811_WOL_MAGIC_EN) 159 wol->wolopts |= WAKE_MAGIC; 160 161 if (value & DP83811_WOL_SECURE_ON) { 162 sopass_val = phy_read_mmd(phydev, DP83811_DEVADDR, 163 MII_DP83811_RXSOP1); 164 wol->sopass[0] = (sopass_val & 0xff); 165 wol->sopass[1] = (sopass_val >> 8); 166 167 sopass_val = phy_read_mmd(phydev, DP83811_DEVADDR, 168 MII_DP83811_RXSOP2); 169 wol->sopass[2] = (sopass_val & 0xff); 170 wol->sopass[3] = (sopass_val >> 8); 171 172 sopass_val = phy_read_mmd(phydev, DP83811_DEVADDR, 173 MII_DP83811_RXSOP3); 174 wol->sopass[4] = (sopass_val & 0xff); 175 wol->sopass[5] = (sopass_val >> 8); 176 177 wol->wolopts |= WAKE_MAGICSECURE; 178 } 179 180 /* WoL is not enabled so set wolopts to 0 */ 181 if (!(value & DP83811_WOL_EN)) 182 wol->wolopts = 0; 183 } 184 185 static int dp83811_config_intr(struct phy_device *phydev) 186 { 187 int misr_status, err; 188 189 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 190 misr_status = phy_read(phydev, MII_DP83811_INT_STAT1); 191 if (misr_status < 0) 192 return misr_status; 193 194 misr_status |= (DP83811_RX_ERR_HF_INT_EN | 195 DP83811_MS_TRAINING_INT_EN | 196 DP83811_ANEG_COMPLETE_INT_EN | 197 DP83811_ESD_EVENT_INT_EN | 198 DP83811_WOL_INT_EN | 199 DP83811_LINK_STAT_INT_EN | 200 DP83811_ENERGY_DET_INT_EN | 201 DP83811_LINK_QUAL_INT_EN); 202 203 err = phy_write(phydev, MII_DP83811_INT_STAT1, misr_status); 204 if (err < 0) 205 return err; 206 207 misr_status = phy_read(phydev, MII_DP83811_INT_STAT2); 208 if (misr_status < 0) 209 return misr_status; 210 211 misr_status |= (DP83811_JABBER_DET_INT_EN | 212 DP83811_POLARITY_INT_EN | 213 DP83811_SLEEP_MODE_INT_EN | 214 DP83811_OVERTEMP_INT_EN | 215 DP83811_OVERVOLTAGE_INT_EN | 216 DP83811_UNDERVOLTAGE_INT_EN); 217 218 err = phy_write(phydev, MII_DP83811_INT_STAT2, misr_status); 219 220 } else { 221 err = phy_write(phydev, MII_DP83811_INT_STAT1, 0); 222 if (err < 0) 223 return err; 224 225 err = phy_write(phydev, MII_DP83811_INT_STAT1, 0); 226 } 227 228 return err; 229 } 230 231 static int dp83811_config_aneg(struct phy_device *phydev) 232 { 233 int value, err; 234 235 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 236 value = phy_read(phydev, MII_DP83811_SGMII_CTRL); 237 if (phydev->autoneg == AUTONEG_ENABLE) { 238 err = phy_write(phydev, MII_DP83811_SGMII_CTRL, 239 (DP83811_SGMII_AUTO_NEG_EN | value)); 240 if (err < 0) 241 return err; 242 } else { 243 err = phy_write(phydev, MII_DP83811_SGMII_CTRL, 244 (~DP83811_SGMII_AUTO_NEG_EN & value)); 245 if (err < 0) 246 return err; 247 } 248 } 249 250 return genphy_config_aneg(phydev); 251 } 252 253 static int dp83811_config_init(struct phy_device *phydev) 254 { 255 int value, err; 256 257 err = genphy_config_init(phydev); 258 if (err < 0) 259 return err; 260 261 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { 262 value = phy_read(phydev, MII_DP83811_SGMII_CTRL); 263 if (!(value & DP83811_SGMII_EN)) { 264 err = phy_write(phydev, MII_DP83811_SGMII_CTRL, 265 (DP83811_SGMII_EN | value)); 266 if (err < 0) 267 return err; 268 } else { 269 err = phy_write(phydev, MII_DP83811_SGMII_CTRL, 270 (~DP83811_SGMII_EN & value)); 271 if (err < 0) 272 return err; 273 } 274 } 275 276 value = DP83811_WOL_MAGIC_EN | DP83811_WOL_SECURE_ON | DP83811_WOL_EN; 277 278 return phy_write_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_CFG, 279 value); 280 } 281 282 static int dp83811_phy_reset(struct phy_device *phydev) 283 { 284 int err; 285 286 err = phy_write(phydev, MII_DP83811_RESET_CTRL, DP83811_HW_RESET); 287 if (err < 0) 288 return err; 289 290 return 0; 291 } 292 293 static int dp83811_suspend(struct phy_device *phydev) 294 { 295 int value; 296 297 value = phy_read_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_CFG); 298 299 if (!(value & DP83811_WOL_EN)) 300 genphy_suspend(phydev); 301 302 return 0; 303 } 304 305 static int dp83811_resume(struct phy_device *phydev) 306 { 307 int value; 308 309 genphy_resume(phydev); 310 311 value = phy_read_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_CFG); 312 313 phy_write_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_CFG, value | 314 DP83811_WOL_CLR_INDICATION); 315 316 return 0; 317 } 318 319 static struct phy_driver dp83811_driver[] = { 320 { 321 .phy_id = DP83TC811_PHY_ID, 322 .phy_id_mask = 0xfffffff0, 323 .name = "TI DP83TC811", 324 .features = PHY_BASIC_FEATURES, 325 .flags = PHY_HAS_INTERRUPT, 326 .config_init = dp83811_config_init, 327 .config_aneg = dp83811_config_aneg, 328 .soft_reset = dp83811_phy_reset, 329 .get_wol = dp83811_get_wol, 330 .set_wol = dp83811_set_wol, 331 .ack_interrupt = dp83811_ack_interrupt, 332 .config_intr = dp83811_config_intr, 333 .suspend = dp83811_suspend, 334 .resume = dp83811_resume, 335 }, 336 }; 337 module_phy_driver(dp83811_driver); 338 339 static struct mdio_device_id __maybe_unused dp83811_tbl[] = { 340 { DP83TC811_PHY_ID, 0xfffffff0 }, 341 { }, 342 }; 343 MODULE_DEVICE_TABLE(mdio, dp83811_tbl); 344 345 MODULE_DESCRIPTION("Texas Instruments DP83TC811 PHY driver"); 346 MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com"); 347 MODULE_LICENSE("GPL"); 348