ath79/mikrotik: use routerbootpart partitions
[oweals/openwrt.git] / target / linux / layerscape / patches-5.4 / 701-net-0283-net-dsa-felix-Add-PCS-operations-for-PHYLINK.patch
1 From 0e219a6aa07754d81a25c9e4408d81d194cd2000 Mon Sep 17 00:00:00 2001
2 From: Vladimir Oltean <vladimir.oltean@nxp.com>
3 Date: Fri, 22 Nov 2019 13:45:52 +0200
4 Subject: [PATCH] net: dsa: felix: Add PCS operations for PHYLINK
5
6 This removes the bootloader dependency for SGMII PCS pre-configuration,
7 as well as adds support for monitoring the in-band SGMII AN between the
8 PCS and the system-side link partner (PHY or other MAC).
9
10 Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
11 ---
12  drivers/net/dsa/ocelot/felix.c         |  23 ++-
13  drivers/net/dsa/ocelot/felix.h         |   7 +-
14  drivers/net/dsa/ocelot/felix_vsc9959.c | 292 ++++++++++++++++++++++++++++++++-
15  3 files changed, 314 insertions(+), 8 deletions(-)
16
17 --- a/drivers/net/dsa/ocelot/felix.c
18 +++ b/drivers/net/dsa/ocelot/felix.c
19 @@ -265,7 +265,7 @@ static int felix_get_ts_info(struct dsa_
20  static int felix_init_structs(struct felix *felix, int num_phys_ports)
21  {
22         struct ocelot *ocelot = &felix->ocelot;
23 -       resource_size_t base;
24 +       resource_size_t switch_base;
25         int port, i, err;
26  
27         ocelot->num_phys_ports = num_phys_ports;
28 @@ -281,7 +281,8 @@ static int felix_init_structs(struct fel
29         ocelot->ops             = felix->info->ops;
30         ocelot->quirks          = felix->info->quirks;
31  
32 -       base = pci_resource_start(felix->pdev, felix->info->pci_bar);
33 +       switch_base = pci_resource_start(felix->pdev,
34 +                                        felix->info->switch_pci_bar);
35  
36         for (i = 0; i < TARGET_MAX; i++) {
37                 struct regmap *target;
38 @@ -292,8 +293,8 @@ static int felix_init_structs(struct fel
39  
40                 res = &felix->info->target_io_res[i];
41                 res->flags = IORESOURCE_MEM;
42 -               res->start += base;
43 -               res->end += base;
44 +               res->start += switch_base;
45 +               res->end += switch_base;
46  
47                 target = ocelot_regmap_init(ocelot, res);
48                 if (IS_ERR(target)) {
49 @@ -327,8 +328,8 @@ static int felix_init_structs(struct fel
50  
51                 res = &felix->info->port_io_res[port];
52                 res->flags = IORESOURCE_MEM;
53 -               res->start += base;
54 -               res->end += base;
55 +               res->start += switch_base;
56 +               res->end += switch_base;
57  
58                 port_regs = devm_ioremap_resource(ocelot->dev, res);
59                 if (IS_ERR(port_regs)) {
60 @@ -342,6 +343,12 @@ static int felix_init_structs(struct fel
61                 ocelot->ports[port] = ocelot_port;
62         }
63  
64 +       if (felix->info->mdio_bus_alloc) {
65 +               err = felix->info->mdio_bus_alloc(ocelot);
66 +               if (err < 0)
67 +                       return err;
68 +       }
69 +
70         return 0;
71  }
72  
73 @@ -377,6 +384,10 @@ static int felix_setup(struct dsa_switch
74  static void felix_teardown(struct dsa_switch *ds)
75  {
76         struct ocelot *ocelot = ds->priv;
77 +       struct felix *felix = ocelot_to_felix(ocelot);
78 +
79 +       if (felix->imdio)
80 +               mdiobus_unregister(felix->imdio);
81  
82         /* stop workqueue thread */
83         ocelot_deinit(ocelot);
84 --- a/drivers/net/dsa/ocelot/felix.h
85 +++ b/drivers/net/dsa/ocelot/felix.h
86 @@ -10,6 +10,7 @@
87  struct felix_info {
88         struct resource                 *target_io_res;
89         struct resource                 *port_io_res;
90 +       struct resource                 *imdio_res;
91         const struct reg_field          *regfields;
92         const u32 *const                *map;
93         const struct ocelot_ops         *ops;
94 @@ -17,8 +18,10 @@ struct felix_info {
95         const struct ocelot_stat_layout *stats_layout;
96         unsigned int                    num_stats;
97         int                             num_ports;
98 -       int                             pci_bar;
99 +       int                             switch_pci_bar;
100 +       int                             imdio_pci_bar;
101         unsigned long                   quirks;
102 +       int (*mdio_bus_alloc)(struct ocelot *ocelot);
103  };
104  
105  extern struct felix_info               felix_info_vsc9959;
106 @@ -33,6 +36,8 @@ struct felix {
107         struct pci_dev                  *pdev;
108         struct felix_info               *info;
109         struct ocelot                   ocelot;
110 +       struct mii_bus                  *imdio;
111 +       struct phy_device               **pcs;
112  };
113  
114  #endif
115 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c
116 +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
117 @@ -2,6 +2,7 @@
118  /* Copyright 2017 Microsemi Corporation
119   * Copyright 2018-2019 NXP Semiconductors
120   */
121 +#include <linux/fsl/enetc_mdio.h>
122  #include <soc/mscc/ocelot_sys.h>
123  #include <soc/mscc/ocelot.h>
124  #include <linux/iopoll.h>
125 @@ -390,6 +391,15 @@ static struct resource vsc9959_port_io_r
126         },
127  };
128  
129 +/* Port MAC 0 Internal MDIO bus through which the SerDes acting as an
130 + * SGMII/QSGMII MAC PCS can be found.
131 + */
132 +static struct resource vsc9959_imdio_res = {
133 +       .start          = 0x8030,
134 +       .end            = 0x8040,
135 +       .name           = "imdio",
136 +};
137 +
138  static const struct reg_field vsc9959_regfields[] = {
139         [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6),
140         [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 5),
141 @@ -569,13 +579,291 @@ static int vsc9959_reset(struct ocelot *
142         return 0;
143  }
144  
145 +void vsc9959_pcs_validate(struct ocelot *ocelot, int port,
146 +                         unsigned long *supported,
147 +                         struct phylink_link_state *state)
148 +{
149 +       __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
150 +
151 +       if (state->interface != PHY_INTERFACE_MODE_NA &&
152 +           state->interface != PHY_INTERFACE_MODE_GMII &&
153 +           state->interface != PHY_INTERFACE_MODE_SGMII &&
154 +           state->interface != PHY_INTERFACE_MODE_QSGMII &&
155 +           state->interface != PHY_INTERFACE_MODE_USXGMII) {
156 +               bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
157 +               return;
158 +       }
159 +
160 +       /* No half-duplex. */
161 +       phylink_set_port_modes(mask);
162 +       phylink_set(mask, Autoneg);
163 +       phylink_set(mask, Pause);
164 +       phylink_set(mask, Asym_Pause);
165 +       phylink_set(mask, 10baseT_Full);
166 +       phylink_set(mask, 100baseT_Full);
167 +       phylink_set(mask, 1000baseT_Full);
168 +       phylink_set(mask, 1000baseX_Full);
169 +       phylink_set(mask, 2500baseT_Full);
170 +       phylink_set(mask, 2500baseX_Full);
171 +       phylink_set(mask, 1000baseKX_Full);
172 +
173 +       bitmap_and(supported, supported, mask,
174 +                  __ETHTOOL_LINK_MODE_MASK_NBITS);
175 +       bitmap_and(state->advertising, state->advertising, mask,
176 +                  __ETHTOOL_LINK_MODE_MASK_NBITS);
177 +}
178 +
179 +static void vsc9959_pcs_an_restart(struct ocelot *ocelot, int port)
180 +{
181 +       struct felix *felix = ocelot_to_felix(ocelot);
182 +       struct phy_device *pcs = felix->pcs[port];
183 +
184 +       if (!pcs)
185 +               return;
186 +
187 +       phy_set_bits(pcs, MII_BMCR, BMCR_ANRESTART);
188 +}
189 +
190 +static void vsc9959_pcs_init_sgmii(struct phy_device *pcs,
191 +                                  unsigned int link_an_mode,
192 +                                  const struct phylink_link_state *state)
193 +{
194 +       /* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001
195 +        * for the MAC PCS in order to acknowledge the AN.
196 +        */
197 +       phy_write(pcs, MII_ADVERTISE, ADVERTISE_SGMII | ADVERTISE_LPACK);
198 +
199 +       /* Set to SGMII mode, use AN */
200 +       phy_write(pcs, ENETC_PCS_IF_MODE, ENETC_PCS_IF_MODE_SGMII_AN);
201 +
202 +       /* Adjust link timer for SGMII */
203 +       phy_write(pcs, ENETC_PCS_LINK_TIMER1, ENETC_PCS_LINK_TIMER1_VAL);
204 +       phy_write(pcs, ENETC_PCS_LINK_TIMER2, ENETC_PCS_LINK_TIMER2_VAL);
205 +
206 +       phy_write(pcs, MII_BMCR, BMCR_SPEED1000 |
207 +                                BMCR_FULLDPLX |
208 +                                BMCR_ANENABLE);
209 +}
210 +
211 +#define ADVERTISE_USXGMII_FDX          BIT(12)
212 +
213 +static void vsc9959_pcs_init_sxgmii(struct phy_device *pcs,
214 +                                   unsigned int link_an_mode,
215 +                                   const struct phylink_link_state *state)
216 +{
217 +       /* Configure device ability for the USXGMII Replicator */
218 +       phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_ADVERTISE,
219 +                     ADVERTISE_SGMII |
220 +                     ADVERTISE_LPACK |
221 +                     ADVERTISE_USXGMII_FDX);
222 +}
223 +
224 +static void vsc9959_pcs_init(struct ocelot *ocelot, int port,
225 +                            unsigned int link_an_mode,
226 +                            const struct phylink_link_state *state)
227 +{
228 +       struct felix *felix = ocelot_to_felix(ocelot);
229 +       struct phy_device *pcs = felix->pcs[port];
230 +
231 +       if (!pcs)
232 +               return;
233 +
234 +       if (link_an_mode == MLO_AN_FIXED) {
235 +               phydev_err(pcs, "Fixed modes are not yet supported.\n");
236 +               return;
237 +       }
238 +
239 +       pcs->interface = state->interface;
240 +       if (pcs->interface == PHY_INTERFACE_MODE_USXGMII)
241 +               pcs->is_c45 = true;
242 +       else
243 +               pcs->is_c45 = false;
244 +
245 +       /* The PCS does not implement the BMSR register fully, so capability
246 +        * detection via genphy_read_abilities does not work. Since we can get
247 +        * the PHY config word from the LPA register though, there is still
248 +        * value in using the generic phy_resolve_aneg_linkmode function. So
249 +        * populate the supported and advertising link modes manually here.
250 +        */
251 +       linkmode_set_bit_array(phy_basic_ports_array,
252 +                              ARRAY_SIZE(phy_basic_ports_array),
253 +                              pcs->supported);
254 +       linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, pcs->supported);
255 +       linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, pcs->supported);
256 +       linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pcs->supported);
257 +       linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, pcs->supported);
258 +       phy_advertise_supported(pcs);
259 +
260 +       switch (pcs->interface) {
261 +       case PHY_INTERFACE_MODE_SGMII:
262 +       case PHY_INTERFACE_MODE_QSGMII:
263 +               vsc9959_pcs_init_sgmii(pcs, link_an_mode, state);
264 +               break;
265 +       case PHY_INTERFACE_MODE_USXGMII:
266 +               vsc9959_pcs_init_sxgmii(pcs, link_an_mode, state);
267 +               break;
268 +       default:
269 +               dev_err(ocelot->dev, "Unsupported link mode %s\n",
270 +                       phy_modes(pcs->interface));
271 +       }
272 +}
273 +
274 +static void vsc9959_pcs_link_state(struct ocelot *ocelot, int port,
275 +                                  struct phylink_link_state *state)
276 +{
277 +       struct felix *felix = ocelot_to_felix(ocelot);
278 +       struct phy_device *pcs = felix->pcs[port];
279 +       int err;
280 +
281 +       if (!pcs)
282 +               return;
283 +
284 +       /* Reading PCS status not yet supported for USXGMII */
285 +       if (pcs->is_c45) {
286 +               state->link = 1;
287 +               return;
288 +       }
289 +
290 +       pcs->speed = SPEED_UNKNOWN;
291 +       pcs->duplex = DUPLEX_UNKNOWN;
292 +       pcs->pause = 0;
293 +       pcs->asym_pause = 0;
294 +
295 +       err = genphy_update_link(pcs);
296 +       if (err < 0)
297 +               return;
298 +
299 +       if (pcs->autoneg_complete) {
300 +               u16 lpa = phy_read(pcs, MII_LPA);
301 +
302 +               switch (state->interface) {
303 +               case PHY_INTERFACE_MODE_SGMII:
304 +               case PHY_INTERFACE_MODE_QSGMII:
305 +                       mii_lpa_to_linkmode_lpa_sgmii(pcs->lp_advertising, lpa);
306 +                       break;
307 +               default:
308 +                       return;
309 +               }
310 +
311 +               phy_resolve_aneg_linkmode(pcs);
312 +       }
313 +
314 +       state->an_complete = pcs->autoneg_complete;
315 +       state->an_enabled = pcs->autoneg;
316 +       state->link = pcs->link;
317 +       state->duplex = pcs->duplex;
318 +       state->speed = pcs->speed;
319 +       /* SGMII AN does not negotiate flow control, but that's ok,
320 +        * since phylink already knows that, and does:
321 +        *      link_state.pause |= pl->phy_state.pause;
322 +        */
323 +       state->pause = pcs->pause;
324 +
325 +       dev_dbg(ocelot->dev,
326 +               "%s: mode=%s/%s/%s adv=%*pb lpa=%*pb link=%u an_enabled=%u an_complete=%u\n",
327 +               __func__,
328 +               phy_modes(state->interface),
329 +               phy_speed_to_str(state->speed),
330 +               phy_duplex_to_str(state->duplex),
331 +               __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising,
332 +               __ETHTOOL_LINK_MODE_MASK_NBITS, state->lp_advertising,
333 +               state->link, state->an_enabled, state->an_complete);
334 +}
335 +
336  static const struct ocelot_ops vsc9959_ops = {
337         .reset                  = vsc9959_reset,
338 +       .pcs_init               = vsc9959_pcs_init,
339 +       .pcs_an_restart         = vsc9959_pcs_an_restart,
340 +       .pcs_link_state         = vsc9959_pcs_link_state,
341 +       .pcs_validate           = vsc9959_pcs_validate,
342  };
343  
344 +static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
345 +{
346 +       struct felix *felix = ocelot_to_felix(ocelot);
347 +       struct enetc_mdio_priv *mdio_priv;
348 +       struct device *dev = ocelot->dev;
349 +       resource_size_t imdio_base;
350 +       void __iomem *imdio_regs;
351 +       struct resource *res;
352 +       struct enetc_hw *hw;
353 +       struct mii_bus *bus;
354 +       int port;
355 +       int rc;
356 +
357 +       felix->pcs = devm_kcalloc(dev, felix->info->num_ports,
358 +                                 sizeof(struct phy_device),
359 +                                 GFP_KERNEL);
360 +       if (!felix->pcs) {
361 +               dev_err(dev, "failed to allocate array for PCS PHYs\n");
362 +               return -ENOMEM;
363 +       }
364 +
365 +       imdio_base = pci_resource_start(felix->pdev,
366 +                                       felix->info->imdio_pci_bar);
367 +
368 +       res = felix->info->imdio_res;
369 +       res->flags = IORESOURCE_MEM;
370 +       res->start += imdio_base;
371 +       res->end += imdio_base;
372 +
373 +       imdio_regs = devm_ioremap_resource(dev, res);
374 +       if (IS_ERR(imdio_regs)) {
375 +               dev_err(dev, "failed to map internal MDIO registers\n");
376 +               return PTR_ERR(imdio_regs);
377 +       }
378 +
379 +       hw = enetc_hw_alloc(dev, imdio_regs);
380 +       if (IS_ERR(hw)) {
381 +               dev_err(dev, "failed to allocate ENETC HW structure\n");
382 +               return PTR_ERR(hw);
383 +       }
384 +
385 +       bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
386 +       if (!bus)
387 +               return -ENOMEM;
388 +
389 +       bus->name = "VSC9959 internal MDIO bus";
390 +       bus->read = enetc_mdio_read;
391 +       bus->write = enetc_mdio_write;
392 +       bus->parent = dev;
393 +       mdio_priv = bus->priv;
394 +       mdio_priv->hw = hw;
395 +       /* This gets added to imdio_regs, which already maps addresses
396 +        * starting with the proper offset.
397 +        */
398 +       mdio_priv->mdio_base = 0;
399 +       snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
400 +
401 +       /* Needed in order to initialize the bus mutex lock */
402 +       rc = mdiobus_register(bus);
403 +       if (rc < 0) {
404 +               dev_err(dev, "failed to register MDIO bus\n");
405 +               return rc;
406 +       }
407 +
408 +       felix->imdio = bus;
409 +
410 +       for (port = 0; port < felix->info->num_ports; port++) {
411 +               struct phy_device *pcs;
412 +               bool is_c45 = false;
413 +
414 +               pcs = get_phy_device(felix->imdio, port, is_c45);
415 +               if (IS_ERR(pcs))
416 +                       continue;
417 +
418 +               felix->pcs[port] = pcs;
419 +
420 +               dev_info(dev, "Found PCS at internal MDIO address %d\n", port);
421 +       }
422 +
423 +       return 0;
424 +}
425 +
426  struct felix_info felix_info_vsc9959 = {
427         .target_io_res          = vsc9959_target_io_res,
428         .port_io_res            = vsc9959_port_io_res,
429 +       .imdio_res              = &vsc9959_imdio_res,
430         .regfields              = vsc9959_regfields,
431         .map                    = vsc9959_regmap,
432         .ops                    = &vsc9959_ops,
433 @@ -583,6 +871,8 @@ struct felix_info felix_info_vsc9959 = {
434         .num_stats              = ARRAY_SIZE(vsc9959_stats_layout),
435         .shared_queue_sz        = 128 * 1024,
436         .num_ports              = 6,
437 -       .pci_bar                = 4,
438 +       .switch_pci_bar         = 4,
439 +       .imdio_pci_bar          = 0,
440         .quirks                 = OCELOT_PCS_PERFORMS_RATE_ADAPTATION,
441 +       .mdio_bus_alloc         = vsc9959_mdio_bus_alloc,
442  };