xref: /linux/drivers/net/phy/dap8211r.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
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