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 */
dap8211r_read_ext(struct phy_device * phydev,u16 reg)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 */
dap8211r_modify_ext(struct phy_device * phydev,u16 reg,u16 mask,u16 set)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 */
dap8211r_config_init(struct phy_device * phydev)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