Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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