xref: /linux/drivers/net/pcs/pcs-lynx.c (revision c31f4aa8fed048fa70e742c4bb49bb48dc489ab3)
1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2 /* Copyright 2020 NXP
3  * Lynx PCS MDIO helpers
4  */
5 
6 #include <linux/mdio.h>
7 #include <linux/phylink.h>
8 #include <linux/pcs-lynx.h>
9 #include <linux/property.h>
10 
11 #define SGMII_CLOCK_PERIOD_NS		8 /* PCS is clocked at 125 MHz */
12 #define LINK_TIMER_VAL(ns)		((u32)((ns) / SGMII_CLOCK_PERIOD_NS))
13 
14 #define LINK_TIMER_LO			0x12
15 #define LINK_TIMER_HI			0x13
16 #define IF_MODE				0x14
17 #define IF_MODE_SGMII_EN		BIT(0)
18 #define IF_MODE_USE_SGMII_AN		BIT(1)
19 #define IF_MODE_SPEED(x)		(((x) << 2) & GENMASK(3, 2))
20 #define IF_MODE_SPEED_MSK		GENMASK(3, 2)
21 #define IF_MODE_HALF_DUPLEX		BIT(4)
22 
23 struct lynx_pcs {
24 	struct phylink_pcs pcs;
25 	struct mdio_device *mdio;
26 };
27 
28 enum sgmii_speed {
29 	SGMII_SPEED_10		= 0,
30 	SGMII_SPEED_100		= 1,
31 	SGMII_SPEED_1000	= 2,
32 	SGMII_SPEED_2500	= 2,
33 };
34 
35 #define phylink_pcs_to_lynx(pl_pcs) container_of((pl_pcs), struct lynx_pcs, pcs)
36 #define lynx_to_phylink_pcs(lynx) (&(lynx)->pcs)
37 
38 static unsigned int lynx_pcs_inband_caps(struct phylink_pcs *pcs,
39 					 phy_interface_t interface)
40 {
41 	switch (interface) {
42 	case PHY_INTERFACE_MODE_1000BASEX:
43 	case PHY_INTERFACE_MODE_2500BASEX:
44 	case PHY_INTERFACE_MODE_SGMII:
45 	case PHY_INTERFACE_MODE_QSGMII:
46 		return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
47 
48 	case PHY_INTERFACE_MODE_10GBASER:
49 		return LINK_INBAND_DISABLE;
50 
51 	case PHY_INTERFACE_MODE_USXGMII:
52 	case PHY_INTERFACE_MODE_10G_QXGMII:
53 		return LINK_INBAND_ENABLE;
54 
55 	default:
56 		return 0;
57 	}
58 }
59 
60 static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs,
61 				       struct phylink_link_state *state)
62 {
63 	struct mii_bus *bus = pcs->bus;
64 	int addr = pcs->addr;
65 	int status, lpa;
66 
67 	status = mdiobus_c45_read(bus, addr, MDIO_MMD_VEND2, MII_BMSR);
68 	if (status < 0)
69 		return;
70 
71 	state->link = !!(status & MDIO_STAT1_LSTATUS);
72 	state->an_complete = !!(status & MDIO_AN_STAT1_COMPLETE);
73 	if (!state->link || !state->an_complete)
74 		return;
75 
76 	lpa = mdiobus_c45_read(bus, addr, MDIO_MMD_VEND2, MII_LPA);
77 	if (lpa < 0)
78 		return;
79 
80 	phylink_decode_usxgmii_word(state, lpa);
81 }
82 
83 static void lynx_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
84 			       struct phylink_link_state *state)
85 {
86 	struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
87 
88 	switch (state->interface) {
89 	case PHY_INTERFACE_MODE_1000BASEX:
90 	case PHY_INTERFACE_MODE_2500BASEX:
91 	case PHY_INTERFACE_MODE_SGMII:
92 	case PHY_INTERFACE_MODE_QSGMII:
93 		phylink_mii_c22_pcs_get_state(lynx->mdio, neg_mode, state);
94 		break;
95 	case PHY_INTERFACE_MODE_USXGMII:
96 	case PHY_INTERFACE_MODE_10G_QXGMII:
97 		lynx_pcs_get_state_usxgmii(lynx->mdio, state);
98 		break;
99 	case PHY_INTERFACE_MODE_10GBASER:
100 		phylink_mii_c45_pcs_get_state(lynx->mdio, state);
101 		break;
102 	default:
103 		break;
104 	}
105 
106 	dev_dbg(&lynx->mdio->dev,
107 		"mode=%s/%s/%s link=%u an_complete=%u\n",
108 		phy_modes(state->interface),
109 		phy_speed_to_str(state->speed),
110 		phy_duplex_to_str(state->duplex),
111 		state->link, state->an_complete);
112 }
113 
114 static int lynx_pcs_config_giga(struct mdio_device *pcs,
115 				phy_interface_t interface,
116 				const unsigned long *advertising,
117 				unsigned int neg_mode)
118 {
119 	int link_timer_ns;
120 	u32 link_timer;
121 	u16 if_mode;
122 	int err;
123 
124 	link_timer_ns = phylink_get_link_timer_ns(interface);
125 	if (link_timer_ns > 0) {
126 		link_timer = LINK_TIMER_VAL(link_timer_ns);
127 
128 		mdiodev_write(pcs, LINK_TIMER_LO, link_timer & 0xffff);
129 		mdiodev_write(pcs, LINK_TIMER_HI, link_timer >> 16);
130 	}
131 
132 	if (interface == PHY_INTERFACE_MODE_1000BASEX ||
133 	    interface == PHY_INTERFACE_MODE_2500BASEX) {
134 		if_mode = 0;
135 	} else {
136 		/* SGMII and QSGMII */
137 		if_mode = IF_MODE_SGMII_EN;
138 		if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
139 			if_mode |= IF_MODE_USE_SGMII_AN;
140 	}
141 
142 	err = mdiodev_modify(pcs, IF_MODE,
143 			     IF_MODE_SGMII_EN | IF_MODE_USE_SGMII_AN,
144 			     if_mode);
145 	if (err)
146 		return err;
147 
148 	return phylink_mii_c22_pcs_config(pcs, interface, advertising,
149 					  neg_mode);
150 }
151 
152 static int lynx_pcs_config_usxgmii(struct mdio_device *pcs,
153 				   phy_interface_t interface,
154 				   const unsigned long *advertising,
155 				   unsigned int neg_mode)
156 {
157 	struct mii_bus *bus = pcs->bus;
158 	int addr = pcs->addr;
159 
160 	if (neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED) {
161 		dev_err(&pcs->dev, "%s only supports in-band AN for now\n",
162 			phy_modes(interface));
163 		return -EOPNOTSUPP;
164 	}
165 
166 	/* Configure device ability for the USXGMII Replicator */
167 	return mdiobus_c45_write(bus, addr, MDIO_MMD_VEND2, MII_ADVERTISE,
168 				 MDIO_USXGMII_10G | MDIO_USXGMII_LINK |
169 				 MDIO_USXGMII_FULL_DUPLEX |
170 				 ADVERTISE_SGMII | ADVERTISE_LPACK);
171 }
172 
173 static int lynx_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
174 			   phy_interface_t ifmode,
175 			   const unsigned long *advertising, bool permit)
176 {
177 	struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
178 
179 	switch (ifmode) {
180 	case PHY_INTERFACE_MODE_1000BASEX:
181 	case PHY_INTERFACE_MODE_SGMII:
182 	case PHY_INTERFACE_MODE_QSGMII:
183 	case PHY_INTERFACE_MODE_2500BASEX:
184 		return lynx_pcs_config_giga(lynx->mdio, ifmode, advertising,
185 					    neg_mode);
186 	case PHY_INTERFACE_MODE_USXGMII:
187 	case PHY_INTERFACE_MODE_10G_QXGMII:
188 		return lynx_pcs_config_usxgmii(lynx->mdio, ifmode, advertising,
189 					       neg_mode);
190 	case PHY_INTERFACE_MODE_10GBASER:
191 		/* Nothing to do here for 10GBASER */
192 		break;
193 	default:
194 		return -EOPNOTSUPP;
195 	}
196 
197 	return 0;
198 }
199 
200 static void lynx_pcs_an_restart(struct phylink_pcs *pcs)
201 {
202 	struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
203 
204 	phylink_mii_c22_pcs_an_restart(lynx->mdio);
205 }
206 
207 static void lynx_pcs_link_up_sgmii(struct mdio_device *pcs,
208 				   unsigned int neg_mode,
209 				   int speed, int duplex)
210 {
211 	u16 if_mode = 0, sgmii_speed;
212 
213 	/* The PCS needs to be configured manually only
214 	 * when not operating on in-band mode
215 	 */
216 	if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
217 		return;
218 
219 	if (duplex == DUPLEX_HALF)
220 		if_mode |= IF_MODE_HALF_DUPLEX;
221 
222 	switch (speed) {
223 	case SPEED_1000:
224 		sgmii_speed = SGMII_SPEED_1000;
225 		break;
226 	case SPEED_100:
227 		sgmii_speed = SGMII_SPEED_100;
228 		break;
229 	case SPEED_10:
230 		sgmii_speed = SGMII_SPEED_10;
231 		break;
232 	case SPEED_UNKNOWN:
233 		/* Silently don't do anything */
234 		return;
235 	default:
236 		dev_err(&pcs->dev, "Invalid PCS speed %d\n", speed);
237 		return;
238 	}
239 	if_mode |= IF_MODE_SPEED(sgmii_speed);
240 
241 	mdiodev_modify(pcs, IF_MODE,
242 		       IF_MODE_HALF_DUPLEX | IF_MODE_SPEED_MSK,
243 		       if_mode);
244 }
245 
246 static void lynx_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
247 			     phy_interface_t interface,
248 			     int speed, int duplex)
249 {
250 	struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
251 
252 	switch (interface) {
253 	case PHY_INTERFACE_MODE_SGMII:
254 	case PHY_INTERFACE_MODE_QSGMII:
255 		lynx_pcs_link_up_sgmii(lynx->mdio, neg_mode, speed, duplex);
256 		break;
257 	case PHY_INTERFACE_MODE_USXGMII:
258 	case PHY_INTERFACE_MODE_10G_QXGMII:
259 		/* At the moment, only in-band AN is supported for USXGMII
260 		 * so nothing to do in link_up
261 		 */
262 		break;
263 	default:
264 		break;
265 	}
266 }
267 
268 static const struct phylink_pcs_ops lynx_pcs_phylink_ops = {
269 	.pcs_inband_caps = lynx_pcs_inband_caps,
270 	.pcs_get_state = lynx_pcs_get_state,
271 	.pcs_config = lynx_pcs_config,
272 	.pcs_an_restart = lynx_pcs_an_restart,
273 	.pcs_link_up = lynx_pcs_link_up,
274 };
275 
276 static const phy_interface_t lynx_interfaces[] = {
277 	PHY_INTERFACE_MODE_SGMII,
278 	PHY_INTERFACE_MODE_QSGMII,
279 	PHY_INTERFACE_MODE_1000BASEX,
280 	PHY_INTERFACE_MODE_2500BASEX,
281 	PHY_INTERFACE_MODE_10GBASER,
282 	PHY_INTERFACE_MODE_USXGMII,
283 	PHY_INTERFACE_MODE_10G_QXGMII,
284 };
285 
286 static struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio)
287 {
288 	struct lynx_pcs *lynx;
289 	int i;
290 
291 	lynx = kzalloc(sizeof(*lynx), GFP_KERNEL);
292 	if (!lynx)
293 		return ERR_PTR(-ENOMEM);
294 
295 	mdio_device_get(mdio);
296 	lynx->mdio = mdio;
297 	lynx->pcs.ops = &lynx_pcs_phylink_ops;
298 	lynx->pcs.poll = true;
299 
300 	for (i = 0; i < ARRAY_SIZE(lynx_interfaces); i++)
301 		__set_bit(lynx_interfaces[i], lynx->pcs.supported_interfaces);
302 
303 	return lynx_to_phylink_pcs(lynx);
304 }
305 
306 struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr)
307 {
308 	struct mdio_device *mdio;
309 	struct phylink_pcs *pcs;
310 
311 	mdio = mdio_device_create(bus, addr);
312 	if (IS_ERR(mdio))
313 		return ERR_CAST(mdio);
314 
315 	pcs = lynx_pcs_create(mdio);
316 
317 	/* lynx_create() has taken a refcount on the mdiodev if it was
318 	 * successful. If lynx_create() fails, this will free the mdio
319 	 * device here. In any case, we don't need to hold our reference
320 	 * anymore, and putting it here will allow mdio_device_put() in
321 	 * lynx_destroy() to automatically free the mdio device.
322 	 */
323 	mdio_device_put(mdio);
324 
325 	return pcs;
326 }
327 EXPORT_SYMBOL(lynx_pcs_create_mdiodev);
328 
329 /*
330  * lynx_pcs_create_fwnode() creates a lynx PCS instance from the fwnode
331  * device indicated by node.
332  *
333  * Returns:
334  *  -ENODEV if the fwnode is marked unavailable
335  *  -EPROBE_DEFER if we fail to find the device
336  *  -ENOMEM if we fail to allocate memory
337  *  pointer to a phylink_pcs on success
338  */
339 struct phylink_pcs *lynx_pcs_create_fwnode(struct fwnode_handle *node)
340 {
341 	struct mdio_device *mdio;
342 	struct phylink_pcs *pcs;
343 
344 	if (!fwnode_device_is_available(node))
345 		return ERR_PTR(-ENODEV);
346 
347 	mdio = fwnode_mdio_find_device(node);
348 	if (!mdio)
349 		return ERR_PTR(-EPROBE_DEFER);
350 
351 	pcs = lynx_pcs_create(mdio);
352 
353 	/* lynx_create() has taken a refcount on the mdiodev if it was
354 	 * successful. If lynx_create() fails, this will free the mdio
355 	 * device here. In any case, we don't need to hold our reference
356 	 * anymore, and putting it here will allow mdio_device_put() in
357 	 * lynx_destroy() to automatically free the mdio device.
358 	 */
359 	mdio_device_put(mdio);
360 
361 	return pcs;
362 }
363 EXPORT_SYMBOL_GPL(lynx_pcs_create_fwnode);
364 
365 void lynx_pcs_destroy(struct phylink_pcs *pcs)
366 {
367 	struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
368 
369 	mdio_device_put(lynx->mdio);
370 	kfree(lynx);
371 }
372 EXPORT_SYMBOL(lynx_pcs_destroy);
373 
374 MODULE_DESCRIPTION("NXP Lynx PCS phylink library");
375 MODULE_LICENSE("Dual BSD/GPL");
376