1e5b732a2SRussell King (Oracle) // SPDX-License-Identifier: GPL-2.0-or-later
2e5b732a2SRussell King (Oracle) /*
3e5b732a2SRussell King (Oracle) * Marvell 88E6352 family SERDES PCS support
4e5b732a2SRussell King (Oracle) *
5e5b732a2SRussell King (Oracle) * Copyright (c) 2008 Marvell Semiconductor
6e5b732a2SRussell King (Oracle) *
7e5b732a2SRussell King (Oracle) * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
8e5b732a2SRussell King (Oracle) */
9e5b732a2SRussell King (Oracle) #include <linux/interrupt.h>
10e5b732a2SRussell King (Oracle) #include <linux/irqdomain.h>
11e5b732a2SRussell King (Oracle) #include <linux/mii.h>
12e5b732a2SRussell King (Oracle)
13e5b732a2SRussell King (Oracle) #include "chip.h"
14e5b732a2SRussell King (Oracle) #include "global2.h"
15e5b732a2SRussell King (Oracle) #include "phy.h"
16e5b732a2SRussell King (Oracle) #include "port.h"
17e5b732a2SRussell King (Oracle) #include "serdes.h"
18e5b732a2SRussell King (Oracle)
19e5b732a2SRussell King (Oracle) struct mv88e639x_pcs {
20e5b732a2SRussell King (Oracle) struct mdio_device mdio;
21e5b732a2SRussell King (Oracle) struct phylink_pcs sgmii_pcs;
22e5b732a2SRussell King (Oracle) struct phylink_pcs xg_pcs;
23745d7e38SAnte Knezic bool erratum_3_14;
24e5b732a2SRussell King (Oracle) bool supports_5g;
25e5b732a2SRussell King (Oracle) phy_interface_t interface;
26e5b732a2SRussell King (Oracle) unsigned int irq;
27e5b732a2SRussell King (Oracle) char name[64];
28e5b732a2SRussell King (Oracle) irqreturn_t (*handle_irq)(struct mv88e639x_pcs *mpcs);
29e5b732a2SRussell King (Oracle) };
30e5b732a2SRussell King (Oracle)
mv88e639x_read(struct mv88e639x_pcs * mpcs,u16 regnum,u16 * val)31e5b732a2SRussell King (Oracle) static int mv88e639x_read(struct mv88e639x_pcs *mpcs, u16 regnum, u16 *val)
32e5b732a2SRussell King (Oracle) {
33e5b732a2SRussell King (Oracle) int err;
34e5b732a2SRussell King (Oracle)
35e5b732a2SRussell King (Oracle) err = mdiodev_c45_read(&mpcs->mdio, MDIO_MMD_PHYXS, regnum);
36e5b732a2SRussell King (Oracle) if (err < 0)
37e5b732a2SRussell King (Oracle) return err;
38e5b732a2SRussell King (Oracle)
39e5b732a2SRussell King (Oracle) *val = err;
40e5b732a2SRussell King (Oracle)
41e5b732a2SRussell King (Oracle) return 0;
42e5b732a2SRussell King (Oracle) }
43e5b732a2SRussell King (Oracle)
mv88e639x_write(struct mv88e639x_pcs * mpcs,u16 regnum,u16 val)44e5b732a2SRussell King (Oracle) static int mv88e639x_write(struct mv88e639x_pcs *mpcs, u16 regnum, u16 val)
45e5b732a2SRussell King (Oracle) {
46e5b732a2SRussell King (Oracle) return mdiodev_c45_write(&mpcs->mdio, MDIO_MMD_PHYXS, regnum, val);
47e5b732a2SRussell King (Oracle) }
48e5b732a2SRussell King (Oracle)
mv88e639x_modify(struct mv88e639x_pcs * mpcs,u16 regnum,u16 mask,u16 val)49e5b732a2SRussell King (Oracle) static int mv88e639x_modify(struct mv88e639x_pcs *mpcs, u16 regnum, u16 mask,
50e5b732a2SRussell King (Oracle) u16 val)
51e5b732a2SRussell King (Oracle) {
52e5b732a2SRussell King (Oracle) return mdiodev_c45_modify(&mpcs->mdio, MDIO_MMD_PHYXS, regnum, mask,
53e5b732a2SRussell King (Oracle) val);
54e5b732a2SRussell King (Oracle) }
55e5b732a2SRussell King (Oracle)
mv88e639x_modify_changed(struct mv88e639x_pcs * mpcs,u16 regnum,u16 mask,u16 set)56e5b732a2SRussell King (Oracle) static int mv88e639x_modify_changed(struct mv88e639x_pcs *mpcs, u16 regnum,
57e5b732a2SRussell King (Oracle) u16 mask, u16 set)
58e5b732a2SRussell King (Oracle) {
59e5b732a2SRussell King (Oracle) return mdiodev_c45_modify_changed(&mpcs->mdio, MDIO_MMD_PHYXS, regnum,
60e5b732a2SRussell King (Oracle) mask, set);
61e5b732a2SRussell King (Oracle) }
62e5b732a2SRussell King (Oracle)
63e5b732a2SRussell King (Oracle) static struct mv88e639x_pcs *
mv88e639x_pcs_alloc(struct device * dev,struct mii_bus * bus,unsigned int addr,int port)64e5b732a2SRussell King (Oracle) mv88e639x_pcs_alloc(struct device *dev, struct mii_bus *bus, unsigned int addr,
65e5b732a2SRussell King (Oracle) int port)
66e5b732a2SRussell King (Oracle) {
67e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs;
68e5b732a2SRussell King (Oracle)
69e5b732a2SRussell King (Oracle) mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL);
70e5b732a2SRussell King (Oracle) if (!mpcs)
71e5b732a2SRussell King (Oracle) return NULL;
72e5b732a2SRussell King (Oracle)
73e5b732a2SRussell King (Oracle) mpcs->mdio.dev.parent = dev;
74e5b732a2SRussell King (Oracle) mpcs->mdio.bus = bus;
75e5b732a2SRussell King (Oracle) mpcs->mdio.addr = addr;
76e5b732a2SRussell King (Oracle)
77e5b732a2SRussell King (Oracle) snprintf(mpcs->name, sizeof(mpcs->name),
78e5b732a2SRussell King (Oracle) "mv88e6xxx-%s-serdes-%d", dev_name(dev), port);
79e5b732a2SRussell King (Oracle)
80e5b732a2SRussell King (Oracle) return mpcs;
81e5b732a2SRussell King (Oracle) }
82e5b732a2SRussell King (Oracle)
mv88e639x_pcs_handle_irq(int irq,void * dev_id)83e5b732a2SRussell King (Oracle) static irqreturn_t mv88e639x_pcs_handle_irq(int irq, void *dev_id)
84e5b732a2SRussell King (Oracle) {
85e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = dev_id;
86e5b732a2SRussell King (Oracle) irqreturn_t (*handler)(struct mv88e639x_pcs *);
87e5b732a2SRussell King (Oracle)
88e5b732a2SRussell King (Oracle) handler = READ_ONCE(mpcs->handle_irq);
89e5b732a2SRussell King (Oracle) if (!handler)
90e5b732a2SRussell King (Oracle) return IRQ_NONE;
91e5b732a2SRussell King (Oracle)
92e5b732a2SRussell King (Oracle) return handler(mpcs);
93e5b732a2SRussell King (Oracle) }
94e5b732a2SRussell King (Oracle)
mv88e639x_pcs_setup_irq(struct mv88e639x_pcs * mpcs,struct mv88e6xxx_chip * chip,int port)95e5b732a2SRussell King (Oracle) static int mv88e639x_pcs_setup_irq(struct mv88e639x_pcs *mpcs,
96e5b732a2SRussell King (Oracle) struct mv88e6xxx_chip *chip, int port)
97e5b732a2SRussell King (Oracle) {
98e5b732a2SRussell King (Oracle) unsigned int irq;
99e5b732a2SRussell King (Oracle)
100e5b732a2SRussell King (Oracle) irq = mv88e6xxx_serdes_irq_mapping(chip, port);
101e5b732a2SRussell King (Oracle) if (!irq) {
102e5b732a2SRussell King (Oracle) /* Use polling mode */
103e5b732a2SRussell King (Oracle) mpcs->sgmii_pcs.poll = true;
104e5b732a2SRussell King (Oracle) mpcs->xg_pcs.poll = true;
105e5b732a2SRussell King (Oracle) return 0;
106e5b732a2SRussell King (Oracle) }
107e5b732a2SRussell King (Oracle)
108e5b732a2SRussell King (Oracle) mpcs->irq = irq;
109e5b732a2SRussell King (Oracle)
110e5b732a2SRussell King (Oracle) return request_threaded_irq(irq, NULL, mv88e639x_pcs_handle_irq,
111e5b732a2SRussell King (Oracle) IRQF_ONESHOT, mpcs->name, mpcs);
112e5b732a2SRussell King (Oracle) }
113e5b732a2SRussell King (Oracle)
mv88e639x_pcs_teardown(struct mv88e6xxx_chip * chip,int port)114e5b732a2SRussell King (Oracle) static void mv88e639x_pcs_teardown(struct mv88e6xxx_chip *chip, int port)
115e5b732a2SRussell King (Oracle) {
116e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = chip->ports[port].pcs_private;
117e5b732a2SRussell King (Oracle)
118e5b732a2SRussell King (Oracle) if (!mpcs)
119e5b732a2SRussell King (Oracle) return;
120e5b732a2SRussell King (Oracle)
121e5b732a2SRussell King (Oracle) if (mpcs->irq)
122e5b732a2SRussell King (Oracle) free_irq(mpcs->irq, mpcs);
123e5b732a2SRussell King (Oracle)
124e5b732a2SRussell King (Oracle) kfree(mpcs);
125e5b732a2SRussell King (Oracle)
126e5b732a2SRussell King (Oracle) chip->ports[port].pcs_private = NULL;
127e5b732a2SRussell King (Oracle) }
128e5b732a2SRussell King (Oracle)
sgmii_pcs_to_mv88e639x_pcs(struct phylink_pcs * pcs)129e5b732a2SRussell King (Oracle) static struct mv88e639x_pcs *sgmii_pcs_to_mv88e639x_pcs(struct phylink_pcs *pcs)
130e5b732a2SRussell King (Oracle) {
131e5b732a2SRussell King (Oracle) return container_of(pcs, struct mv88e639x_pcs, sgmii_pcs);
132e5b732a2SRussell King (Oracle) }
133e5b732a2SRussell King (Oracle)
mv88e639x_sgmii_handle_irq(struct mv88e639x_pcs * mpcs)134e5b732a2SRussell King (Oracle) static irqreturn_t mv88e639x_sgmii_handle_irq(struct mv88e639x_pcs *mpcs)
135e5b732a2SRussell King (Oracle) {
136e5b732a2SRussell King (Oracle) u16 int_status;
137e5b732a2SRussell King (Oracle) int err;
138e5b732a2SRussell King (Oracle)
139e5b732a2SRussell King (Oracle) err = mv88e639x_read(mpcs, MV88E6390_SGMII_INT_STATUS, &int_status);
140e5b732a2SRussell King (Oracle) if (err)
141e5b732a2SRussell King (Oracle) return IRQ_NONE;
142e5b732a2SRussell King (Oracle)
143e5b732a2SRussell King (Oracle) if (int_status & (MV88E6390_SGMII_INT_LINK_DOWN |
144e5b732a2SRussell King (Oracle) MV88E6390_SGMII_INT_LINK_UP)) {
145e5b732a2SRussell King (Oracle) phylink_pcs_change(&mpcs->sgmii_pcs,
146e5b732a2SRussell King (Oracle) int_status & MV88E6390_SGMII_INT_LINK_UP);
147e5b732a2SRussell King (Oracle)
148e5b732a2SRussell King (Oracle) return IRQ_HANDLED;
149e5b732a2SRussell King (Oracle) }
150e5b732a2SRussell King (Oracle)
151e5b732a2SRussell King (Oracle) return IRQ_NONE;
152e5b732a2SRussell King (Oracle) }
153e5b732a2SRussell King (Oracle)
mv88e639x_sgmii_pcs_control_irq(struct mv88e639x_pcs * mpcs,bool enable)154e5b732a2SRussell King (Oracle) static int mv88e639x_sgmii_pcs_control_irq(struct mv88e639x_pcs *mpcs,
155e5b732a2SRussell King (Oracle) bool enable)
156e5b732a2SRussell King (Oracle) {
157e5b732a2SRussell King (Oracle) u16 val = 0;
158e5b732a2SRussell King (Oracle)
159e5b732a2SRussell King (Oracle) if (enable)
160e5b732a2SRussell King (Oracle) val |= MV88E6390_SGMII_INT_LINK_DOWN |
161e5b732a2SRussell King (Oracle) MV88E6390_SGMII_INT_LINK_UP;
162e5b732a2SRussell King (Oracle)
163e5b732a2SRussell King (Oracle) return mv88e639x_modify(mpcs, MV88E6390_SGMII_INT_ENABLE,
164e5b732a2SRussell King (Oracle) MV88E6390_SGMII_INT_LINK_DOWN |
165e5b732a2SRussell King (Oracle) MV88E6390_SGMII_INT_LINK_UP, val);
166e5b732a2SRussell King (Oracle) }
167e5b732a2SRussell King (Oracle)
mv88e639x_sgmii_pcs_control_pwr(struct mv88e639x_pcs * mpcs,bool enable)168e5b732a2SRussell King (Oracle) static int mv88e639x_sgmii_pcs_control_pwr(struct mv88e639x_pcs *mpcs,
169e5b732a2SRussell King (Oracle) bool enable)
170e5b732a2SRussell King (Oracle) {
171e5b732a2SRussell King (Oracle) u16 mask, val;
172e5b732a2SRussell King (Oracle)
173e5b732a2SRussell King (Oracle) if (enable) {
174e5b732a2SRussell King (Oracle) mask = BMCR_RESET | BMCR_LOOPBACK | BMCR_PDOWN;
175e5b732a2SRussell King (Oracle) val = 0;
176e5b732a2SRussell King (Oracle) } else {
177e5b732a2SRussell King (Oracle) mask = val = BMCR_PDOWN;
178e5b732a2SRussell King (Oracle) }
179e5b732a2SRussell King (Oracle)
180e5b732a2SRussell King (Oracle) return mv88e639x_modify(mpcs, MV88E6390_SGMII_BMCR, mask, val);
181e5b732a2SRussell King (Oracle) }
182e5b732a2SRussell King (Oracle)
mv88e639x_sgmii_pcs_enable(struct phylink_pcs * pcs)183e5b732a2SRussell King (Oracle) static int mv88e639x_sgmii_pcs_enable(struct phylink_pcs *pcs)
184e5b732a2SRussell King (Oracle) {
185e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
186e5b732a2SRussell King (Oracle)
187e5b732a2SRussell King (Oracle) /* power enable done in post_config */
188e5b732a2SRussell King (Oracle) mpcs->handle_irq = mv88e639x_sgmii_handle_irq;
189e5b732a2SRussell King (Oracle)
190e5b732a2SRussell King (Oracle) return mv88e639x_sgmii_pcs_control_irq(mpcs, !!mpcs->irq);
191e5b732a2SRussell King (Oracle) }
192e5b732a2SRussell King (Oracle)
mv88e639x_sgmii_pcs_disable(struct phylink_pcs * pcs)193e5b732a2SRussell King (Oracle) static void mv88e639x_sgmii_pcs_disable(struct phylink_pcs *pcs)
194e5b732a2SRussell King (Oracle) {
195e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
196e5b732a2SRussell King (Oracle)
197e5b732a2SRussell King (Oracle) mv88e639x_sgmii_pcs_control_irq(mpcs, false);
198e5b732a2SRussell King (Oracle) mv88e639x_sgmii_pcs_control_pwr(mpcs, false);
199e5b732a2SRussell King (Oracle) }
200e5b732a2SRussell King (Oracle)
mv88e639x_sgmii_pcs_pre_config(struct phylink_pcs * pcs,phy_interface_t interface)201e5b732a2SRussell King (Oracle) static void mv88e639x_sgmii_pcs_pre_config(struct phylink_pcs *pcs,
202e5b732a2SRussell King (Oracle) phy_interface_t interface)
203e5b732a2SRussell King (Oracle) {
204e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
205e5b732a2SRussell King (Oracle)
206e5b732a2SRussell King (Oracle) mv88e639x_sgmii_pcs_control_pwr(mpcs, false);
207e5b732a2SRussell King (Oracle) }
208e5b732a2SRussell King (Oracle)
mv88e6390_erratum_3_14(struct mv88e639x_pcs * mpcs)209745d7e38SAnte Knezic static int mv88e6390_erratum_3_14(struct mv88e639x_pcs *mpcs)
210745d7e38SAnte Knezic {
211745d7e38SAnte Knezic const int lanes[] = { MV88E6390_PORT9_LANE0, MV88E6390_PORT9_LANE1,
212745d7e38SAnte Knezic MV88E6390_PORT9_LANE2, MV88E6390_PORT9_LANE3,
213745d7e38SAnte Knezic MV88E6390_PORT10_LANE0, MV88E6390_PORT10_LANE1,
214745d7e38SAnte Knezic MV88E6390_PORT10_LANE2, MV88E6390_PORT10_LANE3 };
215745d7e38SAnte Knezic int err, i;
216745d7e38SAnte Knezic
217745d7e38SAnte Knezic /* 88e6190x and 88e6390x errata 3.14:
218745d7e38SAnte Knezic * After chip reset, SERDES reconfiguration or SERDES core
219745d7e38SAnte Knezic * Software Reset, the SERDES lanes may not be properly aligned
220745d7e38SAnte Knezic * resulting in CRC errors
221745d7e38SAnte Knezic */
222745d7e38SAnte Knezic
223745d7e38SAnte Knezic for (i = 0; i < ARRAY_SIZE(lanes); i++) {
224745d7e38SAnte Knezic err = mdiobus_c45_write(mpcs->mdio.bus, lanes[i],
225745d7e38SAnte Knezic MDIO_MMD_PHYXS,
226745d7e38SAnte Knezic 0xf054, 0x400C);
227745d7e38SAnte Knezic if (err)
228745d7e38SAnte Knezic return err;
229745d7e38SAnte Knezic
230745d7e38SAnte Knezic err = mdiobus_c45_write(mpcs->mdio.bus, lanes[i],
231745d7e38SAnte Knezic MDIO_MMD_PHYXS,
232745d7e38SAnte Knezic 0xf054, 0x4000);
233745d7e38SAnte Knezic if (err)
234745d7e38SAnte Knezic return err;
235745d7e38SAnte Knezic }
236745d7e38SAnte Knezic
237745d7e38SAnte Knezic return 0;
238745d7e38SAnte Knezic }
239745d7e38SAnte Knezic
mv88e639x_sgmii_pcs_post_config(struct phylink_pcs * pcs,phy_interface_t interface)240e5b732a2SRussell King (Oracle) static int mv88e639x_sgmii_pcs_post_config(struct phylink_pcs *pcs,
241e5b732a2SRussell King (Oracle) phy_interface_t interface)
242e5b732a2SRussell King (Oracle) {
243e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
244745d7e38SAnte Knezic int err;
245e5b732a2SRussell King (Oracle)
246e5b732a2SRussell King (Oracle) mv88e639x_sgmii_pcs_control_pwr(mpcs, true);
247e5b732a2SRussell King (Oracle)
248745d7e38SAnte Knezic if (mpcs->erratum_3_14) {
249745d7e38SAnte Knezic err = mv88e6390_erratum_3_14(mpcs);
250745d7e38SAnte Knezic if (err)
251745d7e38SAnte Knezic dev_err(mpcs->mdio.dev.parent,
252745d7e38SAnte Knezic "failed to apply erratum 3.14: %pe\n",
253745d7e38SAnte Knezic ERR_PTR(err));
254745d7e38SAnte Knezic }
255745d7e38SAnte Knezic
256e5b732a2SRussell King (Oracle) return 0;
257e5b732a2SRussell King (Oracle) }
258e5b732a2SRussell King (Oracle)
mv88e639x_sgmii_pcs_get_state(struct phylink_pcs * pcs,struct phylink_link_state * state)259e5b732a2SRussell King (Oracle) static void mv88e639x_sgmii_pcs_get_state(struct phylink_pcs *pcs,
260e5b732a2SRussell King (Oracle) struct phylink_link_state *state)
261e5b732a2SRussell King (Oracle) {
262e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
263e5b732a2SRussell King (Oracle) u16 bmsr, lpa, status;
264e5b732a2SRussell King (Oracle) int err;
265e5b732a2SRussell King (Oracle)
266e5b732a2SRussell King (Oracle) err = mv88e639x_read(mpcs, MV88E6390_SGMII_BMSR, &bmsr);
267e5b732a2SRussell King (Oracle) if (err) {
268e5b732a2SRussell King (Oracle) dev_err(mpcs->mdio.dev.parent,
269e5b732a2SRussell King (Oracle) "can't read Serdes PHY %s: %pe\n",
270e5b732a2SRussell King (Oracle) "BMSR", ERR_PTR(err));
271e5b732a2SRussell King (Oracle) state->link = false;
272e5b732a2SRussell King (Oracle) return;
273e5b732a2SRussell King (Oracle) }
274e5b732a2SRussell King (Oracle)
275e5b732a2SRussell King (Oracle) err = mv88e639x_read(mpcs, MV88E6390_SGMII_LPA, &lpa);
276e5b732a2SRussell King (Oracle) if (err) {
277e5b732a2SRussell King (Oracle) dev_err(mpcs->mdio.dev.parent,
278e5b732a2SRussell King (Oracle) "can't read Serdes PHY %s: %pe\n",
279e5b732a2SRussell King (Oracle) "LPA", ERR_PTR(err));
280e5b732a2SRussell King (Oracle) state->link = false;
281e5b732a2SRussell King (Oracle) return;
282e5b732a2SRussell King (Oracle) }
283e5b732a2SRussell King (Oracle)
284e5b732a2SRussell King (Oracle) err = mv88e639x_read(mpcs, MV88E6390_SGMII_PHY_STATUS, &status);
285e5b732a2SRussell King (Oracle) if (err) {
286e5b732a2SRussell King (Oracle) dev_err(mpcs->mdio.dev.parent,
287e5b732a2SRussell King (Oracle) "can't read Serdes PHY %s: %pe\n",
288e5b732a2SRussell King (Oracle) "status", ERR_PTR(err));
289e5b732a2SRussell King (Oracle) state->link = false;
290e5b732a2SRussell King (Oracle) return;
291e5b732a2SRussell King (Oracle) }
292e5b732a2SRussell King (Oracle)
293e5b732a2SRussell King (Oracle) mv88e6xxx_pcs_decode_state(mpcs->mdio.dev.parent, bmsr, lpa, status,
294e5b732a2SRussell King (Oracle) state);
295e5b732a2SRussell King (Oracle) }
296e5b732a2SRussell King (Oracle)
mv88e639x_sgmii_pcs_config(struct phylink_pcs * pcs,unsigned int neg_mode,phy_interface_t interface,const unsigned long * advertising,bool permit_pause_to_mac)297e5b732a2SRussell King (Oracle) static int mv88e639x_sgmii_pcs_config(struct phylink_pcs *pcs,
298e5b732a2SRussell King (Oracle) unsigned int neg_mode,
299e5b732a2SRussell King (Oracle) phy_interface_t interface,
300e5b732a2SRussell King (Oracle) const unsigned long *advertising,
301e5b732a2SRussell King (Oracle) bool permit_pause_to_mac)
302e5b732a2SRussell King (Oracle) {
303e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
304e5b732a2SRussell King (Oracle) u16 val, bmcr;
305e5b732a2SRussell King (Oracle) bool changed;
306e5b732a2SRussell King (Oracle) int adv, err;
307e5b732a2SRussell King (Oracle)
308e5b732a2SRussell King (Oracle) adv = phylink_mii_c22_pcs_encode_advertisement(interface, advertising);
309e5b732a2SRussell King (Oracle) if (adv < 0)
310e5b732a2SRussell King (Oracle) return 0;
311e5b732a2SRussell King (Oracle)
312e5b732a2SRussell King (Oracle) mpcs->interface = interface;
313e5b732a2SRussell King (Oracle)
314e5b732a2SRussell King (Oracle) err = mv88e639x_modify_changed(mpcs, MV88E6390_SGMII_ADVERTISE,
315e5b732a2SRussell King (Oracle) 0xffff, adv);
316e5b732a2SRussell King (Oracle) if (err < 0)
317e5b732a2SRussell King (Oracle) return err;
318e5b732a2SRussell King (Oracle)
319e5b732a2SRussell King (Oracle) changed = err > 0;
320e5b732a2SRussell King (Oracle)
321e5b732a2SRussell King (Oracle) err = mv88e639x_read(mpcs, MV88E6390_SGMII_BMCR, &val);
322e5b732a2SRussell King (Oracle) if (err)
323e5b732a2SRussell King (Oracle) return err;
324e5b732a2SRussell King (Oracle)
325e5b732a2SRussell King (Oracle) if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
326e5b732a2SRussell King (Oracle) bmcr = val | BMCR_ANENABLE;
327e5b732a2SRussell King (Oracle) else
328e5b732a2SRussell King (Oracle) bmcr = val & ~BMCR_ANENABLE;
329e5b732a2SRussell King (Oracle)
330e5b732a2SRussell King (Oracle) /* setting ANENABLE triggers a restart of negotiation */
331e5b732a2SRussell King (Oracle) if (bmcr == val)
332e5b732a2SRussell King (Oracle) return changed;
333e5b732a2SRussell King (Oracle)
334e5b732a2SRussell King (Oracle) return mv88e639x_write(mpcs, MV88E6390_SGMII_BMCR, bmcr);
335e5b732a2SRussell King (Oracle) }
336e5b732a2SRussell King (Oracle)
mv88e639x_sgmii_pcs_an_restart(struct phylink_pcs * pcs)337e5b732a2SRussell King (Oracle) static void mv88e639x_sgmii_pcs_an_restart(struct phylink_pcs *pcs)
338e5b732a2SRussell King (Oracle) {
339e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
340e5b732a2SRussell King (Oracle)
341e5b732a2SRussell King (Oracle) mv88e639x_modify(mpcs, MV88E6390_SGMII_BMCR,
342e5b732a2SRussell King (Oracle) BMCR_ANRESTART, BMCR_ANRESTART);
343e5b732a2SRussell King (Oracle) }
344e5b732a2SRussell King (Oracle)
mv88e639x_sgmii_pcs_link_up(struct phylink_pcs * pcs,unsigned int mode,phy_interface_t interface,int speed,int duplex)345e5b732a2SRussell King (Oracle) static void mv88e639x_sgmii_pcs_link_up(struct phylink_pcs *pcs,
346e5b732a2SRussell King (Oracle) unsigned int mode,
347e5b732a2SRussell King (Oracle) phy_interface_t interface,
348e5b732a2SRussell King (Oracle) int speed, int duplex)
349e5b732a2SRussell King (Oracle) {
350e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
351e5b732a2SRussell King (Oracle) u16 bmcr;
352e5b732a2SRussell King (Oracle) int err;
353e5b732a2SRussell King (Oracle)
354e5b732a2SRussell King (Oracle) if (phylink_autoneg_inband(mode))
355e5b732a2SRussell King (Oracle) return;
356e5b732a2SRussell King (Oracle)
357e5b732a2SRussell King (Oracle) bmcr = mii_bmcr_encode_fixed(speed, duplex);
358e5b732a2SRussell King (Oracle)
359e5b732a2SRussell King (Oracle) err = mv88e639x_modify(mpcs, MV88E6390_SGMII_BMCR,
360e5b732a2SRussell King (Oracle) BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX,
361e5b732a2SRussell King (Oracle) bmcr);
362e5b732a2SRussell King (Oracle) if (err)
363e5b732a2SRussell King (Oracle) dev_err(mpcs->mdio.dev.parent,
364e5b732a2SRussell King (Oracle) "can't access Serdes PHY %s: %pe\n",
365e5b732a2SRussell King (Oracle) "BMCR", ERR_PTR(err));
366e5b732a2SRussell King (Oracle) }
367e5b732a2SRussell King (Oracle)
368e5b732a2SRussell King (Oracle) static const struct phylink_pcs_ops mv88e639x_sgmii_pcs_ops = {
369e5b732a2SRussell King (Oracle) .pcs_enable = mv88e639x_sgmii_pcs_enable,
370e5b732a2SRussell King (Oracle) .pcs_disable = mv88e639x_sgmii_pcs_disable,
371e5b732a2SRussell King (Oracle) .pcs_pre_config = mv88e639x_sgmii_pcs_pre_config,
372e5b732a2SRussell King (Oracle) .pcs_post_config = mv88e639x_sgmii_pcs_post_config,
373e5b732a2SRussell King (Oracle) .pcs_get_state = mv88e639x_sgmii_pcs_get_state,
374e5b732a2SRussell King (Oracle) .pcs_an_restart = mv88e639x_sgmii_pcs_an_restart,
375e5b732a2SRussell King (Oracle) .pcs_config = mv88e639x_sgmii_pcs_config,
376e5b732a2SRussell King (Oracle) .pcs_link_up = mv88e639x_sgmii_pcs_link_up,
377e5b732a2SRussell King (Oracle) };
378e5b732a2SRussell King (Oracle)
xg_pcs_to_mv88e639x_pcs(struct phylink_pcs * pcs)379e5b732a2SRussell King (Oracle) static struct mv88e639x_pcs *xg_pcs_to_mv88e639x_pcs(struct phylink_pcs *pcs)
380e5b732a2SRussell King (Oracle) {
381e5b732a2SRussell King (Oracle) return container_of(pcs, struct mv88e639x_pcs, xg_pcs);
382e5b732a2SRussell King (Oracle) }
383e5b732a2SRussell King (Oracle)
mv88e639x_xg_pcs_enable(struct mv88e639x_pcs * mpcs)384e5b732a2SRussell King (Oracle) static int mv88e639x_xg_pcs_enable(struct mv88e639x_pcs *mpcs)
385e5b732a2SRussell King (Oracle) {
386e5b732a2SRussell King (Oracle) return mv88e639x_modify(mpcs, MV88E6390_10G_CTRL1,
387e5b732a2SRussell King (Oracle) MDIO_CTRL1_RESET | MDIO_PCS_CTRL1_LOOPBACK |
388e5b732a2SRussell King (Oracle) MDIO_CTRL1_LPOWER, 0);
389e5b732a2SRussell King (Oracle) }
390e5b732a2SRussell King (Oracle)
mv88e639x_xg_pcs_disable(struct mv88e639x_pcs * mpcs)391e5b732a2SRussell King (Oracle) static void mv88e639x_xg_pcs_disable(struct mv88e639x_pcs *mpcs)
392e5b732a2SRussell King (Oracle) {
393e5b732a2SRussell King (Oracle) mv88e639x_modify(mpcs, MV88E6390_10G_CTRL1, MDIO_CTRL1_LPOWER,
394e5b732a2SRussell King (Oracle) MDIO_CTRL1_LPOWER);
395e5b732a2SRussell King (Oracle) }
396e5b732a2SRussell King (Oracle)
mv88e639x_xg_pcs_get_state(struct phylink_pcs * pcs,struct phylink_link_state * state)397e5b732a2SRussell King (Oracle) static void mv88e639x_xg_pcs_get_state(struct phylink_pcs *pcs,
398e5b732a2SRussell King (Oracle) struct phylink_link_state *state)
399e5b732a2SRussell King (Oracle) {
400e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
401e5b732a2SRussell King (Oracle) u16 status;
402e5b732a2SRussell King (Oracle) int err;
403e5b732a2SRussell King (Oracle)
404e5b732a2SRussell King (Oracle) state->link = false;
405e5b732a2SRussell King (Oracle)
406e5b732a2SRussell King (Oracle) err = mv88e639x_read(mpcs, MV88E6390_10G_STAT1, &status);
407e5b732a2SRussell King (Oracle) if (err) {
408e5b732a2SRussell King (Oracle) dev_err(mpcs->mdio.dev.parent,
409e5b732a2SRussell King (Oracle) "can't read Serdes PHY %s: %pe\n",
410e5b732a2SRussell King (Oracle) "STAT1", ERR_PTR(err));
411e5b732a2SRussell King (Oracle) return;
412e5b732a2SRussell King (Oracle) }
413e5b732a2SRussell King (Oracle)
414e5b732a2SRussell King (Oracle) state->link = !!(status & MDIO_STAT1_LSTATUS);
415e5b732a2SRussell King (Oracle) if (state->link) {
416e5b732a2SRussell King (Oracle) switch (state->interface) {
417e5b732a2SRussell King (Oracle) case PHY_INTERFACE_MODE_5GBASER:
418e5b732a2SRussell King (Oracle) state->speed = SPEED_5000;
419e5b732a2SRussell King (Oracle) break;
420e5b732a2SRussell King (Oracle)
421e5b732a2SRussell King (Oracle) case PHY_INTERFACE_MODE_10GBASER:
422e5b732a2SRussell King (Oracle) case PHY_INTERFACE_MODE_RXAUI:
423e5b732a2SRussell King (Oracle) case PHY_INTERFACE_MODE_XAUI:
424e5b732a2SRussell King (Oracle) state->speed = SPEED_10000;
425e5b732a2SRussell King (Oracle) break;
426e5b732a2SRussell King (Oracle)
427e5b732a2SRussell King (Oracle) default:
428e5b732a2SRussell King (Oracle) state->link = false;
429e5b732a2SRussell King (Oracle) return;
430e5b732a2SRussell King (Oracle) }
431e5b732a2SRussell King (Oracle)
432e5b732a2SRussell King (Oracle) state->duplex = DUPLEX_FULL;
433e5b732a2SRussell King (Oracle) }
434e5b732a2SRussell King (Oracle) }
435e5b732a2SRussell King (Oracle)
mv88e639x_xg_pcs_config(struct phylink_pcs * pcs,unsigned int neg_mode,phy_interface_t interface,const unsigned long * advertising,bool permit_pause_to_mac)436e5b732a2SRussell King (Oracle) static int mv88e639x_xg_pcs_config(struct phylink_pcs *pcs,
437e5b732a2SRussell King (Oracle) unsigned int neg_mode,
438e5b732a2SRussell King (Oracle) phy_interface_t interface,
439e5b732a2SRussell King (Oracle) const unsigned long *advertising,
440e5b732a2SRussell King (Oracle) bool permit_pause_to_mac)
441e5b732a2SRussell King (Oracle) {
442e5b732a2SRussell King (Oracle) return 0;
443e5b732a2SRussell King (Oracle) }
444e5b732a2SRussell King (Oracle)
445e5b732a2SRussell King (Oracle) static struct phylink_pcs *
mv88e639x_pcs_select(struct mv88e6xxx_chip * chip,int port,phy_interface_t mode)446e5b732a2SRussell King (Oracle) mv88e639x_pcs_select(struct mv88e6xxx_chip *chip, int port,
447e5b732a2SRussell King (Oracle) phy_interface_t mode)
448e5b732a2SRussell King (Oracle) {
449e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs;
450e5b732a2SRussell King (Oracle)
451e5b732a2SRussell King (Oracle) mpcs = chip->ports[port].pcs_private;
452e5b732a2SRussell King (Oracle) if (!mpcs)
453e5b732a2SRussell King (Oracle) return NULL;
454e5b732a2SRussell King (Oracle)
455e5b732a2SRussell King (Oracle) switch (mode) {
456e5b732a2SRussell King (Oracle) case PHY_INTERFACE_MODE_SGMII:
457e5b732a2SRussell King (Oracle) case PHY_INTERFACE_MODE_1000BASEX:
458e5b732a2SRussell King (Oracle) case PHY_INTERFACE_MODE_2500BASEX:
459e5b732a2SRussell King (Oracle) return &mpcs->sgmii_pcs;
460e5b732a2SRussell King (Oracle)
461e5b732a2SRussell King (Oracle) case PHY_INTERFACE_MODE_5GBASER:
462e5b732a2SRussell King (Oracle) if (!mpcs->supports_5g)
463e5b732a2SRussell King (Oracle) return NULL;
464e5b732a2SRussell King (Oracle) fallthrough;
465e5b732a2SRussell King (Oracle) case PHY_INTERFACE_MODE_10GBASER:
466e5b732a2SRussell King (Oracle) case PHY_INTERFACE_MODE_XAUI:
467e5b732a2SRussell King (Oracle) case PHY_INTERFACE_MODE_RXAUI:
468*29561ef0STobias Waldekranz case PHY_INTERFACE_MODE_USXGMII:
469e5b732a2SRussell King (Oracle) return &mpcs->xg_pcs;
470e5b732a2SRussell King (Oracle)
471e5b732a2SRussell King (Oracle) default:
472e5b732a2SRussell King (Oracle) return NULL;
473e5b732a2SRussell King (Oracle) }
474e5b732a2SRussell King (Oracle) }
475e5b732a2SRussell King (Oracle)
476e5b732a2SRussell King (Oracle) /* Marvell 88E6390 Specific support */
477e5b732a2SRussell King (Oracle)
mv88e6390_xg_handle_irq(struct mv88e639x_pcs * mpcs)478e5b732a2SRussell King (Oracle) static irqreturn_t mv88e6390_xg_handle_irq(struct mv88e639x_pcs *mpcs)
479e5b732a2SRussell King (Oracle) {
480e5b732a2SRussell King (Oracle) u16 int_status;
481e5b732a2SRussell King (Oracle) int err;
482e5b732a2SRussell King (Oracle)
483e5b732a2SRussell King (Oracle) err = mv88e639x_read(mpcs, MV88E6390_10G_INT_STATUS, &int_status);
484e5b732a2SRussell King (Oracle) if (err)
485e5b732a2SRussell King (Oracle) return IRQ_NONE;
486e5b732a2SRussell King (Oracle)
487e5b732a2SRussell King (Oracle) if (int_status & (MV88E6390_10G_INT_LINK_DOWN |
488e5b732a2SRussell King (Oracle) MV88E6390_10G_INT_LINK_UP)) {
489e5b732a2SRussell King (Oracle) phylink_pcs_change(&mpcs->xg_pcs,
490e5b732a2SRussell King (Oracle) int_status & MV88E6390_10G_INT_LINK_UP);
491e5b732a2SRussell King (Oracle)
492e5b732a2SRussell King (Oracle) return IRQ_HANDLED;
493e5b732a2SRussell King (Oracle) }
494e5b732a2SRussell King (Oracle)
495e5b732a2SRussell King (Oracle) return IRQ_NONE;
496e5b732a2SRussell King (Oracle) }
497e5b732a2SRussell King (Oracle)
mv88e6390_xg_control_irq(struct mv88e639x_pcs * mpcs,bool enable)498e5b732a2SRussell King (Oracle) static int mv88e6390_xg_control_irq(struct mv88e639x_pcs *mpcs, bool enable)
499e5b732a2SRussell King (Oracle) {
500e5b732a2SRussell King (Oracle) u16 val = 0;
501e5b732a2SRussell King (Oracle)
502e5b732a2SRussell King (Oracle) if (enable)
503e5b732a2SRussell King (Oracle) val = MV88E6390_10G_INT_LINK_DOWN | MV88E6390_10G_INT_LINK_UP;
504e5b732a2SRussell King (Oracle)
505e5b732a2SRussell King (Oracle) return mv88e639x_modify(mpcs, MV88E6390_10G_INT_ENABLE,
506e5b732a2SRussell King (Oracle) MV88E6390_10G_INT_LINK_DOWN |
507e5b732a2SRussell King (Oracle) MV88E6390_10G_INT_LINK_UP, val);
508e5b732a2SRussell King (Oracle) }
509e5b732a2SRussell King (Oracle)
mv88e6390_xg_pcs_enable(struct phylink_pcs * pcs)510e5b732a2SRussell King (Oracle) static int mv88e6390_xg_pcs_enable(struct phylink_pcs *pcs)
511e5b732a2SRussell King (Oracle) {
512e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
513e5b732a2SRussell King (Oracle) int err;
514e5b732a2SRussell King (Oracle)
515e5b732a2SRussell King (Oracle) err = mv88e639x_xg_pcs_enable(mpcs);
516e5b732a2SRussell King (Oracle) if (err)
517e5b732a2SRussell King (Oracle) return err;
518e5b732a2SRussell King (Oracle)
519e5b732a2SRussell King (Oracle) mpcs->handle_irq = mv88e6390_xg_handle_irq;
520e5b732a2SRussell King (Oracle)
521e5b732a2SRussell King (Oracle) return mv88e6390_xg_control_irq(mpcs, !!mpcs->irq);
522e5b732a2SRussell King (Oracle) }
523e5b732a2SRussell King (Oracle)
mv88e6390_xg_pcs_disable(struct phylink_pcs * pcs)524e5b732a2SRussell King (Oracle) static void mv88e6390_xg_pcs_disable(struct phylink_pcs *pcs)
525e5b732a2SRussell King (Oracle) {
526e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
527e5b732a2SRussell King (Oracle)
528e5b732a2SRussell King (Oracle) mv88e6390_xg_control_irq(mpcs, false);
529e5b732a2SRussell King (Oracle) mv88e639x_xg_pcs_disable(mpcs);
530e5b732a2SRussell King (Oracle) }
531e5b732a2SRussell King (Oracle)
532e5b732a2SRussell King (Oracle) static const struct phylink_pcs_ops mv88e6390_xg_pcs_ops = {
533e5b732a2SRussell King (Oracle) .pcs_enable = mv88e6390_xg_pcs_enable,
534e5b732a2SRussell King (Oracle) .pcs_disable = mv88e6390_xg_pcs_disable,
535e5b732a2SRussell King (Oracle) .pcs_get_state = mv88e639x_xg_pcs_get_state,
536e5b732a2SRussell King (Oracle) .pcs_config = mv88e639x_xg_pcs_config,
537e5b732a2SRussell King (Oracle) };
538e5b732a2SRussell King (Oracle)
mv88e6390_pcs_enable_checker(struct mv88e639x_pcs * mpcs)539e5b732a2SRussell King (Oracle) static int mv88e6390_pcs_enable_checker(struct mv88e639x_pcs *mpcs)
540e5b732a2SRussell King (Oracle) {
541e5b732a2SRussell King (Oracle) return mv88e639x_modify(mpcs, MV88E6390_PG_CONTROL,
542e5b732a2SRussell King (Oracle) MV88E6390_PG_CONTROL_ENABLE_PC,
543e5b732a2SRussell King (Oracle) MV88E6390_PG_CONTROL_ENABLE_PC);
544e5b732a2SRussell King (Oracle) }
545e5b732a2SRussell King (Oracle)
mv88e6390_pcs_init(struct mv88e6xxx_chip * chip,int port)546e5b732a2SRussell King (Oracle) static int mv88e6390_pcs_init(struct mv88e6xxx_chip *chip, int port)
547e5b732a2SRussell King (Oracle) {
548e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs;
549e5b732a2SRussell King (Oracle) struct mii_bus *bus;
550e5b732a2SRussell King (Oracle) struct device *dev;
551e5b732a2SRussell King (Oracle) int lane, err;
552e5b732a2SRussell King (Oracle)
553e5b732a2SRussell King (Oracle) lane = mv88e6xxx_serdes_get_lane(chip, port);
554e5b732a2SRussell King (Oracle) if (lane < 0)
555e5b732a2SRussell King (Oracle) return 0;
556e5b732a2SRussell King (Oracle)
557e5b732a2SRussell King (Oracle) bus = mv88e6xxx_default_mdio_bus(chip);
558e5b732a2SRussell King (Oracle) dev = chip->dev;
559e5b732a2SRussell King (Oracle)
560e5b732a2SRussell King (Oracle) mpcs = mv88e639x_pcs_alloc(dev, bus, lane, port);
561e5b732a2SRussell King (Oracle) if (!mpcs)
562e5b732a2SRussell King (Oracle) return -ENOMEM;
563e5b732a2SRussell King (Oracle)
564e5b732a2SRussell King (Oracle) mpcs->sgmii_pcs.ops = &mv88e639x_sgmii_pcs_ops;
565e5b732a2SRussell King (Oracle) mpcs->sgmii_pcs.neg_mode = true;
566e5b732a2SRussell King (Oracle) mpcs->xg_pcs.ops = &mv88e6390_xg_pcs_ops;
567e5b732a2SRussell King (Oracle) mpcs->xg_pcs.neg_mode = true;
568e5b732a2SRussell King (Oracle)
569745d7e38SAnte Knezic if (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6190X ||
570745d7e38SAnte Knezic chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6390X)
571745d7e38SAnte Knezic mpcs->erratum_3_14 = true;
572745d7e38SAnte Knezic
573e5b732a2SRussell King (Oracle) err = mv88e639x_pcs_setup_irq(mpcs, chip, port);
574e5b732a2SRussell King (Oracle) if (err)
575e5b732a2SRussell King (Oracle) goto err_free;
576e5b732a2SRussell King (Oracle)
577e5b732a2SRussell King (Oracle) /* 6390 and 6390x has the checker, 6393x doesn't appear to? */
578e5b732a2SRussell King (Oracle) /* This is to enable gathering the statistics. Maybe this
579e5b732a2SRussell King (Oracle) * should call out to a helper? Or we could do this at init time.
580e5b732a2SRussell King (Oracle) */
581e5b732a2SRussell King (Oracle) err = mv88e6390_pcs_enable_checker(mpcs);
582e5b732a2SRussell King (Oracle) if (err)
583e5b732a2SRussell King (Oracle) goto err_free;
584e5b732a2SRussell King (Oracle)
585e5b732a2SRussell King (Oracle) chip->ports[port].pcs_private = mpcs;
586e5b732a2SRussell King (Oracle)
587e5b732a2SRussell King (Oracle) return 0;
588e5b732a2SRussell King (Oracle)
589e5b732a2SRussell King (Oracle) err_free:
590e5b732a2SRussell King (Oracle) kfree(mpcs);
591e5b732a2SRussell King (Oracle) return err;
592e5b732a2SRussell King (Oracle) }
593e5b732a2SRussell King (Oracle)
594e5b732a2SRussell King (Oracle) const struct mv88e6xxx_pcs_ops mv88e6390_pcs_ops = {
595e5b732a2SRussell King (Oracle) .pcs_init = mv88e6390_pcs_init,
596e5b732a2SRussell King (Oracle) .pcs_teardown = mv88e639x_pcs_teardown,
597e5b732a2SRussell King (Oracle) .pcs_select = mv88e639x_pcs_select,
598e5b732a2SRussell King (Oracle) };
599e5b732a2SRussell King (Oracle)
600e5b732a2SRussell King (Oracle) /* Marvell 88E6393X Specific support */
601e5b732a2SRussell King (Oracle)
mv88e6393x_power_lane(struct mv88e639x_pcs * mpcs,bool enable)602e5b732a2SRussell King (Oracle) static int mv88e6393x_power_lane(struct mv88e639x_pcs *mpcs, bool enable)
603e5b732a2SRussell King (Oracle) {
604e5b732a2SRussell King (Oracle) u16 val = MV88E6393X_SERDES_CTRL1_TX_PDOWN |
605e5b732a2SRussell King (Oracle) MV88E6393X_SERDES_CTRL1_RX_PDOWN;
606e5b732a2SRussell King (Oracle)
607e5b732a2SRussell King (Oracle) return mv88e639x_modify(mpcs, MV88E6393X_SERDES_CTRL1, val,
608e5b732a2SRussell King (Oracle) enable ? 0 : val);
609e5b732a2SRussell King (Oracle) }
610e5b732a2SRussell King (Oracle)
611e5b732a2SRussell King (Oracle) /* mv88e6393x family errata 4.6:
612e5b732a2SRussell King (Oracle) * Cannot clear PwrDn bit on SERDES if device is configured CPU_MGD mode or
613e5b732a2SRussell King (Oracle) * P0_mode is configured for [x]MII.
614e5b732a2SRussell King (Oracle) * Workaround: Set SERDES register 4.F002 bit 5=0 and bit 15=1.
615e5b732a2SRussell King (Oracle) *
616e5b732a2SRussell King (Oracle) * It seems that after this workaround the SERDES is automatically powered up
617e5b732a2SRussell King (Oracle) * (the bit is cleared), so power it down.
618e5b732a2SRussell King (Oracle) */
mv88e6393x_erratum_4_6(struct mv88e639x_pcs * mpcs)619e5b732a2SRussell King (Oracle) static int mv88e6393x_erratum_4_6(struct mv88e639x_pcs *mpcs)
620e5b732a2SRussell King (Oracle) {
621e5b732a2SRussell King (Oracle) int err;
622e5b732a2SRussell King (Oracle)
623e5b732a2SRussell King (Oracle) err = mv88e639x_modify(mpcs, MV88E6393X_SERDES_POC,
624e5b732a2SRussell King (Oracle) MV88E6393X_SERDES_POC_PDOWN |
625e5b732a2SRussell King (Oracle) MV88E6393X_SERDES_POC_RESET,
626e5b732a2SRussell King (Oracle) MV88E6393X_SERDES_POC_RESET);
627e5b732a2SRussell King (Oracle) if (err)
628e5b732a2SRussell King (Oracle) return err;
629e5b732a2SRussell King (Oracle)
630e5b732a2SRussell King (Oracle) err = mv88e639x_modify(mpcs, MV88E6390_SGMII_BMCR,
631e5b732a2SRussell King (Oracle) BMCR_PDOWN, BMCR_PDOWN);
632e5b732a2SRussell King (Oracle) if (err)
633e5b732a2SRussell King (Oracle) return err;
634e5b732a2SRussell King (Oracle)
635e5b732a2SRussell King (Oracle) err = mv88e639x_sgmii_pcs_control_pwr(mpcs, false);
636e5b732a2SRussell King (Oracle) if (err)
637e5b732a2SRussell King (Oracle) return err;
638e5b732a2SRussell King (Oracle)
639e5b732a2SRussell King (Oracle) return mv88e6393x_power_lane(mpcs, false);
640e5b732a2SRussell King (Oracle) }
641e5b732a2SRussell King (Oracle)
642e5b732a2SRussell King (Oracle) /* mv88e6393x family errata 4.8:
643e5b732a2SRussell King (Oracle) * When a SERDES port is operating in 1000BASE-X or SGMII mode link may not
644e5b732a2SRussell King (Oracle) * come up after hardware reset or software reset of SERDES core. Workaround
645e5b732a2SRussell King (Oracle) * is to write SERDES register 4.F074.14=1 for only those modes and 0 in all
646e5b732a2SRussell King (Oracle) * other modes.
647e5b732a2SRussell King (Oracle) */
mv88e6393x_erratum_4_8(struct mv88e639x_pcs * mpcs)648e5b732a2SRussell King (Oracle) static int mv88e6393x_erratum_4_8(struct mv88e639x_pcs *mpcs)
649e5b732a2SRussell King (Oracle) {
650e5b732a2SRussell King (Oracle) u16 reg, poc;
651e5b732a2SRussell King (Oracle) int err;
652e5b732a2SRussell King (Oracle)
653e5b732a2SRussell King (Oracle) err = mv88e639x_read(mpcs, MV88E6393X_SERDES_POC, &poc);
654e5b732a2SRussell King (Oracle) if (err)
655e5b732a2SRussell King (Oracle) return err;
656e5b732a2SRussell King (Oracle)
657e5b732a2SRussell King (Oracle) poc &= MV88E6393X_SERDES_POC_PCS_MASK;
658e5b732a2SRussell King (Oracle) if (poc == MV88E6393X_SERDES_POC_PCS_1000BASEX ||
659e5b732a2SRussell King (Oracle) poc == MV88E6393X_SERDES_POC_PCS_SGMII_PHY ||
660e5b732a2SRussell King (Oracle) poc == MV88E6393X_SERDES_POC_PCS_SGMII_MAC)
661e5b732a2SRussell King (Oracle) reg = MV88E6393X_ERRATA_4_8_BIT;
662e5b732a2SRussell King (Oracle) else
663e5b732a2SRussell King (Oracle) reg = 0;
664e5b732a2SRussell King (Oracle)
665e5b732a2SRussell King (Oracle) return mv88e639x_modify(mpcs, MV88E6393X_ERRATA_4_8_REG,
666e5b732a2SRussell King (Oracle) MV88E6393X_ERRATA_4_8_BIT, reg);
667e5b732a2SRussell King (Oracle) }
668e5b732a2SRussell King (Oracle)
669e5b732a2SRussell King (Oracle) /* mv88e6393x family errata 5.2:
670e5b732a2SRussell King (Oracle) * For optimal signal integrity the following sequence should be applied to
671e5b732a2SRussell King (Oracle) * SERDES operating in 10G mode. These registers only apply to 10G operation
672e5b732a2SRussell King (Oracle) * and have no effect on other speeds.
673e5b732a2SRussell King (Oracle) */
mv88e6393x_erratum_5_2(struct mv88e639x_pcs * mpcs)674e5b732a2SRussell King (Oracle) static int mv88e6393x_erratum_5_2(struct mv88e639x_pcs *mpcs)
675e5b732a2SRussell King (Oracle) {
676e5b732a2SRussell King (Oracle) static const struct {
677e5b732a2SRussell King (Oracle) u16 dev, reg, val, mask;
678e5b732a2SRussell King (Oracle) } fixes[] = {
679e5b732a2SRussell King (Oracle) { MDIO_MMD_VEND1, 0x8093, 0xcb5a, 0xffff },
680e5b732a2SRussell King (Oracle) { MDIO_MMD_VEND1, 0x8171, 0x7088, 0xffff },
681e5b732a2SRussell King (Oracle) { MDIO_MMD_VEND1, 0x80c9, 0x311a, 0xffff },
682e5b732a2SRussell King (Oracle) { MDIO_MMD_VEND1, 0x80a2, 0x8000, 0xff7f },
683e5b732a2SRussell King (Oracle) { MDIO_MMD_VEND1, 0x80a9, 0x0000, 0xfff0 },
684e5b732a2SRussell King (Oracle) { MDIO_MMD_VEND1, 0x80a3, 0x0000, 0xf8ff },
685e5b732a2SRussell King (Oracle) { MDIO_MMD_PHYXS, MV88E6393X_SERDES_POC,
686e5b732a2SRussell King (Oracle) MV88E6393X_SERDES_POC_RESET, MV88E6393X_SERDES_POC_RESET },
687e5b732a2SRussell King (Oracle) };
688e5b732a2SRussell King (Oracle) int err, i;
689e5b732a2SRussell King (Oracle)
690e5b732a2SRussell King (Oracle) for (i = 0; i < ARRAY_SIZE(fixes); ++i) {
691e5b732a2SRussell King (Oracle) err = mdiodev_c45_modify(&mpcs->mdio, fixes[i].dev,
692e5b732a2SRussell King (Oracle) fixes[i].reg, fixes[i].mask,
693e5b732a2SRussell King (Oracle) fixes[i].val);
694e5b732a2SRussell King (Oracle) if (err)
695e5b732a2SRussell King (Oracle) return err;
696e5b732a2SRussell King (Oracle) }
697e5b732a2SRussell King (Oracle)
698e5b732a2SRussell King (Oracle) return 0;
699e5b732a2SRussell King (Oracle) }
700e5b732a2SRussell King (Oracle)
701e5b732a2SRussell King (Oracle) /* Inband AN is broken on Amethyst in 2500base-x mode when set by standard
702e5b732a2SRussell King (Oracle) * mechanism (via cmode).
703e5b732a2SRussell King (Oracle) * We can get around this by configuring the PCS mode to 1000base-x and then
704e5b732a2SRussell King (Oracle) * writing value 0x58 to register 1e.8000. (This must be done while SerDes
705e5b732a2SRussell King (Oracle) * receiver and transmitter are disabled, which is, when this function is
706e5b732a2SRussell King (Oracle) * called.)
707e5b732a2SRussell King (Oracle) * It seem that when we do this configuration to 2500base-x mode (by changing
708e5b732a2SRussell King (Oracle) * PCS mode to 1000base-x and frequency to 3.125 GHz from 1.25 GHz) and then
709e5b732a2SRussell King (Oracle) * configure to sgmii or 1000base-x, the device thinks that it already has
710e5b732a2SRussell King (Oracle) * SerDes at 1.25 GHz and does not change the 1e.8000 register, leaving SerDes
711e5b732a2SRussell King (Oracle) * at 3.125 GHz.
712e5b732a2SRussell King (Oracle) * To avoid this, change PCS mode back to 2500base-x when disabling SerDes from
713e5b732a2SRussell King (Oracle) * 2500base-x mode.
714e5b732a2SRussell King (Oracle) */
mv88e6393x_fix_2500basex_an(struct mv88e639x_pcs * mpcs,bool on)715e5b732a2SRussell King (Oracle) static int mv88e6393x_fix_2500basex_an(struct mv88e639x_pcs *mpcs, bool on)
716e5b732a2SRussell King (Oracle) {
717e5b732a2SRussell King (Oracle) u16 reg;
718e5b732a2SRussell King (Oracle) int err;
719e5b732a2SRussell King (Oracle)
720e5b732a2SRussell King (Oracle) if (on)
721e5b732a2SRussell King (Oracle) reg = MV88E6393X_SERDES_POC_PCS_1000BASEX |
722e5b732a2SRussell King (Oracle) MV88E6393X_SERDES_POC_AN;
723e5b732a2SRussell King (Oracle) else
724e5b732a2SRussell King (Oracle) reg = MV88E6393X_SERDES_POC_PCS_2500BASEX;
725e5b732a2SRussell King (Oracle)
726e5b732a2SRussell King (Oracle) reg |= MV88E6393X_SERDES_POC_RESET;
727e5b732a2SRussell King (Oracle)
728e5b732a2SRussell King (Oracle) err = mv88e639x_modify(mpcs, MV88E6393X_SERDES_POC,
729e5b732a2SRussell King (Oracle) MV88E6393X_SERDES_POC_PCS_MASK |
730e5b732a2SRussell King (Oracle) MV88E6393X_SERDES_POC_AN |
731e5b732a2SRussell King (Oracle) MV88E6393X_SERDES_POC_RESET, reg);
732e5b732a2SRussell King (Oracle) if (err)
733e5b732a2SRussell King (Oracle) return err;
734e5b732a2SRussell King (Oracle)
735e5b732a2SRussell King (Oracle) return mdiodev_c45_write(&mpcs->mdio, MDIO_MMD_VEND1, 0x8000, 0x58);
736e5b732a2SRussell King (Oracle) }
737e5b732a2SRussell King (Oracle)
mv88e6393x_sgmii_apply_2500basex_an(struct mv88e639x_pcs * mpcs,phy_interface_t interface,bool enable)738e5b732a2SRussell King (Oracle) static int mv88e6393x_sgmii_apply_2500basex_an(struct mv88e639x_pcs *mpcs,
739e5b732a2SRussell King (Oracle) phy_interface_t interface,
740e5b732a2SRussell King (Oracle) bool enable)
741e5b732a2SRussell King (Oracle) {
742e5b732a2SRussell King (Oracle) int err;
743e5b732a2SRussell King (Oracle)
744e5b732a2SRussell King (Oracle) if (interface != PHY_INTERFACE_MODE_2500BASEX)
745e5b732a2SRussell King (Oracle) return 0;
746e5b732a2SRussell King (Oracle)
747e5b732a2SRussell King (Oracle) err = mv88e6393x_fix_2500basex_an(mpcs, enable);
748e5b732a2SRussell King (Oracle) if (err)
749e5b732a2SRussell King (Oracle) dev_err(mpcs->mdio.dev.parent,
750e5b732a2SRussell King (Oracle) "failed to %s 2500basex fix: %pe\n",
751e5b732a2SRussell King (Oracle) enable ? "enable" : "disable", ERR_PTR(err));
752e5b732a2SRussell King (Oracle)
753e5b732a2SRussell King (Oracle) return err;
754e5b732a2SRussell King (Oracle) }
755e5b732a2SRussell King (Oracle)
mv88e6393x_sgmii_pcs_disable(struct phylink_pcs * pcs)756e5b732a2SRussell King (Oracle) static void mv88e6393x_sgmii_pcs_disable(struct phylink_pcs *pcs)
757e5b732a2SRussell King (Oracle) {
758e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
759e5b732a2SRussell King (Oracle)
760e5b732a2SRussell King (Oracle) mv88e639x_sgmii_pcs_disable(pcs);
761e5b732a2SRussell King (Oracle) mv88e6393x_power_lane(mpcs, false);
762e5b732a2SRussell King (Oracle) mv88e6393x_sgmii_apply_2500basex_an(mpcs, mpcs->interface, false);
763e5b732a2SRussell King (Oracle) }
764e5b732a2SRussell King (Oracle)
mv88e6393x_sgmii_pcs_pre_config(struct phylink_pcs * pcs,phy_interface_t interface)765e5b732a2SRussell King (Oracle) static void mv88e6393x_sgmii_pcs_pre_config(struct phylink_pcs *pcs,
766e5b732a2SRussell King (Oracle) phy_interface_t interface)
767e5b732a2SRussell King (Oracle) {
768e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
769e5b732a2SRussell King (Oracle)
770e5b732a2SRussell King (Oracle) mv88e639x_sgmii_pcs_pre_config(pcs, interface);
771e5b732a2SRussell King (Oracle) mv88e6393x_power_lane(mpcs, false);
772e5b732a2SRussell King (Oracle) mv88e6393x_sgmii_apply_2500basex_an(mpcs, mpcs->interface, false);
773e5b732a2SRussell King (Oracle) }
774e5b732a2SRussell King (Oracle)
mv88e6393x_sgmii_pcs_post_config(struct phylink_pcs * pcs,phy_interface_t interface)775e5b732a2SRussell King (Oracle) static int mv88e6393x_sgmii_pcs_post_config(struct phylink_pcs *pcs,
776e5b732a2SRussell King (Oracle) phy_interface_t interface)
777e5b732a2SRussell King (Oracle) {
778e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
779e5b732a2SRussell King (Oracle) int err;
780e5b732a2SRussell King (Oracle)
781e5b732a2SRussell King (Oracle) err = mv88e6393x_erratum_4_8(mpcs);
782e5b732a2SRussell King (Oracle) if (err)
783e5b732a2SRussell King (Oracle) return err;
784e5b732a2SRussell King (Oracle)
785e5b732a2SRussell King (Oracle) err = mv88e6393x_sgmii_apply_2500basex_an(mpcs, interface, true);
786e5b732a2SRussell King (Oracle) if (err)
787e5b732a2SRussell King (Oracle) return err;
788e5b732a2SRussell King (Oracle)
789e5b732a2SRussell King (Oracle) err = mv88e6393x_power_lane(mpcs, true);
790e5b732a2SRussell King (Oracle) if (err)
791e5b732a2SRussell King (Oracle) return err;
792e5b732a2SRussell King (Oracle)
793e5b732a2SRussell King (Oracle) return mv88e639x_sgmii_pcs_post_config(pcs, interface);
794e5b732a2SRussell King (Oracle) }
795e5b732a2SRussell King (Oracle)
796e5b732a2SRussell King (Oracle) static const struct phylink_pcs_ops mv88e6393x_sgmii_pcs_ops = {
797e5b732a2SRussell King (Oracle) .pcs_enable = mv88e639x_sgmii_pcs_enable,
798e5b732a2SRussell King (Oracle) .pcs_disable = mv88e6393x_sgmii_pcs_disable,
799e5b732a2SRussell King (Oracle) .pcs_pre_config = mv88e6393x_sgmii_pcs_pre_config,
800e5b732a2SRussell King (Oracle) .pcs_post_config = mv88e6393x_sgmii_pcs_post_config,
801e5b732a2SRussell King (Oracle) .pcs_get_state = mv88e639x_sgmii_pcs_get_state,
802e5b732a2SRussell King (Oracle) .pcs_an_restart = mv88e639x_sgmii_pcs_an_restart,
803e5b732a2SRussell King (Oracle) .pcs_config = mv88e639x_sgmii_pcs_config,
804e5b732a2SRussell King (Oracle) .pcs_link_up = mv88e639x_sgmii_pcs_link_up,
805e5b732a2SRussell King (Oracle) };
806e5b732a2SRussell King (Oracle)
mv88e6393x_xg_handle_irq(struct mv88e639x_pcs * mpcs)807e5b732a2SRussell King (Oracle) static irqreturn_t mv88e6393x_xg_handle_irq(struct mv88e639x_pcs *mpcs)
808e5b732a2SRussell King (Oracle) {
809e5b732a2SRussell King (Oracle) u16 int_status, stat1;
810e5b732a2SRussell King (Oracle) bool link_down;
811e5b732a2SRussell King (Oracle) int err;
812e5b732a2SRussell King (Oracle)
813e5b732a2SRussell King (Oracle) err = mv88e639x_read(mpcs, MV88E6393X_10G_INT_STATUS, &int_status);
814e5b732a2SRussell King (Oracle) if (err)
815e5b732a2SRussell King (Oracle) return IRQ_NONE;
816e5b732a2SRussell King (Oracle)
817e5b732a2SRussell King (Oracle) if (int_status & MV88E6393X_10G_INT_LINK_CHANGE) {
818e5b732a2SRussell King (Oracle) err = mv88e639x_read(mpcs, MV88E6390_10G_STAT1, &stat1);
819e5b732a2SRussell King (Oracle) if (err)
820e5b732a2SRussell King (Oracle) return IRQ_NONE;
821e5b732a2SRussell King (Oracle)
822e5b732a2SRussell King (Oracle) link_down = !(stat1 & MDIO_STAT1_LSTATUS);
823e5b732a2SRussell King (Oracle)
824e5b732a2SRussell King (Oracle) phylink_pcs_change(&mpcs->xg_pcs, !link_down);
825e5b732a2SRussell King (Oracle)
826e5b732a2SRussell King (Oracle) return IRQ_HANDLED;
827e5b732a2SRussell King (Oracle) }
828e5b732a2SRussell King (Oracle)
829e5b732a2SRussell King (Oracle) return IRQ_NONE;
830e5b732a2SRussell King (Oracle) }
831e5b732a2SRussell King (Oracle)
mv88e6393x_xg_control_irq(struct mv88e639x_pcs * mpcs,bool enable)832e5b732a2SRussell King (Oracle) static int mv88e6393x_xg_control_irq(struct mv88e639x_pcs *mpcs, bool enable)
833e5b732a2SRussell King (Oracle) {
834e5b732a2SRussell King (Oracle) u16 val = 0;
835e5b732a2SRussell King (Oracle)
836e5b732a2SRussell King (Oracle) if (enable)
837e5b732a2SRussell King (Oracle) val = MV88E6393X_10G_INT_LINK_CHANGE;
838e5b732a2SRussell King (Oracle)
839e5b732a2SRussell King (Oracle) return mv88e639x_modify(mpcs, MV88E6393X_10G_INT_ENABLE,
840e5b732a2SRussell King (Oracle) MV88E6393X_10G_INT_LINK_CHANGE, val);
841e5b732a2SRussell King (Oracle) }
842e5b732a2SRussell King (Oracle)
mv88e6393x_xg_pcs_enable(struct phylink_pcs * pcs)843e5b732a2SRussell King (Oracle) static int mv88e6393x_xg_pcs_enable(struct phylink_pcs *pcs)
844e5b732a2SRussell King (Oracle) {
845e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
846e5b732a2SRussell King (Oracle)
847e5b732a2SRussell King (Oracle) mpcs->handle_irq = mv88e6393x_xg_handle_irq;
848e5b732a2SRussell King (Oracle)
849e5b732a2SRussell King (Oracle) return mv88e6393x_xg_control_irq(mpcs, !!mpcs->irq);
850e5b732a2SRussell King (Oracle) }
851e5b732a2SRussell King (Oracle)
mv88e6393x_xg_pcs_disable(struct phylink_pcs * pcs)852e5b732a2SRussell King (Oracle) static void mv88e6393x_xg_pcs_disable(struct phylink_pcs *pcs)
853e5b732a2SRussell King (Oracle) {
854e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
855e5b732a2SRussell King (Oracle)
856e5b732a2SRussell King (Oracle) mv88e6393x_xg_control_irq(mpcs, false);
857e5b732a2SRussell King (Oracle) mv88e639x_xg_pcs_disable(mpcs);
858e5b732a2SRussell King (Oracle) mv88e6393x_power_lane(mpcs, false);
859e5b732a2SRussell King (Oracle) }
860e5b732a2SRussell King (Oracle)
861e5b732a2SRussell King (Oracle) /* The PCS has to be powered down while CMODE is changed */
mv88e6393x_xg_pcs_pre_config(struct phylink_pcs * pcs,phy_interface_t interface)862e5b732a2SRussell King (Oracle) static void mv88e6393x_xg_pcs_pre_config(struct phylink_pcs *pcs,
863e5b732a2SRussell King (Oracle) phy_interface_t interface)
864e5b732a2SRussell King (Oracle) {
865e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
866e5b732a2SRussell King (Oracle)
867e5b732a2SRussell King (Oracle) mv88e639x_xg_pcs_disable(mpcs);
868e5b732a2SRussell King (Oracle) mv88e6393x_power_lane(mpcs, false);
869e5b732a2SRussell King (Oracle) }
870e5b732a2SRussell King (Oracle)
mv88e6393x_xg_pcs_post_config(struct phylink_pcs * pcs,phy_interface_t interface)871e5b732a2SRussell King (Oracle) static int mv88e6393x_xg_pcs_post_config(struct phylink_pcs *pcs,
872e5b732a2SRussell King (Oracle) phy_interface_t interface)
873e5b732a2SRussell King (Oracle) {
874e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
875e5b732a2SRussell King (Oracle) int err;
876e5b732a2SRussell King (Oracle)
877*29561ef0STobias Waldekranz if (interface == PHY_INTERFACE_MODE_10GBASER ||
878*29561ef0STobias Waldekranz interface == PHY_INTERFACE_MODE_USXGMII) {
879e5b732a2SRussell King (Oracle) err = mv88e6393x_erratum_5_2(mpcs);
880e5b732a2SRussell King (Oracle) if (err)
881e5b732a2SRussell King (Oracle) return err;
882e5b732a2SRussell King (Oracle) }
883e5b732a2SRussell King (Oracle)
884e5b732a2SRussell King (Oracle) err = mv88e6393x_power_lane(mpcs, true);
885e5b732a2SRussell King (Oracle) if (err)
886e5b732a2SRussell King (Oracle) return err;
887e5b732a2SRussell King (Oracle)
888e5b732a2SRussell King (Oracle) return mv88e639x_xg_pcs_enable(mpcs);
889e5b732a2SRussell King (Oracle) }
890e5b732a2SRussell King (Oracle)
mv88e6393x_xg_pcs_get_state(struct phylink_pcs * pcs,struct phylink_link_state * state)891*29561ef0STobias Waldekranz static void mv88e6393x_xg_pcs_get_state(struct phylink_pcs *pcs,
892*29561ef0STobias Waldekranz struct phylink_link_state *state)
893*29561ef0STobias Waldekranz {
894*29561ef0STobias Waldekranz struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
895*29561ef0STobias Waldekranz u16 status, lp_status;
896*29561ef0STobias Waldekranz int err;
897*29561ef0STobias Waldekranz
898*29561ef0STobias Waldekranz if (state->interface != PHY_INTERFACE_MODE_USXGMII)
899*29561ef0STobias Waldekranz return mv88e639x_xg_pcs_get_state(pcs, state);
900*29561ef0STobias Waldekranz
901*29561ef0STobias Waldekranz state->link = false;
902*29561ef0STobias Waldekranz
903*29561ef0STobias Waldekranz err = mv88e639x_read(mpcs, MV88E6390_USXGMII_PHY_STATUS, &status);
904*29561ef0STobias Waldekranz err = err ? : mv88e639x_read(mpcs, MV88E6390_USXGMII_LP_STATUS, &lp_status);
905*29561ef0STobias Waldekranz if (err) {
906*29561ef0STobias Waldekranz dev_err(mpcs->mdio.dev.parent,
907*29561ef0STobias Waldekranz "can't read USXGMII status: %pe\n", ERR_PTR(err));
908*29561ef0STobias Waldekranz return;
909*29561ef0STobias Waldekranz }
910*29561ef0STobias Waldekranz
911*29561ef0STobias Waldekranz state->link = !!(status & MDIO_USXGMII_LINK);
912*29561ef0STobias Waldekranz state->an_complete = state->link;
913*29561ef0STobias Waldekranz phylink_decode_usxgmii_word(state, lp_status);
914*29561ef0STobias Waldekranz }
915*29561ef0STobias Waldekranz
916e5b732a2SRussell King (Oracle) static const struct phylink_pcs_ops mv88e6393x_xg_pcs_ops = {
917e5b732a2SRussell King (Oracle) .pcs_enable = mv88e6393x_xg_pcs_enable,
918e5b732a2SRussell King (Oracle) .pcs_disable = mv88e6393x_xg_pcs_disable,
919e5b732a2SRussell King (Oracle) .pcs_pre_config = mv88e6393x_xg_pcs_pre_config,
920e5b732a2SRussell King (Oracle) .pcs_post_config = mv88e6393x_xg_pcs_post_config,
921*29561ef0STobias Waldekranz .pcs_get_state = mv88e6393x_xg_pcs_get_state,
922e5b732a2SRussell King (Oracle) .pcs_config = mv88e639x_xg_pcs_config,
923e5b732a2SRussell King (Oracle) };
924e5b732a2SRussell King (Oracle)
mv88e6393x_pcs_init(struct mv88e6xxx_chip * chip,int port)925e5b732a2SRussell King (Oracle) static int mv88e6393x_pcs_init(struct mv88e6xxx_chip *chip, int port)
926e5b732a2SRussell King (Oracle) {
927e5b732a2SRussell King (Oracle) struct mv88e639x_pcs *mpcs;
928e5b732a2SRussell King (Oracle) struct mii_bus *bus;
929e5b732a2SRussell King (Oracle) struct device *dev;
930e5b732a2SRussell King (Oracle) int lane, err;
931e5b732a2SRussell King (Oracle)
932e5b732a2SRussell King (Oracle) lane = mv88e6xxx_serdes_get_lane(chip, port);
933e5b732a2SRussell King (Oracle) if (lane < 0)
934e5b732a2SRussell King (Oracle) return 0;
935e5b732a2SRussell King (Oracle)
936e5b732a2SRussell King (Oracle) bus = mv88e6xxx_default_mdio_bus(chip);
937e5b732a2SRussell King (Oracle) dev = chip->dev;
938e5b732a2SRussell King (Oracle)
939e5b732a2SRussell King (Oracle) mpcs = mv88e639x_pcs_alloc(dev, bus, lane, port);
940e5b732a2SRussell King (Oracle) if (!mpcs)
941e5b732a2SRussell King (Oracle) return -ENOMEM;
942e5b732a2SRussell King (Oracle)
943e5b732a2SRussell King (Oracle) mpcs->sgmii_pcs.ops = &mv88e6393x_sgmii_pcs_ops;
944e5b732a2SRussell King (Oracle) mpcs->sgmii_pcs.neg_mode = true;
945e5b732a2SRussell King (Oracle) mpcs->xg_pcs.ops = &mv88e6393x_xg_pcs_ops;
946e5b732a2SRussell King (Oracle) mpcs->xg_pcs.neg_mode = true;
947e5b732a2SRussell King (Oracle) mpcs->supports_5g = true;
948e5b732a2SRussell King (Oracle)
949e5b732a2SRussell King (Oracle) err = mv88e6393x_erratum_4_6(mpcs);
950e5b732a2SRussell King (Oracle) if (err)
951e5b732a2SRussell King (Oracle) goto err_free;
952e5b732a2SRussell King (Oracle)
953e5b732a2SRussell King (Oracle) err = mv88e639x_pcs_setup_irq(mpcs, chip, port);
954e5b732a2SRussell King (Oracle) if (err)
955e5b732a2SRussell King (Oracle) goto err_free;
956e5b732a2SRussell King (Oracle)
957e5b732a2SRussell King (Oracle) chip->ports[port].pcs_private = mpcs;
958e5b732a2SRussell King (Oracle)
959e5b732a2SRussell King (Oracle) return 0;
960e5b732a2SRussell King (Oracle)
961e5b732a2SRussell King (Oracle) err_free:
962e5b732a2SRussell King (Oracle) kfree(mpcs);
963e5b732a2SRussell King (Oracle) return err;
964e5b732a2SRussell King (Oracle) }
965e5b732a2SRussell King (Oracle)
966e5b732a2SRussell King (Oracle) const struct mv88e6xxx_pcs_ops mv88e6393x_pcs_ops = {
967e5b732a2SRussell King (Oracle) .pcs_init = mv88e6393x_pcs_init,
968e5b732a2SRussell King (Oracle) .pcs_teardown = mv88e639x_pcs_teardown,
969e5b732a2SRussell King (Oracle) .pcs_select = mv88e639x_pcs_select,
970e5b732a2SRussell King (Oracle) };
971