cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dp83tc811.c (10599B)


      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		/* 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 status
    271	 * in the upper half (15:8), while the lower half (7:0) is used for
    272	 * controlling the interrupt enable state of those individual interrupt
    273	 * sources. To determine the possible interrupt sources, just read the
    274	 * INT_STAT* register and use it directly to know which interrupts have
    275	 * 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");