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