1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for the DAPU Telecom DAP8211R(I) Gigabit Ethernet PHY. 4 * 5 * Specifications: 6 * - IEEE 802.3 10BASE-Te, 100BASE-TX, 1000BASE-T 7 * - IEEE 802.3az-2010 Energy Efficient Ethernet 8 * - IEEE 1588 SyncE support 9 * - RGMII 10 * 11 * Author: Artem Shimko <a.shimko.dev@gmail.com> 12 */ 13 14 #include <linux/bitfield.h> 15 #include <linux/errno.h> 16 #include <linux/ethtool.h> 17 #include <linux/kernel.h> 18 #include <linux/iopoll.h> 19 #include <linux/mii.h> 20 #include <linux/module.h> 21 #include <linux/netdevice.h> 22 #include <linux/phy.h> 23 24 #define DAP8211R_PHY_ID 0x0008011B 25 #define DAP8211R_PHY_ID_MASK 0xFFFFFFFF 26 27 #define DAP8211R_EXT_ADD 0x1E 28 #define DAP8211R_EXT_DATA 0x1F 29 30 #define DAP8211R_PHY_CON 0xA001 31 #define DAP8211R_PHY_SW_RST BIT(15) 32 33 #define DAP8211R_RGMII_CON 0xA003 34 #define DAP8211R_RGMII_TX_DEL_MASK GENMASK(3, 0) 35 #define DAP8211R_RGMII_RX_DEL_MASK GENMASK(13, 10) 36 37 #define DAP8211R_RGMII_CONFIG_MASK (DAP8211R_RGMII_RX_DEL_MASK | DAP8211R_RGMII_TX_DEL_MASK) 38 39 /* 40 * Hardware reset RX RGMII default delay from the datasheet: 0 * 150ps == 0.00ns 41 * Used when rx-internal-delay-ps is not specified in DT for RGMII mode and 42 * in RGMII_TXID to set rx delay. 43 */ 44 #define DAP8211R_INITIAL_RX_DEL_VAL 0 45 46 /* 47 * Hardware reset TX RGMII default delay from the datasheet: 1 * 150ps == 0.15ns 48 * Used when tx-internal-delay-ps is not specified in DT for RGMII mode and 49 * in RGMII_RXID to set tx delay. 50 */ 51 #define DAP8211R_INITIAL_TX_DEL_VAL 1 52 53 /* 54 * Default RGMII delay: 13 * 150 == 1.95ns 55 * Used when rx-internal-delay-ps or tx-internal-delay-ps are not specified in DT 56 * for RGMII ID modes to set tx or rx delay. 57 */ 58 #define DAP8211R_DEFAULT_DEL_SEL 0xD 59 60 static const int dap8211r_internal_delay[] = {0, 150, 300, 450, 600, 750, 900, 61 1050, 1200, 1350, 1500, 1650, 1800, 62 1950, 2100, 2250}; 63 64 #define DAP8211R_DELAY_SIZE ARRAY_SIZE(dap8211r_internal_delay) 65 66 /** 67 * dap8211r_read_ext() - Read extended register 68 * @phydev: PHY device structure 69 * @reg: Extended register address 70 * 71 * Reads a PHY extended register using the indirect access method. 72 * The caller must hold the MDIO bus lock. 73 * 74 * Return: Register value on success, or negative error code 75 */ 76 static int dap8211r_read_ext(struct phy_device *phydev, u16 reg) 77 { 78 int ret; 79 80 phy_lock_mdio_bus(phydev); 81 ret = __phy_write(phydev, DAP8211R_EXT_ADD, reg); 82 if (ret < 0) 83 goto out; 84 85 ret = __phy_read(phydev, DAP8211R_EXT_DATA); 86 out: 87 phy_unlock_mdio_bus(phydev); 88 return ret; 89 } 90 91 /** 92 * dap8211r_modify_ext() - Modify extended register bits 93 * @phydev: PHY device structure 94 * @reg: Extended register address 95 * @mask: Bit mask of bits to clear 96 * @set: Bit mask of bits to set 97 * 98 * Modifies a PHY extended register using the indirect access method. 99 * New value = (old value & ~mask) | set. 100 * The caller must hold the MDIO bus lock. 101 * 102 * Return: 0 on success, or negative error code 103 */ 104 static int dap8211r_modify_ext(struct phy_device *phydev, u16 reg, u16 mask, u16 set) 105 { 106 int ret; 107 108 phy_lock_mdio_bus(phydev); 109 ret = __phy_write(phydev, DAP8211R_EXT_ADD, reg); 110 if (ret < 0) 111 goto out; 112 113 ret = __phy_modify(phydev, DAP8211R_EXT_DATA, mask, set); 114 out: 115 phy_unlock_mdio_bus(phydev); 116 return ret; 117 } 118 119 /** 120 * dap8211r_config_init() - Initialize PHY 121 * @phydev: PHY device structure 122 * 123 * Configures the PHY during initialization: 124 * - RGMII delays based on interface mode 125 * - Software reset to apply settings (low active, self clear) 126 * 127 * Return: 0 on success, or negative error code 128 */ 129 static int dap8211r_config_init(struct phy_device *phydev) 130 { 131 u16 set = 0; 132 int ret, val; 133 s32 rx_internal_delay = DAP8211R_INITIAL_RX_DEL_VAL; 134 s32 tx_internal_delay = DAP8211R_INITIAL_TX_DEL_VAL; 135 136 if (!phy_interface_is_rgmii(phydev)) 137 return 0; 138 139 if (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID) 140 rx_internal_delay = phy_get_internal_delay(phydev, dap8211r_internal_delay, 141 DAP8211R_DELAY_SIZE, true); 142 143 if (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID) 144 tx_internal_delay = phy_get_internal_delay(phydev, dap8211r_internal_delay, 145 DAP8211R_DELAY_SIZE, false); 146 147 switch (phydev->interface) { 148 case PHY_INTERFACE_MODE_RGMII: 149 if (rx_internal_delay < 0) 150 rx_internal_delay = DAP8211R_INITIAL_RX_DEL_VAL; 151 152 if (tx_internal_delay < 0) 153 tx_internal_delay = DAP8211R_INITIAL_TX_DEL_VAL; 154 break; 155 case PHY_INTERFACE_MODE_RGMII_RXID: 156 if (rx_internal_delay < 0) 157 rx_internal_delay = DAP8211R_DEFAULT_DEL_SEL; 158 break; 159 case PHY_INTERFACE_MODE_RGMII_ID: 160 if (rx_internal_delay < 0) 161 rx_internal_delay = DAP8211R_DEFAULT_DEL_SEL; 162 fallthrough; 163 case PHY_INTERFACE_MODE_RGMII_TXID: 164 if (tx_internal_delay < 0) 165 tx_internal_delay = DAP8211R_DEFAULT_DEL_SEL; 166 break; 167 default: 168 phydev_err(phydev, "Unsupported interface: %d\n", 169 phydev->interface); 170 return -EINVAL; 171 } 172 173 set |= FIELD_PREP(DAP8211R_RGMII_RX_DEL_MASK, rx_internal_delay); 174 set |= FIELD_PREP(DAP8211R_RGMII_TX_DEL_MASK, tx_internal_delay); 175 176 ret = dap8211r_modify_ext(phydev, DAP8211R_PHY_CON, DAP8211R_PHY_SW_RST, 0); 177 if (ret) 178 return ret; 179 180 /* Wait for reset self-clear (from low active to high) */ 181 ret = read_poll_timeout(dap8211r_read_ext, val, 182 (val & DAP8211R_PHY_SW_RST), 183 20, 200, false, phydev, DAP8211R_PHY_CON); 184 if (ret) 185 return ret; 186 if (val < 0) 187 return val; 188 189 ret = dap8211r_modify_ext(phydev, DAP8211R_RGMII_CON, DAP8211R_RGMII_CONFIG_MASK, set); 190 if (ret) 191 return ret; 192 193 return 0; 194 } 195 196 static struct phy_driver dap8211r_driver[] = { 197 { 198 PHY_ID_MATCH_EXACT(DAP8211R_PHY_ID), 199 .name = "DAP8211R Gigabit Ethernet", 200 .soft_reset = genphy_soft_reset, 201 .config_init = dap8211r_config_init, 202 .read_status = genphy_read_status, 203 .set_loopback = genphy_loopback, 204 .config_aneg = genphy_config_aneg, 205 .suspend = genphy_suspend, 206 .resume = genphy_resume, 207 }, 208 }; 209 module_phy_driver(dap8211r_driver); 210 211 MODULE_DESCRIPTION("DAP8211R Gigabit Ethernet PHY driver"); 212 MODULE_AUTHOR("Artem Shimko <a.shimko.dev@gmail.com>"); 213 MODULE_LICENSE("GPL"); 214 215 static const struct mdio_device_id __maybe_unused dap8211r_tb[] = { 216 { DAP8211R_PHY_ID, DAP8211R_PHY_ID_MASK }, 217 { /* sentinel */ } 218 }; 219 MODULE_DEVICE_TABLE(mdio, dap8211r_tb); 220 221