GNU Linux-libre 6.8.7-gnu
[releases.git] / drivers / net / pcs / pcs-lynx.c
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 void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs,
39                                        struct phylink_link_state *state)
40 {
41         struct mii_bus *bus = pcs->bus;
42         int addr = pcs->addr;
43         int status, lpa;
44
45         status = mdiobus_c45_read(bus, addr, MDIO_MMD_VEND2, MII_BMSR);
46         if (status < 0)
47                 return;
48
49         state->link = !!(status & MDIO_STAT1_LSTATUS);
50         state->an_complete = !!(status & MDIO_AN_STAT1_COMPLETE);
51         if (!state->link || !state->an_complete)
52                 return;
53
54         lpa = mdiobus_c45_read(bus, addr, MDIO_MMD_VEND2, MII_LPA);
55         if (lpa < 0)
56                 return;
57
58         phylink_decode_usxgmii_word(state, lpa);
59 }
60
61 static void lynx_pcs_get_state_2500basex(struct mdio_device *pcs,
62                                          struct phylink_link_state *state)
63 {
64         int bmsr, lpa;
65
66         bmsr = mdiodev_read(pcs, MII_BMSR);
67         lpa = mdiodev_read(pcs, MII_LPA);
68         if (bmsr < 0 || lpa < 0) {
69                 state->link = false;
70                 return;
71         }
72
73         state->link = !!(bmsr & BMSR_LSTATUS);
74         state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE);
75         if (!state->link)
76                 return;
77
78         state->speed = SPEED_2500;
79         state->pause |= MLO_PAUSE_TX | MLO_PAUSE_RX;
80         state->duplex = DUPLEX_FULL;
81 }
82
83 static void lynx_pcs_get_state(struct phylink_pcs *pcs,
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_SGMII:
91         case PHY_INTERFACE_MODE_QSGMII:
92                 phylink_mii_c22_pcs_get_state(lynx->mdio, state);
93                 break;
94         case PHY_INTERFACE_MODE_2500BASEX:
95                 lynx_pcs_get_state_2500basex(lynx->mdio, state);
96                 break;
97         case PHY_INTERFACE_MODE_USXGMII:
98                 lynx_pcs_get_state_usxgmii(lynx->mdio, state);
99                 break;
100         case PHY_INTERFACE_MODE_10GBASER:
101                 phylink_mii_c45_pcs_get_state(lynx->mdio, state);
102                 break;
103         default:
104                 break;
105         }
106
107         dev_dbg(&lynx->mdio->dev,
108                 "mode=%s/%s/%s link=%u an_complete=%u\n",
109                 phy_modes(state->interface),
110                 phy_speed_to_str(state->speed),
111                 phy_duplex_to_str(state->duplex),
112                 state->link, state->an_complete);
113 }
114
115 static int lynx_pcs_config_giga(struct mdio_device *pcs,
116                                 phy_interface_t interface,
117                                 const unsigned long *advertising,
118                                 unsigned int neg_mode)
119 {
120         int link_timer_ns;
121         u32 link_timer;
122         u16 if_mode;
123         int err;
124
125         link_timer_ns = phylink_get_link_timer_ns(interface);
126         if (link_timer_ns > 0) {
127                 link_timer = LINK_TIMER_VAL(link_timer_ns);
128
129                 mdiodev_write(pcs, LINK_TIMER_LO, link_timer & 0xffff);
130                 mdiodev_write(pcs, LINK_TIMER_HI, link_timer >> 16);
131         }
132
133         if (interface == PHY_INTERFACE_MODE_1000BASEX) {
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                                    const unsigned long *advertising,
154                                    unsigned int neg_mode)
155 {
156         struct mii_bus *bus = pcs->bus;
157         int addr = pcs->addr;
158
159         if (neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED) {
160                 dev_err(&pcs->dev, "USXGMII only supports in-band AN for now\n");
161                 return -EOPNOTSUPP;
162         }
163
164         /* Configure device ability for the USXGMII Replicator */
165         return mdiobus_c45_write(bus, addr, MDIO_MMD_VEND2, MII_ADVERTISE,
166                                  MDIO_USXGMII_10G | MDIO_USXGMII_LINK |
167                                  MDIO_USXGMII_FULL_DUPLEX |
168                                  ADVERTISE_SGMII | ADVERTISE_LPACK);
169 }
170
171 static int lynx_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
172                            phy_interface_t ifmode,
173                            const unsigned long *advertising, bool permit)
174 {
175         struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
176
177         switch (ifmode) {
178         case PHY_INTERFACE_MODE_1000BASEX:
179         case PHY_INTERFACE_MODE_SGMII:
180         case PHY_INTERFACE_MODE_QSGMII:
181                 return lynx_pcs_config_giga(lynx->mdio, ifmode, advertising,
182                                             neg_mode);
183         case PHY_INTERFACE_MODE_2500BASEX:
184                 if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
185                         dev_err(&lynx->mdio->dev,
186                                 "AN not supported on 3.125GHz SerDes lane\n");
187                         return -EOPNOTSUPP;
188                 }
189                 break;
190         case PHY_INTERFACE_MODE_USXGMII:
191                 return lynx_pcs_config_usxgmii(lynx->mdio, advertising,
192                                                neg_mode);
193         case PHY_INTERFACE_MODE_10GBASER:
194                 /* Nothing to do here for 10GBASER */
195                 break;
196         default:
197                 return -EOPNOTSUPP;
198         }
199
200         return 0;
201 }
202
203 static void lynx_pcs_an_restart(struct phylink_pcs *pcs)
204 {
205         struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
206
207         phylink_mii_c22_pcs_an_restart(lynx->mdio);
208 }
209
210 static void lynx_pcs_link_up_sgmii(struct mdio_device *pcs,
211                                    unsigned int neg_mode,
212                                    int speed, int duplex)
213 {
214         u16 if_mode = 0, sgmii_speed;
215
216         /* The PCS needs to be configured manually only
217          * when not operating on in-band mode
218          */
219         if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
220                 return;
221
222         if (duplex == DUPLEX_HALF)
223                 if_mode |= IF_MODE_HALF_DUPLEX;
224
225         switch (speed) {
226         case SPEED_1000:
227                 sgmii_speed = SGMII_SPEED_1000;
228                 break;
229         case SPEED_100:
230                 sgmii_speed = SGMII_SPEED_100;
231                 break;
232         case SPEED_10:
233                 sgmii_speed = SGMII_SPEED_10;
234                 break;
235         case SPEED_UNKNOWN:
236                 /* Silently don't do anything */
237                 return;
238         default:
239                 dev_err(&pcs->dev, "Invalid PCS speed %d\n", speed);
240                 return;
241         }
242         if_mode |= IF_MODE_SPEED(sgmii_speed);
243
244         mdiodev_modify(pcs, IF_MODE,
245                        IF_MODE_HALF_DUPLEX | IF_MODE_SPEED_MSK,
246                        if_mode);
247 }
248
249 /* 2500Base-X is SerDes protocol 7 on Felix and 6 on ENETC. It is a SerDes lane
250  * clocked at 3.125 GHz which encodes symbols with 8b/10b and does not have
251  * auto-negotiation of any link parameters. Electrically it is compatible with
252  * a single lane of XAUI.
253  * The hardware reference manual wants to call this mode SGMII, but it isn't
254  * really, since the fundamental features of SGMII:
255  * - Downgrading the link speed by duplicating symbols
256  * - Auto-negotiation
257  * are not there.
258  * The speed is configured at 1000 in the IF_MODE because the clock frequency
259  * is actually given by a PLL configured in the Reset Configuration Word (RCW).
260  * Since there is no difference between fixed speed SGMII w/o AN and 802.3z w/o
261  * AN, we call this PHY interface type 2500Base-X. In case a PHY negotiates a
262  * lower link speed on line side, the system-side interface remains fixed at
263  * 2500 Mbps and we do rate adaptation through pause frames.
264  */
265 static void lynx_pcs_link_up_2500basex(struct mdio_device *pcs,
266                                        unsigned int neg_mode,
267                                        int speed, int duplex)
268 {
269         u16 if_mode = 0;
270
271         if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
272                 dev_err(&pcs->dev, "AN not supported for 2500BaseX\n");
273                 return;
274         }
275
276         if (duplex == DUPLEX_HALF)
277                 if_mode |= IF_MODE_HALF_DUPLEX;
278         if_mode |= IF_MODE_SPEED(SGMII_SPEED_2500);
279
280         mdiodev_modify(pcs, IF_MODE,
281                        IF_MODE_HALF_DUPLEX | IF_MODE_SPEED_MSK,
282                        if_mode);
283 }
284
285 static void lynx_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
286                              phy_interface_t interface,
287                              int speed, int duplex)
288 {
289         struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
290
291         switch (interface) {
292         case PHY_INTERFACE_MODE_SGMII:
293         case PHY_INTERFACE_MODE_QSGMII:
294                 lynx_pcs_link_up_sgmii(lynx->mdio, neg_mode, speed, duplex);
295                 break;
296         case PHY_INTERFACE_MODE_2500BASEX:
297                 lynx_pcs_link_up_2500basex(lynx->mdio, neg_mode, speed, duplex);
298                 break;
299         case PHY_INTERFACE_MODE_USXGMII:
300                 /* At the moment, only in-band AN is supported for USXGMII
301                  * so nothing to do in link_up
302                  */
303                 break;
304         default:
305                 break;
306         }
307 }
308
309 static const struct phylink_pcs_ops lynx_pcs_phylink_ops = {
310         .pcs_get_state = lynx_pcs_get_state,
311         .pcs_config = lynx_pcs_config,
312         .pcs_an_restart = lynx_pcs_an_restart,
313         .pcs_link_up = lynx_pcs_link_up,
314 };
315
316 static struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio)
317 {
318         struct lynx_pcs *lynx;
319
320         lynx = kzalloc(sizeof(*lynx), GFP_KERNEL);
321         if (!lynx)
322                 return ERR_PTR(-ENOMEM);
323
324         mdio_device_get(mdio);
325         lynx->mdio = mdio;
326         lynx->pcs.ops = &lynx_pcs_phylink_ops;
327         lynx->pcs.neg_mode = true;
328         lynx->pcs.poll = true;
329
330         return lynx_to_phylink_pcs(lynx);
331 }
332
333 struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr)
334 {
335         struct mdio_device *mdio;
336         struct phylink_pcs *pcs;
337
338         mdio = mdio_device_create(bus, addr);
339         if (IS_ERR(mdio))
340                 return ERR_CAST(mdio);
341
342         pcs = lynx_pcs_create(mdio);
343
344         /* lynx_create() has taken a refcount on the mdiodev if it was
345          * successful. If lynx_create() fails, this will free the mdio
346          * device here. In any case, we don't need to hold our reference
347          * anymore, and putting it here will allow mdio_device_put() in
348          * lynx_destroy() to automatically free the mdio device.
349          */
350         mdio_device_put(mdio);
351
352         return pcs;
353 }
354 EXPORT_SYMBOL(lynx_pcs_create_mdiodev);
355
356 /*
357  * lynx_pcs_create_fwnode() creates a lynx PCS instance from the fwnode
358  * device indicated by node.
359  *
360  * Returns:
361  *  -ENODEV if the fwnode is marked unavailable
362  *  -EPROBE_DEFER if we fail to find the device
363  *  -ENOMEM if we fail to allocate memory
364  *  pointer to a phylink_pcs on success
365  */
366 struct phylink_pcs *lynx_pcs_create_fwnode(struct fwnode_handle *node)
367 {
368         struct mdio_device *mdio;
369         struct phylink_pcs *pcs;
370
371         if (!fwnode_device_is_available(node))
372                 return ERR_PTR(-ENODEV);
373
374         mdio = fwnode_mdio_find_device(node);
375         if (!mdio)
376                 return ERR_PTR(-EPROBE_DEFER);
377
378         pcs = lynx_pcs_create(mdio);
379
380         /* lynx_create() has taken a refcount on the mdiodev if it was
381          * successful. If lynx_create() fails, this will free the mdio
382          * device here. In any case, we don't need to hold our reference
383          * anymore, and putting it here will allow mdio_device_put() in
384          * lynx_destroy() to automatically free the mdio device.
385          */
386         mdio_device_put(mdio);
387
388         return pcs;
389 }
390 EXPORT_SYMBOL_GPL(lynx_pcs_create_fwnode);
391
392 void lynx_pcs_destroy(struct phylink_pcs *pcs)
393 {
394         struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
395
396         mdio_device_put(lynx->mdio);
397         kfree(lynx);
398 }
399 EXPORT_SYMBOL(lynx_pcs_destroy);
400
401 MODULE_LICENSE("Dual BSD/GPL");