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