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