xref: /openbmc/linux/drivers/net/phy/phy-c45.c (revision 711aab1d)
1 /*
2  * Clause 45 PHY support
3  */
4 #include <linux/ethtool.h>
5 #include <linux/export.h>
6 #include <linux/mdio.h>
7 #include <linux/mii.h>
8 #include <linux/phy.h>
9 
10 /**
11  * genphy_c45_setup_forced - configures a forced speed
12  * @phydev: target phy_device struct
13  */
14 int genphy_c45_pma_setup_forced(struct phy_device *phydev)
15 {
16 	int ctrl1, ctrl2, ret;
17 
18 	/* Half duplex is not supported */
19 	if (phydev->duplex != DUPLEX_FULL)
20 		return -EINVAL;
21 
22 	ctrl1 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1);
23 	if (ctrl1 < 0)
24 		return ctrl1;
25 
26 	ctrl2 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2);
27 	if (ctrl2 < 0)
28 		return ctrl2;
29 
30 	ctrl1 &= ~MDIO_CTRL1_SPEEDSEL;
31 	/*
32 	 * PMA/PMD type selection is 1.7.5:0 not 1.7.3:0.  See 45.2.1.6.1
33 	 * in 802.3-2012 and 802.3-2015.
34 	 */
35 	ctrl2 &= ~(MDIO_PMA_CTRL2_TYPE | 0x30);
36 
37 	switch (phydev->speed) {
38 	case SPEED_10:
39 		ctrl2 |= MDIO_PMA_CTRL2_10BT;
40 		break;
41 	case SPEED_100:
42 		ctrl1 |= MDIO_PMA_CTRL1_SPEED100;
43 		ctrl2 |= MDIO_PMA_CTRL2_100BTX;
44 		break;
45 	case SPEED_1000:
46 		ctrl1 |= MDIO_PMA_CTRL1_SPEED1000;
47 		/* Assume 1000base-T */
48 		ctrl2 |= MDIO_PMA_CTRL2_1000BT;
49 		break;
50 	case SPEED_10000:
51 		ctrl1 |= MDIO_CTRL1_SPEED10G;
52 		/* Assume 10Gbase-T */
53 		ctrl2 |= MDIO_PMA_CTRL2_10GBT;
54 		break;
55 	default:
56 		return -EINVAL;
57 	}
58 
59 	ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, ctrl1);
60 	if (ret < 0)
61 		return ret;
62 
63 	return phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2, ctrl2);
64 }
65 EXPORT_SYMBOL_GPL(genphy_c45_pma_setup_forced);
66 
67 /**
68  * genphy_c45_an_disable_aneg - disable auto-negotiation
69  * @phydev: target phy_device struct
70  *
71  * Disable auto-negotiation in the Clause 45 PHY. The link parameters
72  * parameters are controlled through the PMA/PMD MMD registers.
73  *
74  * Returns zero on success, negative errno code on failure.
75  */
76 int genphy_c45_an_disable_aneg(struct phy_device *phydev)
77 {
78 	int val;
79 
80 	val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
81 	if (val < 0)
82 		return val;
83 
84 	val &= ~(MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART);
85 
86 	return phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, val);
87 }
88 EXPORT_SYMBOL_GPL(genphy_c45_an_disable_aneg);
89 
90 /**
91  * genphy_c45_restart_aneg - Enable and restart auto-negotiation
92  * @phydev: target phy_device struct
93  *
94  * This assumes that the auto-negotiation MMD is present.
95  *
96  * Enable and restart auto-negotiation.
97  */
98 int genphy_c45_restart_aneg(struct phy_device *phydev)
99 {
100 	int val;
101 
102 	val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
103 	if (val < 0)
104 		return val;
105 
106 	val |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART;
107 
108 	return phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, val);
109 }
110 EXPORT_SYMBOL_GPL(genphy_c45_restart_aneg);
111 
112 /**
113  * genphy_c45_aneg_done - return auto-negotiation complete status
114  * @phydev: target phy_device struct
115  *
116  * This assumes that the auto-negotiation MMD is present.
117  *
118  * Reads the status register from the auto-negotiation MMD, returning:
119  * - positive if auto-negotiation is complete
120  * - negative errno code on error
121  * - zero otherwise
122  */
123 int genphy_c45_aneg_done(struct phy_device *phydev)
124 {
125 	int val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
126 
127 	return val < 0 ? val : val & MDIO_AN_STAT1_COMPLETE ? 1 : 0;
128 }
129 EXPORT_SYMBOL_GPL(genphy_c45_aneg_done);
130 
131 /**
132  * genphy_c45_read_link - read the overall link status from the MMDs
133  * @phydev: target phy_device struct
134  * @mmd_mask: MMDs to read status from
135  *
136  * Read the link status from the specified MMDs, and if they all indicate
137  * that the link is up, return positive.  If an error is encountered,
138  * a negative errno will be returned, otherwise zero.
139  */
140 int genphy_c45_read_link(struct phy_device *phydev, u32 mmd_mask)
141 {
142 	int val, devad;
143 	bool link = true;
144 
145 	while (mmd_mask) {
146 		devad = __ffs(mmd_mask);
147 		mmd_mask &= ~BIT(devad);
148 
149 		/* The link state is latched low so that momentary link
150 		 * drops can be detected.  Do not double-read the status
151 		 * register if the link is down.
152 		 */
153 		val = phy_read_mmd(phydev, devad, MDIO_STAT1);
154 		if (val < 0)
155 			return val;
156 
157 		if (!(val & MDIO_STAT1_LSTATUS))
158 			link = false;
159 	}
160 
161 	return link;
162 }
163 EXPORT_SYMBOL_GPL(genphy_c45_read_link);
164 
165 /**
166  * genphy_c45_read_lpa - read the link partner advertisment and pause
167  * @phydev: target phy_device struct
168  *
169  * Read the Clause 45 defined base (7.19) and 10G (7.33) status registers,
170  * filling in the link partner advertisment, pause and asym_pause members
171  * in @phydev.  This assumes that the auto-negotiation MMD is present, and
172  * the backplane bit (7.48.0) is clear.  Clause 45 PHY drivers are expected
173  * to fill in the remainder of the link partner advert from vendor registers.
174  */
175 int genphy_c45_read_lpa(struct phy_device *phydev)
176 {
177 	int val;
178 
179 	/* Read the link partner's base page advertisment */
180 	val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA);
181 	if (val < 0)
182 		return val;
183 
184 	phydev->lp_advertising = mii_lpa_to_ethtool_lpa_t(val);
185 	phydev->pause = val & LPA_PAUSE_CAP ? 1 : 0;
186 	phydev->asym_pause = val & LPA_PAUSE_ASYM ? 1 : 0;
187 
188 	/* Read the link partner's 10G advertisment */
189 	val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
190 	if (val < 0)
191 		return val;
192 
193 	if (val & MDIO_AN_10GBT_STAT_LP10G)
194 		phydev->lp_advertising |= ADVERTISED_10000baseT_Full;
195 
196 	return 0;
197 }
198 EXPORT_SYMBOL_GPL(genphy_c45_read_lpa);
199 
200 /**
201  * genphy_c45_read_pma - read link speed etc from PMA
202  * @phydev: target phy_device struct
203  */
204 int genphy_c45_read_pma(struct phy_device *phydev)
205 {
206 	int val;
207 
208 	val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1);
209 	if (val < 0)
210 		return val;
211 
212 	switch (val & MDIO_CTRL1_SPEEDSEL) {
213 	case 0:
214 		phydev->speed = SPEED_10;
215 		break;
216 	case MDIO_PMA_CTRL1_SPEED100:
217 		phydev->speed = SPEED_100;
218 		break;
219 	case MDIO_PMA_CTRL1_SPEED1000:
220 		phydev->speed = SPEED_1000;
221 		break;
222 	case MDIO_CTRL1_SPEED10G:
223 		phydev->speed = SPEED_10000;
224 		break;
225 	default:
226 		phydev->speed = SPEED_UNKNOWN;
227 		break;
228 	}
229 
230 	phydev->duplex = DUPLEX_FULL;
231 
232 	return 0;
233 }
234 EXPORT_SYMBOL_GPL(genphy_c45_read_pma);
235 
236 /* The gen10g_* functions are the old Clause 45 stub */
237 
238 static int gen10g_config_aneg(struct phy_device *phydev)
239 {
240 	return 0;
241 }
242 
243 static int gen10g_read_status(struct phy_device *phydev)
244 {
245 	u32 mmd_mask = phydev->c45_ids.devices_in_package;
246 	int ret;
247 
248 	/* For now just lie and say it's 10G all the time */
249 	phydev->speed = SPEED_10000;
250 	phydev->duplex = DUPLEX_FULL;
251 
252 	/* Avoid reading the vendor MMDs */
253 	mmd_mask &= ~(BIT(MDIO_MMD_VEND1) | BIT(MDIO_MMD_VEND2));
254 
255 	ret = genphy_c45_read_link(phydev, mmd_mask);
256 
257 	phydev->link = ret > 0 ? 1 : 0;
258 
259 	return 0;
260 }
261 
262 static int gen10g_soft_reset(struct phy_device *phydev)
263 {
264 	/* Do nothing for now */
265 	return 0;
266 }
267 
268 static int gen10g_config_init(struct phy_device *phydev)
269 {
270 	/* Temporarily just say we support everything */
271 	phydev->supported = SUPPORTED_10000baseT_Full;
272 	phydev->advertising = SUPPORTED_10000baseT_Full;
273 
274 	return 0;
275 }
276 
277 static int gen10g_suspend(struct phy_device *phydev)
278 {
279 	return 0;
280 }
281 
282 static int gen10g_resume(struct phy_device *phydev)
283 {
284 	return 0;
285 }
286 
287 struct phy_driver genphy_10g_driver = {
288 	.phy_id         = 0xffffffff,
289 	.phy_id_mask    = 0xffffffff,
290 	.name           = "Generic 10G PHY",
291 	.soft_reset	= gen10g_soft_reset,
292 	.config_init    = gen10g_config_init,
293 	.features       = 0,
294 	.config_aneg    = gen10g_config_aneg,
295 	.read_status    = gen10g_read_status,
296 	.suspend        = gen10g_suspend,
297 	.resume         = gen10g_resume,
298 };
299