1 // SPDX-License-Identifier: GPL-2.0 2 /* Driver for the Texas Instruments DP83822, DP83825 and DP83826 PHYs. 3 * 4 * Copyright (C) 2017 Texas Instruments Inc. 5 */ 6 7 #include <linux/ethtool.h> 8 #include <linux/etherdevice.h> 9 #include <linux/kernel.h> 10 #include <linux/mii.h> 11 #include <linux/module.h> 12 #include <linux/of.h> 13 #include <linux/phy.h> 14 #include <linux/netdevice.h> 15 16 #define DP83822_PHY_ID 0x2000a240 17 #define DP83825S_PHY_ID 0x2000a140 18 #define DP83825I_PHY_ID 0x2000a150 19 #define DP83825CM_PHY_ID 0x2000a160 20 #define DP83825CS_PHY_ID 0x2000a170 21 #define DP83826C_PHY_ID 0x2000a130 22 #define DP83826NC_PHY_ID 0x2000a110 23 24 #define DP83822_DEVADDR 0x1f 25 26 #define MII_DP83822_PHYSCR 0x11 27 #define MII_DP83822_MISR1 0x12 28 #define MII_DP83822_MISR2 0x13 29 #define MII_DP83822_RESET_CTRL 0x1f 30 31 #define DP83822_HW_RESET BIT(15) 32 #define DP83822_SW_RESET BIT(14) 33 34 /* PHYSCR Register Fields */ 35 #define DP83822_PHYSCR_INT_OE BIT(0) /* Interrupt Output Enable */ 36 #define DP83822_PHYSCR_INTEN BIT(1) /* Interrupt Enable */ 37 38 /* MISR1 bits */ 39 #define DP83822_RX_ERR_HF_INT_EN BIT(0) 40 #define DP83822_FALSE_CARRIER_HF_INT_EN BIT(1) 41 #define DP83822_ANEG_COMPLETE_INT_EN BIT(2) 42 #define DP83822_DUP_MODE_CHANGE_INT_EN BIT(3) 43 #define DP83822_SPEED_CHANGED_INT_EN BIT(4) 44 #define DP83822_LINK_STAT_INT_EN BIT(5) 45 #define DP83822_ENERGY_DET_INT_EN BIT(6) 46 #define DP83822_LINK_QUAL_INT_EN BIT(7) 47 48 /* MISR2 bits */ 49 #define DP83822_JABBER_DET_INT_EN BIT(0) 50 #define DP83822_WOL_PKT_INT_EN BIT(1) 51 #define DP83822_SLEEP_MODE_INT_EN BIT(2) 52 #define DP83822_MDI_XOVER_INT_EN BIT(3) 53 #define DP83822_LB_FIFO_INT_EN BIT(4) 54 #define DP83822_PAGE_RX_INT_EN BIT(5) 55 #define DP83822_ANEG_ERR_INT_EN BIT(6) 56 #define DP83822_EEE_ERROR_CHANGE_INT_EN BIT(7) 57 58 /* INT_STAT1 bits */ 59 #define DP83822_WOL_INT_EN BIT(4) 60 #define DP83822_WOL_INT_STAT BIT(12) 61 62 #define MII_DP83822_RXSOP1 0x04a5 63 #define MII_DP83822_RXSOP2 0x04a6 64 #define MII_DP83822_RXSOP3 0x04a7 65 66 /* WoL Registers */ 67 #define MII_DP83822_WOL_CFG 0x04a0 68 #define MII_DP83822_WOL_STAT 0x04a1 69 #define MII_DP83822_WOL_DA1 0x04a2 70 #define MII_DP83822_WOL_DA2 0x04a3 71 #define MII_DP83822_WOL_DA3 0x04a4 72 73 /* WoL bits */ 74 #define DP83822_WOL_MAGIC_EN BIT(0) 75 #define DP83822_WOL_SECURE_ON BIT(5) 76 #define DP83822_WOL_EN BIT(7) 77 #define DP83822_WOL_INDICATION_SEL BIT(8) 78 #define DP83822_WOL_CLR_INDICATION BIT(11) 79 80 static int dp83822_ack_interrupt(struct phy_device *phydev) 81 { 82 int err; 83 84 err = phy_read(phydev, MII_DP83822_MISR1); 85 if (err < 0) 86 return err; 87 88 err = phy_read(phydev, MII_DP83822_MISR2); 89 if (err < 0) 90 return err; 91 92 return 0; 93 } 94 95 static int dp83822_set_wol(struct phy_device *phydev, 96 struct ethtool_wolinfo *wol) 97 { 98 struct net_device *ndev = phydev->attached_dev; 99 u16 value; 100 const u8 *mac; 101 102 if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) { 103 mac = (const u8 *)ndev->dev_addr; 104 105 if (!is_valid_ether_addr(mac)) 106 return -EINVAL; 107 108 /* MAC addresses start with byte 5, but stored in mac[0]. 109 * 822 PHYs store bytes 4|5, 2|3, 0|1 110 */ 111 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA1, 112 (mac[1] << 8) | mac[0]); 113 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA2, 114 (mac[3] << 8) | mac[2]); 115 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA3, 116 (mac[5] << 8) | mac[4]); 117 118 value = phy_read_mmd(phydev, DP83822_DEVADDR, 119 MII_DP83822_WOL_CFG); 120 if (wol->wolopts & WAKE_MAGIC) 121 value |= DP83822_WOL_MAGIC_EN; 122 else 123 value &= ~DP83822_WOL_MAGIC_EN; 124 125 if (wol->wolopts & WAKE_MAGICSECURE) { 126 phy_write_mmd(phydev, DP83822_DEVADDR, 127 MII_DP83822_RXSOP1, 128 (wol->sopass[1] << 8) | wol->sopass[0]); 129 phy_write_mmd(phydev, DP83822_DEVADDR, 130 MII_DP83822_RXSOP2, 131 (wol->sopass[3] << 8) | wol->sopass[2]); 132 phy_write_mmd(phydev, DP83822_DEVADDR, 133 MII_DP83822_RXSOP3, 134 (wol->sopass[5] << 8) | wol->sopass[4]); 135 value |= DP83822_WOL_SECURE_ON; 136 } else { 137 value &= ~DP83822_WOL_SECURE_ON; 138 } 139 140 value |= (DP83822_WOL_EN | DP83822_WOL_INDICATION_SEL | 141 DP83822_WOL_CLR_INDICATION); 142 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, 143 value); 144 } else { 145 value = phy_read_mmd(phydev, DP83822_DEVADDR, 146 MII_DP83822_WOL_CFG); 147 value &= ~DP83822_WOL_EN; 148 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, 149 value); 150 } 151 152 return 0; 153 } 154 155 static void dp83822_get_wol(struct phy_device *phydev, 156 struct ethtool_wolinfo *wol) 157 { 158 int value; 159 u16 sopass_val; 160 161 wol->supported = (WAKE_MAGIC | WAKE_MAGICSECURE); 162 wol->wolopts = 0; 163 164 value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG); 165 166 if (value & DP83822_WOL_MAGIC_EN) 167 wol->wolopts |= WAKE_MAGIC; 168 169 if (value & DP83822_WOL_SECURE_ON) { 170 sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR, 171 MII_DP83822_RXSOP1); 172 wol->sopass[0] = (sopass_val & 0xff); 173 wol->sopass[1] = (sopass_val >> 8); 174 175 sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR, 176 MII_DP83822_RXSOP2); 177 wol->sopass[2] = (sopass_val & 0xff); 178 wol->sopass[3] = (sopass_val >> 8); 179 180 sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR, 181 MII_DP83822_RXSOP3); 182 wol->sopass[4] = (sopass_val & 0xff); 183 wol->sopass[5] = (sopass_val >> 8); 184 185 wol->wolopts |= WAKE_MAGICSECURE; 186 } 187 188 /* WoL is not enabled so set wolopts to 0 */ 189 if (!(value & DP83822_WOL_EN)) 190 wol->wolopts = 0; 191 } 192 193 static int dp83822_config_intr(struct phy_device *phydev) 194 { 195 int misr_status; 196 int physcr_status; 197 int err; 198 199 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 200 misr_status = phy_read(phydev, MII_DP83822_MISR1); 201 if (misr_status < 0) 202 return misr_status; 203 204 misr_status |= (DP83822_RX_ERR_HF_INT_EN | 205 DP83822_FALSE_CARRIER_HF_INT_EN | 206 DP83822_ANEG_COMPLETE_INT_EN | 207 DP83822_DUP_MODE_CHANGE_INT_EN | 208 DP83822_SPEED_CHANGED_INT_EN | 209 DP83822_LINK_STAT_INT_EN | 210 DP83822_ENERGY_DET_INT_EN | 211 DP83822_LINK_QUAL_INT_EN); 212 213 err = phy_write(phydev, MII_DP83822_MISR1, misr_status); 214 if (err < 0) 215 return err; 216 217 misr_status = phy_read(phydev, MII_DP83822_MISR2); 218 if (misr_status < 0) 219 return misr_status; 220 221 misr_status |= (DP83822_JABBER_DET_INT_EN | 222 DP83822_WOL_PKT_INT_EN | 223 DP83822_SLEEP_MODE_INT_EN | 224 DP83822_MDI_XOVER_INT_EN | 225 DP83822_LB_FIFO_INT_EN | 226 DP83822_PAGE_RX_INT_EN | 227 DP83822_ANEG_ERR_INT_EN | 228 DP83822_EEE_ERROR_CHANGE_INT_EN); 229 230 err = phy_write(phydev, MII_DP83822_MISR2, misr_status); 231 if (err < 0) 232 return err; 233 234 physcr_status = phy_read(phydev, MII_DP83822_PHYSCR); 235 if (physcr_status < 0) 236 return physcr_status; 237 238 physcr_status |= DP83822_PHYSCR_INT_OE | DP83822_PHYSCR_INTEN; 239 240 } else { 241 err = phy_write(phydev, MII_DP83822_MISR1, 0); 242 if (err < 0) 243 return err; 244 245 err = phy_write(phydev, MII_DP83822_MISR1, 0); 246 if (err < 0) 247 return err; 248 249 physcr_status = phy_read(phydev, MII_DP83822_PHYSCR); 250 if (physcr_status < 0) 251 return physcr_status; 252 253 physcr_status &= ~DP83822_PHYSCR_INTEN; 254 } 255 256 return phy_write(phydev, MII_DP83822_PHYSCR, physcr_status); 257 } 258 259 static int dp83822_config_init(struct phy_device *phydev) 260 { 261 int value; 262 263 value = DP83822_WOL_MAGIC_EN | DP83822_WOL_SECURE_ON | DP83822_WOL_EN; 264 265 return phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, 266 value); 267 } 268 269 static int dp83822_phy_reset(struct phy_device *phydev) 270 { 271 int err; 272 273 err = phy_write(phydev, MII_DP83822_RESET_CTRL, DP83822_HW_RESET); 274 if (err < 0) 275 return err; 276 277 dp83822_config_init(phydev); 278 279 return 0; 280 } 281 282 static int dp83822_suspend(struct phy_device *phydev) 283 { 284 int value; 285 286 value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG); 287 288 if (!(value & DP83822_WOL_EN)) 289 genphy_suspend(phydev); 290 291 return 0; 292 } 293 294 static int dp83822_resume(struct phy_device *phydev) 295 { 296 int value; 297 298 genphy_resume(phydev); 299 300 value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG); 301 302 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, value | 303 DP83822_WOL_CLR_INDICATION); 304 305 return 0; 306 } 307 308 #define DP83822_PHY_DRIVER(_id, _name) \ 309 { \ 310 PHY_ID_MATCH_MODEL(_id), \ 311 .name = (_name), \ 312 /* PHY_BASIC_FEATURES */ \ 313 .soft_reset = dp83822_phy_reset, \ 314 .config_init = dp83822_config_init, \ 315 .get_wol = dp83822_get_wol, \ 316 .set_wol = dp83822_set_wol, \ 317 .ack_interrupt = dp83822_ack_interrupt, \ 318 .config_intr = dp83822_config_intr, \ 319 .suspend = dp83822_suspend, \ 320 .resume = dp83822_resume, \ 321 } 322 323 static struct phy_driver dp83822_driver[] = { 324 DP83822_PHY_DRIVER(DP83822_PHY_ID, "TI DP83822"), 325 DP83822_PHY_DRIVER(DP83825I_PHY_ID, "TI DP83825I"), 326 DP83822_PHY_DRIVER(DP83826C_PHY_ID, "TI DP83826C"), 327 DP83822_PHY_DRIVER(DP83826NC_PHY_ID, "TI DP83826NC"), 328 DP83822_PHY_DRIVER(DP83825S_PHY_ID, "TI DP83825S"), 329 DP83822_PHY_DRIVER(DP83825CM_PHY_ID, "TI DP83825M"), 330 DP83822_PHY_DRIVER(DP83825CS_PHY_ID, "TI DP83825CS"), 331 }; 332 module_phy_driver(dp83822_driver); 333 334 static struct mdio_device_id __maybe_unused dp83822_tbl[] = { 335 { DP83822_PHY_ID, 0xfffffff0 }, 336 { DP83825I_PHY_ID, 0xfffffff0 }, 337 { DP83826C_PHY_ID, 0xfffffff0 }, 338 { DP83826NC_PHY_ID, 0xfffffff0 }, 339 { DP83825S_PHY_ID, 0xfffffff0 }, 340 { DP83825CM_PHY_ID, 0xfffffff0 }, 341 { DP83825CS_PHY_ID, 0xfffffff0 }, 342 { }, 343 }; 344 MODULE_DEVICE_TABLE(mdio, dp83822_tbl); 345 346 MODULE_DESCRIPTION("Texas Instruments DP83822 PHY driver"); 347 MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com"); 348 MODULE_LICENSE("GPL v2"); 349