1 // SPDX-License-Identifier: GPL-2.0 2 /* Driver for the Texas Instruments DP83TG720 PHY 3 * Copyright (c) 2023 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> 4 */ 5 #include <linux/bitfield.h> 6 #include <linux/kernel.h> 7 #include <linux/module.h> 8 #include <linux/phy.h> 9 10 #define DP83TG720S_PHY_ID 0x2000a284 11 12 /* MDIO_MMD_VEND2 registers */ 13 #define DP83TG720S_MII_REG_10 0x10 14 #define DP83TG720S_STS_MII_INT BIT(7) 15 #define DP83TG720S_LINK_STATUS BIT(0) 16 17 #define DP83TG720S_PHY_RESET 0x1f 18 #define DP83TG720S_HW_RESET BIT(15) 19 20 #define DP83TG720S_LPS_CFG3 0x18c 21 /* Power modes are documented as bit fields but used as values */ 22 /* Power Mode 0 is Normal mode */ 23 #define DP83TG720S_LPS_CFG3_PWR_MODE_0 BIT(0) 24 25 #define DP83TG720S_RGMII_DELAY_CTRL 0x602 26 /* In RGMII mode, Enable or disable the internal delay for RXD */ 27 #define DP83TG720S_RGMII_RX_CLK_SEL BIT(1) 28 /* In RGMII mode, Enable or disable the internal delay for TXD */ 29 #define DP83TG720S_RGMII_TX_CLK_SEL BIT(0) 30 31 #define DP83TG720S_SQI_REG_1 0x871 32 #define DP83TG720S_SQI_OUT_WORST GENMASK(7, 5) 33 #define DP83TG720S_SQI_OUT GENMASK(3, 1) 34 35 #define DP83TG720_SQI_MAX 7 36 37 static int dp83tg720_config_aneg(struct phy_device *phydev) 38 { 39 int ret; 40 41 /* Autoneg is not supported and this PHY supports only one speed. 42 * We need to care only about master/slave configuration if it was 43 * changed by user. 44 */ 45 ret = genphy_c45_pma_baset1_setup_master_slave(phydev); 46 if (ret) 47 return ret; 48 49 /* Re-read role configuration to make changes visible even if 50 * the link is in administrative down state. 51 */ 52 return genphy_c45_pma_baset1_read_master_slave(phydev); 53 } 54 55 static int dp83tg720_read_status(struct phy_device *phydev) 56 { 57 u16 phy_sts; 58 int ret; 59 60 phydev->pause = 0; 61 phydev->asym_pause = 0; 62 63 /* Most of Clause 45 registers are not present, so we can't use 64 * genphy_c45_read_status() here. 65 */ 66 phy_sts = phy_read(phydev, DP83TG720S_MII_REG_10); 67 phydev->link = !!(phy_sts & DP83TG720S_LINK_STATUS); 68 if (!phydev->link) { 69 /* According to the "DP83TC81x, DP83TG72x Software 70 * Implementation Guide", the PHY needs to be reset after a 71 * link loss or if no link is created after at least 100ms. 72 * 73 * Currently we are polling with the PHY_STATE_TIME (1000ms) 74 * interval, which is still enough for not automotive use cases. 75 */ 76 ret = phy_init_hw(phydev); 77 if (ret) 78 return ret; 79 80 /* After HW reset we need to restore master/slave configuration. 81 * genphy_c45_pma_baset1_read_master_slave() call will be done 82 * by the dp83tg720_config_aneg() function. 83 */ 84 ret = dp83tg720_config_aneg(phydev); 85 if (ret) 86 return ret; 87 88 phydev->speed = SPEED_UNKNOWN; 89 phydev->duplex = DUPLEX_UNKNOWN; 90 } else { 91 /* PMA/PMD control 1 register (Register 1.0) is present, but it 92 * doesn't contain the link speed information. 93 * So genphy_c45_read_pma() can't be used here. 94 */ 95 ret = genphy_c45_pma_baset1_read_master_slave(phydev); 96 if (ret) 97 return ret; 98 99 phydev->duplex = DUPLEX_FULL; 100 phydev->speed = SPEED_1000; 101 } 102 103 return 0; 104 } 105 106 static int dp83tg720_get_sqi(struct phy_device *phydev) 107 { 108 int ret; 109 110 if (!phydev->link) 111 return 0; 112 113 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_SQI_REG_1); 114 if (ret < 0) 115 return ret; 116 117 return FIELD_GET(DP83TG720S_SQI_OUT, ret); 118 } 119 120 static int dp83tg720_get_sqi_max(struct phy_device *phydev) 121 { 122 return DP83TG720_SQI_MAX; 123 } 124 125 static int dp83tg720_config_rgmii_delay(struct phy_device *phydev) 126 { 127 u16 rgmii_delay_mask; 128 u16 rgmii_delay = 0; 129 130 switch (phydev->interface) { 131 case PHY_INTERFACE_MODE_RGMII: 132 rgmii_delay = 0; 133 break; 134 case PHY_INTERFACE_MODE_RGMII_ID: 135 rgmii_delay = DP83TG720S_RGMII_RX_CLK_SEL | 136 DP83TG720S_RGMII_TX_CLK_SEL; 137 break; 138 case PHY_INTERFACE_MODE_RGMII_RXID: 139 rgmii_delay = DP83TG720S_RGMII_RX_CLK_SEL; 140 break; 141 case PHY_INTERFACE_MODE_RGMII_TXID: 142 rgmii_delay = DP83TG720S_RGMII_TX_CLK_SEL; 143 break; 144 default: 145 return 0; 146 } 147 148 rgmii_delay_mask = DP83TG720S_RGMII_RX_CLK_SEL | 149 DP83TG720S_RGMII_TX_CLK_SEL; 150 151 return phy_modify_mmd(phydev, MDIO_MMD_VEND2, 152 DP83TG720S_RGMII_DELAY_CTRL, rgmii_delay_mask, 153 rgmii_delay); 154 } 155 156 static int dp83tg720_config_init(struct phy_device *phydev) 157 { 158 int ret; 159 160 /* Software Restart is not enough to recover from a link failure. 161 * Using Hardware Reset instead. 162 */ 163 ret = phy_write(phydev, DP83TG720S_PHY_RESET, DP83TG720S_HW_RESET); 164 if (ret) 165 return ret; 166 167 /* Wait until MDC can be used again. 168 * The wait value of one 1ms is documented in "DP83TG720S-Q1 1000BASE-T1 169 * Automotive Ethernet PHY with SGMII and RGMII" datasheet. 170 */ 171 usleep_range(1000, 2000); 172 173 if (phy_interface_is_rgmii(phydev)) { 174 ret = dp83tg720_config_rgmii_delay(phydev); 175 if (ret) 176 return ret; 177 } 178 179 /* In case the PHY is bootstrapped in managed mode, we need to 180 * wake it. 181 */ 182 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_LPS_CFG3, 183 DP83TG720S_LPS_CFG3_PWR_MODE_0); 184 if (ret) 185 return ret; 186 187 /* Make role configuration visible for ethtool on init and after 188 * rest. 189 */ 190 return genphy_c45_pma_baset1_read_master_slave(phydev); 191 } 192 193 static struct phy_driver dp83tg720_driver[] = { 194 { 195 PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID), 196 .name = "TI DP83TG720S", 197 198 .config_aneg = dp83tg720_config_aneg, 199 .read_status = dp83tg720_read_status, 200 .get_features = genphy_c45_pma_read_ext_abilities, 201 .config_init = dp83tg720_config_init, 202 .get_sqi = dp83tg720_get_sqi, 203 .get_sqi_max = dp83tg720_get_sqi_max, 204 205 .suspend = genphy_suspend, 206 .resume = genphy_resume, 207 } }; 208 module_phy_driver(dp83tg720_driver); 209 210 static struct mdio_device_id __maybe_unused dp83tg720_tbl[] = { 211 { PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID) }, 212 { } 213 }; 214 MODULE_DEVICE_TABLE(mdio, dp83tg720_tbl); 215 216 MODULE_DESCRIPTION("Texas Instruments DP83TG720S PHY driver"); 217 MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>"); 218 MODULE_LICENSE("GPL"); 219