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

dp83td510.c (5345B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Driver for the Texas Instruments DP83TD510 PHY
      3 * Copyright (c) 2022 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
      4 */
      5
      6#include <linux/bitfield.h>
      7#include <linux/kernel.h>
      8#include <linux/module.h>
      9#include <linux/phy.h>
     10
     11#define DP83TD510E_PHY_ID			0x20000181
     12
     13/* MDIO_MMD_VEND2 registers */
     14#define DP83TD510E_PHY_STS			0x10
     15#define DP83TD510E_STS_MII_INT			BIT(7)
     16#define DP83TD510E_LINK_STATUS			BIT(0)
     17
     18#define DP83TD510E_GEN_CFG			0x11
     19#define DP83TD510E_GENCFG_INT_POLARITY		BIT(3)
     20#define DP83TD510E_GENCFG_INT_EN		BIT(1)
     21#define DP83TD510E_GENCFG_INT_OE		BIT(0)
     22
     23#define DP83TD510E_INTERRUPT_REG_1		0x12
     24#define DP83TD510E_INT1_LINK			BIT(13)
     25#define DP83TD510E_INT1_LINK_EN			BIT(5)
     26
     27#define DP83TD510E_AN_STAT_1			0x60c
     28#define DP83TD510E_MASTER_SLAVE_RESOL_FAIL	BIT(15)
     29
     30static int dp83td510_config_intr(struct phy_device *phydev)
     31{
     32	int ret;
     33
     34	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
     35		/* Clear any pending interrupts */
     36		ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_PHY_STS,
     37				    0x0);
     38		if (ret)
     39			return ret;
     40
     41		ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
     42				    DP83TD510E_INTERRUPT_REG_1,
     43				    DP83TD510E_INT1_LINK_EN);
     44		if (ret)
     45			return ret;
     46
     47		ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
     48				       DP83TD510E_GEN_CFG,
     49				       DP83TD510E_GENCFG_INT_POLARITY |
     50				       DP83TD510E_GENCFG_INT_EN |
     51				       DP83TD510E_GENCFG_INT_OE);
     52	} else {
     53		ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
     54				    DP83TD510E_INTERRUPT_REG_1, 0x0);
     55		if (ret)
     56			return ret;
     57
     58		ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,
     59					 DP83TD510E_GEN_CFG,
     60					 DP83TD510E_GENCFG_INT_EN);
     61		if (ret)
     62			return ret;
     63
     64		/* Clear any pending interrupts */
     65		ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_PHY_STS,
     66				    0x0);
     67	}
     68
     69	return ret;
     70}
     71
     72static irqreturn_t dp83td510_handle_interrupt(struct phy_device *phydev)
     73{
     74	int  ret;
     75
     76	ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_PHY_STS);
     77	if (ret < 0) {
     78		phy_error(phydev);
     79		return IRQ_NONE;
     80	} else if (!(ret & DP83TD510E_STS_MII_INT)) {
     81		return IRQ_NONE;
     82	}
     83
     84	/* Read the current enabled interrupts */
     85	ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_INTERRUPT_REG_1);
     86	if (ret < 0) {
     87		phy_error(phydev);
     88		return IRQ_NONE;
     89	} else if (!(ret & DP83TD510E_INT1_LINK_EN) ||
     90		   !(ret & DP83TD510E_INT1_LINK)) {
     91		return IRQ_NONE;
     92	}
     93
     94	phy_trigger_machine(phydev);
     95
     96	return IRQ_HANDLED;
     97}
     98
     99static int dp83td510_read_status(struct phy_device *phydev)
    100{
    101	u16 phy_sts;
    102	int ret;
    103
    104	phydev->speed = SPEED_UNKNOWN;
    105	phydev->duplex = DUPLEX_UNKNOWN;
    106	phydev->pause = 0;
    107	phydev->asym_pause = 0;
    108	linkmode_zero(phydev->lp_advertising);
    109
    110	phy_sts = phy_read(phydev, DP83TD510E_PHY_STS);
    111
    112	phydev->link = !!(phy_sts & DP83TD510E_LINK_STATUS);
    113	if (phydev->link) {
    114		/* This PHY supports only one link mode: 10BaseT1L_Full */
    115		phydev->duplex = DUPLEX_FULL;
    116		phydev->speed = SPEED_10;
    117
    118		if (phydev->autoneg == AUTONEG_ENABLE) {
    119			ret = genphy_c45_read_lpa(phydev);
    120			if (ret)
    121				return ret;
    122
    123			phy_resolve_aneg_linkmode(phydev);
    124		}
    125	}
    126
    127	if (phydev->autoneg == AUTONEG_ENABLE) {
    128		ret = genphy_c45_baset1_read_status(phydev);
    129		if (ret < 0)
    130			return ret;
    131
    132		ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
    133				   DP83TD510E_AN_STAT_1);
    134		if (ret < 0)
    135			return ret;
    136
    137		if (ret & DP83TD510E_MASTER_SLAVE_RESOL_FAIL)
    138			phydev->master_slave_state = MASTER_SLAVE_STATE_ERR;
    139	} else {
    140		return genphy_c45_pma_baset1_read_master_slave(phydev);
    141	}
    142
    143	return 0;
    144}
    145
    146static int dp83td510_config_aneg(struct phy_device *phydev)
    147{
    148	bool changed = false;
    149	int ret;
    150
    151	ret = genphy_c45_pma_baset1_setup_master_slave(phydev);
    152	if (ret < 0)
    153		return ret;
    154
    155	if (phydev->autoneg == AUTONEG_DISABLE)
    156		return genphy_c45_an_disable_aneg(phydev);
    157
    158	ret = genphy_c45_an_config_aneg(phydev);
    159	if (ret < 0)
    160		return ret;
    161	if (ret > 0)
    162		changed = true;
    163
    164	return genphy_c45_check_and_restart_aneg(phydev, changed);
    165}
    166
    167static int dp83td510_get_features(struct phy_device *phydev)
    168{
    169	/* This PHY can't respond on MDIO bus if no RMII clock is enabled.
    170	 * In case RMII mode is used (most meaningful mode for this PHY) and
    171	 * the PHY do not have own XTAL, and CLK providing MAC is not probed,
    172	 * we won't be able to read all needed ability registers.
    173	 * So provide it manually.
    174	 */
    175
    176	linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
    177	linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->supported);
    178	linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported);
    179	linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
    180			 phydev->supported);
    181
    182	return 0;
    183}
    184
    185static struct phy_driver dp83td510_driver[] = {
    186{
    187	PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID),
    188	.name		= "TI DP83TD510E",
    189
    190	.config_aneg	= dp83td510_config_aneg,
    191	.read_status	= dp83td510_read_status,
    192	.get_features	= dp83td510_get_features,
    193	.config_intr	= dp83td510_config_intr,
    194	.handle_interrupt = dp83td510_handle_interrupt,
    195
    196	.suspend	= genphy_suspend,
    197	.resume		= genphy_resume,
    198} };
    199module_phy_driver(dp83td510_driver);
    200
    201static struct mdio_device_id __maybe_unused dp83td510_tbl[] = {
    202	{ PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID) },
    203	{ }
    204};
    205MODULE_DEVICE_TABLE(mdio, dp83td510_tbl);
    206
    207MODULE_DESCRIPTION("Texas Instruments DP83TD510E PHY driver");
    208MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>");
    209MODULE_LICENSE("GPL v2");