415 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Driver for the Texas Instruments DP83TC811 PHY4 *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 0x2000a25319#define DP83811_DEVADDR 0x1f20 21#define MII_DP83811_SGMII_CTRL 0x0922#define MII_DP83811_INT_STAT1 0x1223#define MII_DP83811_INT_STAT2 0x1324#define MII_DP83811_INT_STAT3 0x1825#define MII_DP83811_RESET_CTRL 0x1f26 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 0x04a554#define MII_DP83811_RXSOP2 0x04a655#define MII_DP83811_RXSOP3 0x04a756 57/* WoL Registers */58#define MII_DP83811_WOL_CFG 0x04a059#define MII_DP83811_WOL_STAT 0x04a160#define MII_DP83811_WOL_DA1 0x04a261#define MII_DP83811_WOL_DA2 0x04a362#define MII_DP83811_WOL_DA3 0x04a463 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|1112 */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 else125 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 /* Clear any pending WoL interrupt */143 phy_read(phydev, MII_DP83811_INT_STAT1);144 145 value |= DP83811_WOL_EN | DP83811_WOL_INDICATION_SEL |146 DP83811_WOL_CLR_INDICATION;147 148 return phy_write_mmd(phydev, DP83811_DEVADDR,149 MII_DP83811_WOL_CFG, value);150 } else {151 return phy_clear_bits_mmd(phydev, DP83811_DEVADDR,152 MII_DP83811_WOL_CFG, DP83811_WOL_EN);153 }154 155}156 157static void dp83811_get_wol(struct phy_device *phydev,158 struct ethtool_wolinfo *wol)159{160 u16 sopass_val;161 int value;162 163 wol->supported = (WAKE_MAGIC | WAKE_MAGICSECURE);164 wol->wolopts = 0;165 166 value = phy_read_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_CFG);167 168 if (value & DP83811_WOL_MAGIC_EN)169 wol->wolopts |= WAKE_MAGIC;170 171 if (value & DP83811_WOL_SECURE_ON) {172 sopass_val = phy_read_mmd(phydev, DP83811_DEVADDR,173 MII_DP83811_RXSOP1);174 wol->sopass[0] = (sopass_val & 0xff);175 wol->sopass[1] = (sopass_val >> 8);176 177 sopass_val = phy_read_mmd(phydev, DP83811_DEVADDR,178 MII_DP83811_RXSOP2);179 wol->sopass[2] = (sopass_val & 0xff);180 wol->sopass[3] = (sopass_val >> 8);181 182 sopass_val = phy_read_mmd(phydev, DP83811_DEVADDR,183 MII_DP83811_RXSOP3);184 wol->sopass[4] = (sopass_val & 0xff);185 wol->sopass[5] = (sopass_val >> 8);186 187 wol->wolopts |= WAKE_MAGICSECURE;188 }189 190 /* WoL is not enabled so set wolopts to 0 */191 if (!(value & DP83811_WOL_EN))192 wol->wolopts = 0;193}194 195static int dp83811_config_intr(struct phy_device *phydev)196{197 int misr_status, err;198 199 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {200 err = dp83811_ack_interrupt(phydev);201 if (err)202 return err;203 204 misr_status = phy_read(phydev, MII_DP83811_INT_STAT1);205 if (misr_status < 0)206 return misr_status;207 208 misr_status |= (DP83811_RX_ERR_HF_INT_EN |209 DP83811_MS_TRAINING_INT_EN |210 DP83811_ANEG_COMPLETE_INT_EN |211 DP83811_ESD_EVENT_INT_EN |212 DP83811_WOL_INT_EN |213 DP83811_LINK_STAT_INT_EN |214 DP83811_ENERGY_DET_INT_EN |215 DP83811_LINK_QUAL_INT_EN);216 217 err = phy_write(phydev, MII_DP83811_INT_STAT1, misr_status);218 if (err < 0)219 return err;220 221 misr_status = phy_read(phydev, MII_DP83811_INT_STAT2);222 if (misr_status < 0)223 return misr_status;224 225 misr_status |= (DP83811_JABBER_DET_INT_EN |226 DP83811_POLARITY_INT_EN |227 DP83811_SLEEP_MODE_INT_EN |228 DP83811_OVERTEMP_INT_EN |229 DP83811_OVERVOLTAGE_INT_EN |230 DP83811_UNDERVOLTAGE_INT_EN);231 232 err = phy_write(phydev, MII_DP83811_INT_STAT2, misr_status);233 if (err < 0)234 return err;235 236 misr_status = phy_read(phydev, MII_DP83811_INT_STAT3);237 if (misr_status < 0)238 return misr_status;239 240 misr_status |= (DP83811_LPS_INT_EN |241 DP83811_NO_FRAME_INT_EN |242 DP83811_POR_DONE_INT_EN);243 244 err = phy_write(phydev, MII_DP83811_INT_STAT3, misr_status);245 246 } else {247 err = phy_write(phydev, MII_DP83811_INT_STAT1, 0);248 if (err < 0)249 return err;250 251 err = phy_write(phydev, MII_DP83811_INT_STAT2, 0);252 if (err < 0)253 return err;254 255 err = phy_write(phydev, MII_DP83811_INT_STAT3, 0);256 if (err < 0)257 return err;258 259 err = dp83811_ack_interrupt(phydev);260 }261 262 return err;263}264 265static irqreturn_t dp83811_handle_interrupt(struct phy_device *phydev)266{267 bool trigger_machine = false;268 int irq_status;269 270 /* The INT_STAT registers 1, 2 and 3 are holding the interrupt status271 * in the upper half (15:8), while the lower half (7:0) is used for272 * controlling the interrupt enable state of those individual interrupt273 * sources. To determine the possible interrupt sources, just read the274 * INT_STAT* register and use it directly to know which interrupts have275 * been enabled previously or not.276 */277 irq_status = phy_read(phydev, MII_DP83811_INT_STAT1);278 if (irq_status < 0) {279 phy_error(phydev);280 return IRQ_NONE;281 }282 if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))283 trigger_machine = true;284 285 irq_status = phy_read(phydev, MII_DP83811_INT_STAT2);286 if (irq_status < 0) {287 phy_error(phydev);288 return IRQ_NONE;289 }290 if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))291 trigger_machine = true;292 293 irq_status = phy_read(phydev, MII_DP83811_INT_STAT3);294 if (irq_status < 0) {295 phy_error(phydev);296 return IRQ_NONE;297 }298 if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))299 trigger_machine = true;300 301 if (!trigger_machine)302 return IRQ_NONE;303 304 phy_trigger_machine(phydev);305 306 return IRQ_HANDLED;307}308 309static int dp83811_config_aneg(struct phy_device *phydev)310{311 int value, err;312 313 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {314 value = phy_read(phydev, MII_DP83811_SGMII_CTRL);315 if (phydev->autoneg == AUTONEG_ENABLE) {316 err = phy_write(phydev, MII_DP83811_SGMII_CTRL,317 (DP83811_SGMII_AUTO_NEG_EN | value));318 if (err < 0)319 return err;320 } else {321 err = phy_write(phydev, MII_DP83811_SGMII_CTRL,322 (~DP83811_SGMII_AUTO_NEG_EN & value));323 if (err < 0)324 return err;325 }326 }327 328 return genphy_config_aneg(phydev);329}330 331static int dp83811_config_init(struct phy_device *phydev)332{333 int value, err;334 335 value = phy_read(phydev, MII_DP83811_SGMII_CTRL);336 if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {337 err = phy_write(phydev, MII_DP83811_SGMII_CTRL,338 (DP83811_SGMII_EN | value));339 } else {340 err = phy_write(phydev, MII_DP83811_SGMII_CTRL,341 (~DP83811_SGMII_EN & value));342 }343 344 if (err < 0)345 346 return err;347 348 value = DP83811_WOL_MAGIC_EN | DP83811_WOL_SECURE_ON | DP83811_WOL_EN;349 350 return phy_clear_bits_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_CFG,351 value);352}353 354static int dp83811_phy_reset(struct phy_device *phydev)355{356 int err;357 358 err = phy_write(phydev, MII_DP83811_RESET_CTRL, DP83811_HW_RESET);359 if (err < 0)360 return err;361 362 return 0;363}364 365static int dp83811_suspend(struct phy_device *phydev)366{367 int value;368 369 value = phy_read_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_CFG);370 371 if (!(value & DP83811_WOL_EN))372 genphy_suspend(phydev);373 374 return 0;375}376 377static int dp83811_resume(struct phy_device *phydev)378{379 genphy_resume(phydev);380 381 phy_set_bits_mmd(phydev, DP83811_DEVADDR, MII_DP83811_WOL_CFG,382 DP83811_WOL_CLR_INDICATION);383 384 return 0;385}386 387static struct phy_driver dp83811_driver[] = {388 {389 .phy_id = DP83TC811_PHY_ID,390 .phy_id_mask = 0xfffffff0,391 .name = "TI DP83TC811",392 /* PHY_BASIC_FEATURES */393 .config_init = dp83811_config_init,394 .config_aneg = dp83811_config_aneg,395 .soft_reset = dp83811_phy_reset,396 .get_wol = dp83811_get_wol,397 .set_wol = dp83811_set_wol,398 .config_intr = dp83811_config_intr,399 .handle_interrupt = dp83811_handle_interrupt,400 .suspend = dp83811_suspend,401 .resume = dp83811_resume,402 },403};404module_phy_driver(dp83811_driver);405 406static struct mdio_device_id __maybe_unused dp83811_tbl[] = {407 { DP83TC811_PHY_ID, 0xfffffff0 },408 { },409};410MODULE_DEVICE_TABLE(mdio, dp83811_tbl);411 412MODULE_DESCRIPTION("Texas Instruments DP83TC811 PHY driver");413MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com");414MODULE_LICENSE("GPL");415