xref: /linux/drivers/net/phy/intel-xway.c (revision f2c53ea949c5048f96b3dbb5a5ee7131ce4ff2de)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2012 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
4  * Copyright (C) 2016 Hauke Mehrtens <hauke@hauke-m.de>
5  */
6 
7 #include <linux/mdio.h>
8 #include <linux/module.h>
9 #include <linux/phy.h>
10 #include <linux/of.h>
11 #include <linux/bitfield.h>
12 
13 #define XWAY_MDIO_ERRCNT		0x15	/* error counter */
14 #define XWAY_MDIO_MIICTRL		0x17	/* mii control */
15 #define XWAY_MDIO_IMASK			0x19	/* interrupt mask */
16 #define XWAY_MDIO_ISTAT			0x1A	/* interrupt status */
17 #define XWAY_MDIO_LED			0x1B	/* led control */
18 
19 #define XWAY_MDIO_GCTRL_TM_MASK		GENMASK(15, 13)
20 #define XWAY_MDIO_GCTRL_TM(mode)	FIELD_PREP(XWAY_MDIO_GCTRL_TM_MASK, (mode))
21 #define XWAY_MDIO_GCTRL_TM_NOP		XWAY_MDIO_GCTRL_TM(0)	/* Normal operation */
22 #define XWAY_MDIO_GCTRL_TM_CDIAG	XWAY_MDIO_GCTRL_TM(6)	/* Cable diagnostics */
23 
24 #define XWAY_MDIO_ERRCNT_SEL		GENMASK(11, 8)
25 #define XWAY_MDIO_ERRCNT_COUNT		GENMASK(7, 0)
26 #define XWAY_MDIO_ERRCNT_SEL_RXERR	0
27 
28 #define XWAY_MDIO_MIICTRL_RXSKEW_MASK	GENMASK(14, 12)
29 #define XWAY_MDIO_MIICTRL_TXSKEW_MASK	GENMASK(10, 8)
30 
31 /* bit 15:12 are reserved */
32 #define XWAY_MDIO_LED_LED3_EN		BIT(11)	/* Enable the integrated function of LED3 */
33 #define XWAY_MDIO_LED_LED2_EN		BIT(10)	/* Enable the integrated function of LED2 */
34 #define XWAY_MDIO_LED_LED1_EN		BIT(9)	/* Enable the integrated function of LED1 */
35 #define XWAY_MDIO_LED_LED0_EN		BIT(8)	/* Enable the integrated function of LED0 */
36 /* bit 7:4 are reserved */
37 #define XWAY_MDIO_LED_LED3_DA		BIT(3)	/* Direct Access to LED3 */
38 #define XWAY_MDIO_LED_LED2_DA		BIT(2)	/* Direct Access to LED2 */
39 #define XWAY_MDIO_LED_LED1_DA		BIT(1)	/* Direct Access to LED1 */
40 #define XWAY_MDIO_LED_LED0_DA		BIT(0)	/* Direct Access to LED0 */
41 
42 #define XWAY_MDIO_INIT_WOL		BIT(15)	/* Wake-On-LAN */
43 #define XWAY_MDIO_INIT_MSRE		BIT(14)
44 #define XWAY_MDIO_INIT_NPRX		BIT(13)
45 #define XWAY_MDIO_INIT_NPTX		BIT(12)
46 #define XWAY_MDIO_INIT_ANE		BIT(11)	/* Auto-Neg error */
47 #define XWAY_MDIO_INIT_ANC		BIT(10)	/* Auto-Neg complete */
48 #define XWAY_MDIO_INIT_ADSC		BIT(5)	/* Link auto-downspeed detect */
49 #define XWAY_MDIO_INIT_MPIPC		BIT(4)
50 #define XWAY_MDIO_INIT_MDIXC		BIT(3)
51 #define XWAY_MDIO_INIT_DXMC		BIT(2)	/* Duplex mode change */
52 #define XWAY_MDIO_INIT_LSPC		BIT(1)	/* Link speed change */
53 #define XWAY_MDIO_INIT_LSTC		BIT(0)	/* Link state change */
54 #define XWAY_MDIO_INIT_MASK		(XWAY_MDIO_INIT_LSTC | \
55 					 XWAY_MDIO_INIT_ADSC)
56 
57 #define ADVERTISED_MPD			BIT(10)	/* Multi-port device */
58 
59 /* LED Configuration */
60 #define XWAY_MMD_LEDCH			0x01E0
61 /* Inverse of SCAN Function */
62 #define  XWAY_MMD_LEDCH_NACS_NONE	0x0000
63 #define  XWAY_MMD_LEDCH_NACS_LINK	0x0001
64 #define  XWAY_MMD_LEDCH_NACS_PDOWN	0x0002
65 #define  XWAY_MMD_LEDCH_NACS_EEE	0x0003
66 #define  XWAY_MMD_LEDCH_NACS_ANEG	0x0004
67 #define  XWAY_MMD_LEDCH_NACS_ABIST	0x0005
68 #define  XWAY_MMD_LEDCH_NACS_CDIAG	0x0006
69 #define  XWAY_MMD_LEDCH_NACS_TEST	0x0007
70 /* Slow Blink Frequency */
71 #define  XWAY_MMD_LEDCH_SBF_F02HZ	0x0000
72 #define  XWAY_MMD_LEDCH_SBF_F04HZ	0x0010
73 #define  XWAY_MMD_LEDCH_SBF_F08HZ	0x0020
74 #define  XWAY_MMD_LEDCH_SBF_F16HZ	0x0030
75 /* Fast Blink Frequency */
76 #define  XWAY_MMD_LEDCH_FBF_F02HZ	0x0000
77 #define  XWAY_MMD_LEDCH_FBF_F04HZ	0x0040
78 #define  XWAY_MMD_LEDCH_FBF_F08HZ	0x0080
79 #define  XWAY_MMD_LEDCH_FBF_F16HZ	0x00C0
80 /* LED Configuration */
81 #define XWAY_MMD_LEDCL			0x01E1
82 /* Complex Blinking Configuration */
83 #define  XWAY_MMD_LEDCH_CBLINK_NONE	0x0000
84 #define  XWAY_MMD_LEDCH_CBLINK_LINK	0x0001
85 #define  XWAY_MMD_LEDCH_CBLINK_PDOWN	0x0002
86 #define  XWAY_MMD_LEDCH_CBLINK_EEE	0x0003
87 #define  XWAY_MMD_LEDCH_CBLINK_ANEG	0x0004
88 #define  XWAY_MMD_LEDCH_CBLINK_ABIST	0x0005
89 #define  XWAY_MMD_LEDCH_CBLINK_CDIAG	0x0006
90 #define  XWAY_MMD_LEDCH_CBLINK_TEST	0x0007
91 /* Complex SCAN Configuration */
92 #define  XWAY_MMD_LEDCH_SCAN_NONE	0x0000
93 #define  XWAY_MMD_LEDCH_SCAN_LINK	0x0010
94 #define  XWAY_MMD_LEDCH_SCAN_PDOWN	0x0020
95 #define  XWAY_MMD_LEDCH_SCAN_EEE	0x0030
96 #define  XWAY_MMD_LEDCH_SCAN_ANEG	0x0040
97 #define  XWAY_MMD_LEDCH_SCAN_ABIST	0x0050
98 #define  XWAY_MMD_LEDCH_SCAN_CDIAG	0x0060
99 #define  XWAY_MMD_LEDCH_SCAN_TEST	0x0070
100 /* Configuration for LED Pin x */
101 #define XWAY_MMD_LED0H			0x01E2
102 /* Fast Blinking Configuration */
103 #define  XWAY_MMD_LEDxH_BLINKF_MASK	0x000F
104 #define  XWAY_MMD_LEDxH_BLINKF_NONE	0x0000
105 #define  XWAY_MMD_LEDxH_BLINKF_LINK10	0x0001
106 #define  XWAY_MMD_LEDxH_BLINKF_LINK100	0x0002
107 #define  XWAY_MMD_LEDxH_BLINKF_LINK10X	0x0003
108 #define  XWAY_MMD_LEDxH_BLINKF_LINK1000	0x0004
109 #define  XWAY_MMD_LEDxH_BLINKF_LINK10_0	0x0005
110 #define  XWAY_MMD_LEDxH_BLINKF_LINK100X	0x0006
111 #define  XWAY_MMD_LEDxH_BLINKF_LINK10XX	0x0007
112 #define  XWAY_MMD_LEDxH_BLINKF_PDOWN	0x0008
113 #define  XWAY_MMD_LEDxH_BLINKF_EEE	0x0009
114 #define  XWAY_MMD_LEDxH_BLINKF_ANEG	0x000A
115 #define  XWAY_MMD_LEDxH_BLINKF_ABIST	0x000B
116 #define  XWAY_MMD_LEDxH_BLINKF_CDIAG	0x000C
117 /* Constant On Configuration */
118 #define  XWAY_MMD_LEDxH_CON_MASK	0x00F0
119 #define  XWAY_MMD_LEDxH_CON_NONE	0x0000
120 #define  XWAY_MMD_LEDxH_CON_LINK10	0x0010
121 #define  XWAY_MMD_LEDxH_CON_LINK100	0x0020
122 #define  XWAY_MMD_LEDxH_CON_LINK10X	0x0030
123 #define  XWAY_MMD_LEDxH_CON_LINK1000	0x0040
124 #define  XWAY_MMD_LEDxH_CON_LINK10_0	0x0050
125 #define  XWAY_MMD_LEDxH_CON_LINK100X	0x0060
126 #define  XWAY_MMD_LEDxH_CON_LINK10XX	0x0070
127 #define  XWAY_MMD_LEDxH_CON_PDOWN	0x0080
128 #define  XWAY_MMD_LEDxH_CON_EEE		0x0090
129 #define  XWAY_MMD_LEDxH_CON_ANEG	0x00A0
130 #define  XWAY_MMD_LEDxH_CON_ABIST	0x00B0
131 #define  XWAY_MMD_LEDxH_CON_CDIAG	0x00C0
132 #define  XWAY_MMD_LEDxH_CON_COPPER	0x00D0
133 #define  XWAY_MMD_LEDxH_CON_FIBER	0x00E0
134 /* Configuration for LED Pin x */
135 #define XWAY_MMD_LED0L			0x01E3
136 /* Pulsing Configuration */
137 #define  XWAY_MMD_LEDxL_PULSE_MASK	0x000F
138 #define  XWAY_MMD_LEDxL_PULSE_NONE	0x0000
139 #define  XWAY_MMD_LEDxL_PULSE_TXACT	0x0001
140 #define  XWAY_MMD_LEDxL_PULSE_RXACT	0x0002
141 #define  XWAY_MMD_LEDxL_PULSE_COL	0x0004
142 /* Slow Blinking Configuration */
143 #define  XWAY_MMD_LEDxL_BLINKS_MASK	0x00F0
144 #define  XWAY_MMD_LEDxL_BLINKS_NONE	0x0000
145 #define  XWAY_MMD_LEDxL_BLINKS_LINK10	0x0010
146 #define  XWAY_MMD_LEDxL_BLINKS_LINK100	0x0020
147 #define  XWAY_MMD_LEDxL_BLINKS_LINK10X	0x0030
148 #define  XWAY_MMD_LEDxL_BLINKS_LINK1000	0x0040
149 #define  XWAY_MMD_LEDxL_BLINKS_LINK10_0	0x0050
150 #define  XWAY_MMD_LEDxL_BLINKS_LINK100X	0x0060
151 #define  XWAY_MMD_LEDxL_BLINKS_LINK10XX	0x0070
152 #define  XWAY_MMD_LEDxL_BLINKS_PDOWN	0x0080
153 #define  XWAY_MMD_LEDxL_BLINKS_EEE	0x0090
154 #define  XWAY_MMD_LEDxL_BLINKS_ANEG	0x00A0
155 #define  XWAY_MMD_LEDxL_BLINKS_ABIST	0x00B0
156 #define  XWAY_MMD_LEDxL_BLINKS_CDIAG	0x00C0
157 #define XWAY_MMD_LED1H			0x01E4
158 #define XWAY_MMD_LED1L			0x01E5
159 #define XWAY_MMD_LED2H			0x01E6
160 #define XWAY_MMD_LED2L			0x01E7
161 #define XWAY_MMD_LED3H			0x01E8
162 #define XWAY_MMD_LED3L			0x01E9
163 
164 #define XWAY_GPHY_MAX_LEDS		3
165 #define XWAY_GPHY_LED_INV(idx)		BIT(12 + (idx))
166 #define XWAY_GPHY_LED_EN(idx)		BIT(8 + (idx))
167 #define XWAY_GPHY_LED_DA(idx)		BIT(idx)
168 #define XWAY_MMD_LEDxH(idx)		(XWAY_MMD_LED0H + 2 * (idx))
169 #define XWAY_MMD_LEDxL(idx)		(XWAY_MMD_LED0L + 2 * (idx))
170 
171 #define PHY_ID_PHY11G_1_3		0x030260D1
172 #define PHY_ID_PHY22F_1_3		0x030260E1
173 #define PHY_ID_PHY11G_1_4		0xD565A400
174 #define PHY_ID_PHY22F_1_4		0xD565A410
175 #define PHY_ID_PHY11G_1_5		0xD565A401
176 #define PHY_ID_PHY22F_1_5		0xD565A411
177 #define PHY_ID_PHY11G_VR9_1_1		0xD565A408
178 #define PHY_ID_PHY22F_VR9_1_1		0xD565A418
179 #define PHY_ID_PHY11G_VR9_1_2		0xD565A409
180 #define PHY_ID_PHY22F_VR9_1_2		0xD565A419
181 
182 struct xway_gphy_priv {
183 	u64 rx_errors;
184 };
185 
186 static const int xway_internal_delay[] = {0, 500, 1000, 1500, 2000, 2500,
187 					 3000, 3500};
188 
xway_gphy_rgmii_init(struct phy_device * phydev)189 static int xway_gphy_rgmii_init(struct phy_device *phydev)
190 {
191 	unsigned int delay_size = ARRAY_SIZE(xway_internal_delay);
192 	s32 int_delay;
193 	int val = 0;
194 
195 	if (!phy_interface_is_rgmii(phydev))
196 		return 0;
197 
198 	/* Existing behavior was to use default pin strapping delay in rgmii
199 	 * mode, but rgmii should have meant no delay.  Warn existing users,
200 	 * but do not change anything at the moment.
201 	 */
202 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
203 		u16 txskew, rxskew;
204 
205 		val = phy_read(phydev, XWAY_MDIO_MIICTRL);
206 		if (val < 0)
207 			return val;
208 
209 		txskew = FIELD_GET(XWAY_MDIO_MIICTRL_TXSKEW_MASK, val);
210 		rxskew = FIELD_GET(XWAY_MDIO_MIICTRL_RXSKEW_MASK, val);
211 
212 		if (txskew > 0 || rxskew > 0)
213 			phydev_warn(phydev,
214 				    "PHY has delays (e.g. via pin strapping), but phy-mode = 'rgmii'\n"
215 				    "Should be 'rgmii-id' to use internal delays txskew:%d ps rxskew:%d ps\n",
216 				    xway_internal_delay[txskew],
217 				    xway_internal_delay[rxskew]);
218 		return 0;
219 	}
220 
221 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
222 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
223 		int_delay = phy_get_internal_delay(phydev, xway_internal_delay,
224 						   delay_size, true);
225 
226 		/* if rx-internal-delay-ps is missing, use default of 2.0 ns */
227 		if (int_delay < 0)
228 			int_delay = 4; /* 2000 ps */
229 
230 		val |= FIELD_PREP(XWAY_MDIO_MIICTRL_RXSKEW_MASK, int_delay);
231 	}
232 
233 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
234 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
235 		int_delay = phy_get_internal_delay(phydev, xway_internal_delay,
236 						   delay_size, false);
237 
238 		/* if tx-internal-delay-ps is missing, use default of 2.0 ns */
239 		if (int_delay < 0)
240 			int_delay = 4; /* 2000 ps */
241 
242 		val |= FIELD_PREP(XWAY_MDIO_MIICTRL_TXSKEW_MASK, int_delay);
243 	}
244 
245 	return phy_modify(phydev, XWAY_MDIO_MIICTRL,
246 			  XWAY_MDIO_MIICTRL_RXSKEW_MASK |
247 			  XWAY_MDIO_MIICTRL_TXSKEW_MASK, val);
248 }
249 
xway_gphy_init_leds(struct phy_device * phydev)250 static int xway_gphy_init_leds(struct phy_device *phydev)
251 {
252 	int err;
253 	u32 ledxh;
254 	u32 ledxl;
255 
256 	/* Ensure that integrated led function is enabled for all leds */
257 	err = phy_write(phydev, XWAY_MDIO_LED,
258 			XWAY_MDIO_LED_LED0_EN |
259 			XWAY_MDIO_LED_LED1_EN |
260 			XWAY_MDIO_LED_LED2_EN |
261 			XWAY_MDIO_LED_LED3_EN);
262 	if (err)
263 		return err;
264 
265 	phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCH,
266 		      XWAY_MMD_LEDCH_NACS_NONE |
267 		      XWAY_MMD_LEDCH_SBF_F02HZ |
268 		      XWAY_MMD_LEDCH_FBF_F16HZ);
269 	phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCL,
270 		      XWAY_MMD_LEDCH_CBLINK_NONE |
271 		      XWAY_MMD_LEDCH_SCAN_NONE);
272 
273 	/**
274 	 * In most cases only one LED is connected to this phy, so
275 	 * configure them all to constant on and pulse mode. LED3 is
276 	 * only available in some packages, leave it in its reset
277 	 * configuration.
278 	 */
279 	ledxh = XWAY_MMD_LEDxH_BLINKF_NONE | XWAY_MMD_LEDxH_CON_LINK10XX;
280 	ledxl = XWAY_MMD_LEDxL_PULSE_TXACT | XWAY_MMD_LEDxL_PULSE_RXACT |
281 		XWAY_MMD_LEDxL_BLINKS_NONE;
282 	phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0H, ledxh);
283 	phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0L, ledxl);
284 	phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1H, ledxh);
285 	phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1L, ledxl);
286 	phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh);
287 	phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl);
288 
289 	return 0;
290 }
291 
xway_gphy_config_init(struct phy_device * phydev)292 static int xway_gphy_config_init(struct phy_device *phydev)
293 {
294 	struct device_node *np;
295 	int err;
296 
297 	/* Mask all interrupts */
298 	err = phy_write(phydev, XWAY_MDIO_IMASK, 0);
299 	if (err)
300 		return err;
301 
302 	/* Use default LED configuration if 'leds' node isn't defined */
303 	np = of_get_child_by_name(phydev->mdio.dev.of_node, "leds");
304 	if (np)
305 		of_node_put(np);
306 	else
307 		xway_gphy_init_leds(phydev);
308 
309 	/* Clear all pending interrupts */
310 	phy_read(phydev, XWAY_MDIO_ISTAT);
311 
312 	err = xway_gphy_rgmii_init(phydev);
313 	if (err)
314 		return err;
315 
316 	/* Count MDI RX errors (SymbolErrorDuringCarrier) */
317 	return phy_write(phydev, XWAY_MDIO_ERRCNT,
318 			 FIELD_PREP(XWAY_MDIO_ERRCNT_SEL, XWAY_MDIO_ERRCNT_SEL_RXERR));
319 }
320 
xway_gphy_probe(struct phy_device * phydev)321 static int xway_gphy_probe(struct phy_device *phydev)
322 {
323 	struct device *dev = &phydev->mdio.dev;
324 	struct xway_gphy_priv *priv;
325 
326 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
327 	if (!priv)
328 		return -ENOMEM;
329 	phydev->priv = priv;
330 
331 	return 0;
332 }
333 
xway_11g_int_config_init(struct phy_device * phydev)334 static int xway_11g_int_config_init(struct phy_device *phydev)
335 {
336 	int err;
337 
338 	/* An issue has been sporadically observed after device power-on on the
339 	 * first link-up attempt in 100BASE-TX mode resulting in either the
340 	 * link-up taking a long time, or failing to link-up altogether.
341 	 *
342 	 * Workaround:
343 	 * After power-on, enable Cable Diagnostic Mode for all ports and
344 	 * disable it.
345 	 */
346 	err = phy_modify(phydev, MII_CTRL1000, XWAY_MDIO_GCTRL_TM_MASK, XWAY_MDIO_GCTRL_TM_CDIAG);
347 	if (err)
348 		return err;
349 	err = phy_modify(phydev, MII_CTRL1000, XWAY_MDIO_GCTRL_TM_MASK, XWAY_MDIO_GCTRL_TM_NOP);
350 	if (err)
351 		return err;
352 
353 	return xway_gphy_config_init(phydev);
354 }
355 
xway_gphy14_config_aneg(struct phy_device * phydev)356 static int xway_gphy14_config_aneg(struct phy_device *phydev)
357 {
358 	int reg, err;
359 
360 	/* Advertise as multi-port device, see IEEE802.3-2002 40.5.1.1 */
361 	/* This is a workaround for an errata in rev < 1.5 devices */
362 	reg = phy_read(phydev, MII_CTRL1000);
363 	reg |= ADVERTISED_MPD;
364 	err = phy_write(phydev, MII_CTRL1000, reg);
365 	if (err)
366 		return err;
367 
368 	return genphy_config_aneg(phydev);
369 }
370 
xway_gphy_ack_interrupt(struct phy_device * phydev)371 static int xway_gphy_ack_interrupt(struct phy_device *phydev)
372 {
373 	int reg;
374 
375 	reg = phy_read(phydev, XWAY_MDIO_ISTAT);
376 	return (reg < 0) ? reg : 0;
377 }
378 
xway_gphy_config_intr(struct phy_device * phydev)379 static int xway_gphy_config_intr(struct phy_device *phydev)
380 {
381 	u16 mask = 0;
382 	int err;
383 
384 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
385 		err = xway_gphy_ack_interrupt(phydev);
386 		if (err)
387 			return err;
388 
389 		mask = XWAY_MDIO_INIT_MASK;
390 		err = phy_write(phydev, XWAY_MDIO_IMASK, mask);
391 	} else {
392 		err = phy_write(phydev, XWAY_MDIO_IMASK, mask);
393 		if (err)
394 			return err;
395 
396 		err = xway_gphy_ack_interrupt(phydev);
397 	}
398 
399 	return err;
400 }
401 
xway_gphy_handle_interrupt(struct phy_device * phydev)402 static irqreturn_t xway_gphy_handle_interrupt(struct phy_device *phydev)
403 {
404 	int irq_status;
405 
406 	irq_status = phy_read(phydev, XWAY_MDIO_ISTAT);
407 	if (irq_status < 0) {
408 		phy_error(phydev);
409 		return IRQ_NONE;
410 	}
411 
412 	if (!(irq_status & XWAY_MDIO_INIT_MASK))
413 		return IRQ_NONE;
414 
415 	phy_trigger_machine(phydev);
416 
417 	return IRQ_HANDLED;
418 }
419 
xway_gphy_led_brightness_set(struct phy_device * phydev,u8 index,enum led_brightness value)420 static int xway_gphy_led_brightness_set(struct phy_device *phydev,
421 					u8 index, enum led_brightness value)
422 {
423 	int ret;
424 
425 	if (index >= XWAY_GPHY_MAX_LEDS)
426 		return -EINVAL;
427 
428 	/* clear EN and set manual LED state */
429 	ret = phy_modify(phydev, XWAY_MDIO_LED,
430 			 ((value == LED_OFF) ? XWAY_GPHY_LED_EN(index) : 0) |
431 			 XWAY_GPHY_LED_DA(index),
432 			 (value == LED_OFF) ? 0 : XWAY_GPHY_LED_DA(index));
433 	if (ret)
434 		return ret;
435 
436 	/* clear HW LED setup */
437 	if (value == LED_OFF) {
438 		ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), 0);
439 		if (ret)
440 			return ret;
441 
442 		return phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), 0);
443 	} else {
444 		return 0;
445 	}
446 }
447 
448 static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
449 						 BIT(TRIGGER_NETDEV_LINK_10) |
450 						 BIT(TRIGGER_NETDEV_LINK_100) |
451 						 BIT(TRIGGER_NETDEV_LINK_1000) |
452 						 BIT(TRIGGER_NETDEV_RX) |
453 						 BIT(TRIGGER_NETDEV_TX));
454 
xway_gphy_led_hw_is_supported(struct phy_device * phydev,u8 index,unsigned long rules)455 static int xway_gphy_led_hw_is_supported(struct phy_device *phydev, u8 index,
456 					 unsigned long rules)
457 {
458 	if (index >= XWAY_GPHY_MAX_LEDS)
459 		return -EINVAL;
460 
461 	/* activity triggers are not possible without combination with a link
462 	 * trigger.
463 	 */
464 	if (rules & (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) &&
465 	    !(rules & (BIT(TRIGGER_NETDEV_LINK) |
466 		       BIT(TRIGGER_NETDEV_LINK_10) |
467 		       BIT(TRIGGER_NETDEV_LINK_100) |
468 		       BIT(TRIGGER_NETDEV_LINK_1000))))
469 		return -EOPNOTSUPP;
470 
471 	/* All other combinations of the supported triggers are allowed */
472 	if (rules & ~supported_triggers)
473 		return -EOPNOTSUPP;
474 
475 	return 0;
476 }
477 
xway_gphy_led_hw_control_get(struct phy_device * phydev,u8 index,unsigned long * rules)478 static int xway_gphy_led_hw_control_get(struct phy_device *phydev, u8 index,
479 					unsigned long *rules)
480 {
481 	int lval, hval;
482 
483 	if (index >= XWAY_GPHY_MAX_LEDS)
484 		return -EINVAL;
485 
486 	hval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index));
487 	if (hval < 0)
488 		return hval;
489 
490 	lval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index));
491 	if (lval < 0)
492 		return lval;
493 
494 	if (hval & XWAY_MMD_LEDxH_CON_LINK10)
495 		*rules |= BIT(TRIGGER_NETDEV_LINK_10);
496 
497 	if (hval & XWAY_MMD_LEDxH_CON_LINK100)
498 		*rules |= BIT(TRIGGER_NETDEV_LINK_100);
499 
500 	if (hval & XWAY_MMD_LEDxH_CON_LINK1000)
501 		*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
502 
503 	if ((hval & XWAY_MMD_LEDxH_CON_LINK10) &&
504 	    (hval & XWAY_MMD_LEDxH_CON_LINK100) &&
505 	    (hval & XWAY_MMD_LEDxH_CON_LINK1000))
506 		*rules |= BIT(TRIGGER_NETDEV_LINK);
507 
508 	if (lval & XWAY_MMD_LEDxL_PULSE_TXACT)
509 		*rules |= BIT(TRIGGER_NETDEV_TX);
510 
511 	if (lval & XWAY_MMD_LEDxL_PULSE_RXACT)
512 		*rules |= BIT(TRIGGER_NETDEV_RX);
513 
514 	return 0;
515 }
516 
xway_gphy_led_hw_control_set(struct phy_device * phydev,u8 index,unsigned long rules)517 static int xway_gphy_led_hw_control_set(struct phy_device *phydev, u8 index,
518 					unsigned long rules)
519 {
520 	u16 hval = 0, lval = 0;
521 	int ret;
522 
523 	if (index >= XWAY_GPHY_MAX_LEDS)
524 		return -EINVAL;
525 
526 	if (rules & BIT(TRIGGER_NETDEV_LINK) ||
527 	    rules & BIT(TRIGGER_NETDEV_LINK_10))
528 		hval |= XWAY_MMD_LEDxH_CON_LINK10;
529 
530 	if (rules & BIT(TRIGGER_NETDEV_LINK) ||
531 	    rules & BIT(TRIGGER_NETDEV_LINK_100))
532 		hval |= XWAY_MMD_LEDxH_CON_LINK100;
533 
534 	if (rules & BIT(TRIGGER_NETDEV_LINK) ||
535 	    rules & BIT(TRIGGER_NETDEV_LINK_1000))
536 		hval |= XWAY_MMD_LEDxH_CON_LINK1000;
537 
538 	if (rules & BIT(TRIGGER_NETDEV_TX))
539 		lval |= XWAY_MMD_LEDxL_PULSE_TXACT;
540 
541 	if (rules & BIT(TRIGGER_NETDEV_RX))
542 		lval |= XWAY_MMD_LEDxL_PULSE_RXACT;
543 
544 	ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), hval);
545 	if (ret)
546 		return ret;
547 
548 	ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), lval);
549 	if (ret)
550 		return ret;
551 
552 	return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_EN(index));
553 }
554 
xway_gphy_led_polarity_set(struct phy_device * phydev,int index,unsigned long modes)555 static int xway_gphy_led_polarity_set(struct phy_device *phydev, int index,
556 				      unsigned long modes)
557 {
558 	bool force_active_low = false, force_active_high = false;
559 	u32 mode;
560 
561 	if (index >= XWAY_GPHY_MAX_LEDS)
562 		return -EINVAL;
563 
564 	for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
565 		switch (mode) {
566 		case PHY_LED_ACTIVE_LOW:
567 			force_active_low = true;
568 			break;
569 		case PHY_LED_ACTIVE_HIGH:
570 			force_active_high = true;
571 			break;
572 		default:
573 			return -EINVAL;
574 		}
575 	}
576 
577 	if (force_active_low)
578 		return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index));
579 
580 	if (force_active_high)
581 		return phy_clear_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index));
582 
583 	return -EINVAL;
584 }
585 
xway_gphy_update_stats(struct phy_device * phydev)586 static int xway_gphy_update_stats(struct phy_device *phydev)
587 {
588 	struct xway_gphy_priv *priv = phydev->priv;
589 	int ret;
590 
591 	/* XWAY_MDIO_ERRCNT: 8-bit read-clear counter, SEL set to RXERR */
592 	ret = phy_read(phydev, XWAY_MDIO_ERRCNT);
593 	if (ret < 0)
594 		return ret;
595 
596 	priv->rx_errors += FIELD_GET(XWAY_MDIO_ERRCNT_COUNT, ret);
597 
598 	return 0;
599 }
600 
xway_gphy_get_phy_stats(struct phy_device * phydev,struct ethtool_eth_phy_stats * eth_stats,struct ethtool_phy_stats * stats)601 static void xway_gphy_get_phy_stats(struct phy_device *phydev,
602 				    struct ethtool_eth_phy_stats *eth_stats,
603 				    struct ethtool_phy_stats *stats)
604 {
605 	struct xway_gphy_priv *priv = phydev->priv;
606 
607 	eth_stats->SymbolErrorDuringCarrier = priv->rx_errors;
608 	stats->rx_errors = priv->rx_errors;
609 }
610 
611 static struct phy_driver xway_gphy[] = {
612 	{
613 		.phy_id		= PHY_ID_PHY11G_1_3,
614 		.phy_id_mask	= 0xffffffff,
615 		.name		= "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.3",
616 		/* PHY_GBIT_FEATURES */
617 		.config_init	= xway_gphy_config_init,
618 		.probe		= xway_gphy_probe,
619 		.config_aneg	= xway_gphy14_config_aneg,
620 		.handle_interrupt = xway_gphy_handle_interrupt,
621 		.config_intr	= xway_gphy_config_intr,
622 		.suspend	= genphy_suspend,
623 		.resume		= genphy_resume,
624 		.led_brightness_set = xway_gphy_led_brightness_set,
625 		.led_hw_is_supported = xway_gphy_led_hw_is_supported,
626 		.led_hw_control_get = xway_gphy_led_hw_control_get,
627 		.led_hw_control_set = xway_gphy_led_hw_control_set,
628 		.led_polarity_set = xway_gphy_led_polarity_set,
629 		.update_stats	= xway_gphy_update_stats,
630 		.get_phy_stats	= xway_gphy_get_phy_stats,
631 	}, {
632 		.phy_id		= PHY_ID_PHY22F_1_3,
633 		.phy_id_mask	= 0xffffffff,
634 		.name		= "Intel XWAY PHY22F (PEF 7061) v1.3",
635 		/* PHY_BASIC_FEATURES */
636 		.config_init	= xway_gphy_config_init,
637 		.probe		= xway_gphy_probe,
638 		.config_aneg	= xway_gphy14_config_aneg,
639 		.handle_interrupt = xway_gphy_handle_interrupt,
640 		.config_intr	= xway_gphy_config_intr,
641 		.suspend	= genphy_suspend,
642 		.resume		= genphy_resume,
643 		.led_brightness_set = xway_gphy_led_brightness_set,
644 		.led_hw_is_supported = xway_gphy_led_hw_is_supported,
645 		.led_hw_control_get = xway_gphy_led_hw_control_get,
646 		.led_hw_control_set = xway_gphy_led_hw_control_set,
647 		.led_polarity_set = xway_gphy_led_polarity_set,
648 		.update_stats	= xway_gphy_update_stats,
649 		.get_phy_stats	= xway_gphy_get_phy_stats,
650 	}, {
651 		.phy_id		= PHY_ID_PHY11G_1_4,
652 		.phy_id_mask	= 0xffffffff,
653 		.name		= "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.4",
654 		/* PHY_GBIT_FEATURES */
655 		.config_init	= xway_gphy_config_init,
656 		.probe		= xway_gphy_probe,
657 		.config_aneg	= xway_gphy14_config_aneg,
658 		.handle_interrupt = xway_gphy_handle_interrupt,
659 		.config_intr	= xway_gphy_config_intr,
660 		.suspend	= genphy_suspend,
661 		.resume		= genphy_resume,
662 		.led_brightness_set = xway_gphy_led_brightness_set,
663 		.led_hw_is_supported = xway_gphy_led_hw_is_supported,
664 		.led_hw_control_get = xway_gphy_led_hw_control_get,
665 		.led_hw_control_set = xway_gphy_led_hw_control_set,
666 		.led_polarity_set = xway_gphy_led_polarity_set,
667 		.update_stats	= xway_gphy_update_stats,
668 		.get_phy_stats	= xway_gphy_get_phy_stats,
669 	}, {
670 		.phy_id		= PHY_ID_PHY22F_1_4,
671 		.phy_id_mask	= 0xffffffff,
672 		.name		= "Intel XWAY PHY22F (PEF 7061) v1.4",
673 		/* PHY_BASIC_FEATURES */
674 		.config_init	= xway_gphy_config_init,
675 		.probe		= xway_gphy_probe,
676 		.config_aneg	= xway_gphy14_config_aneg,
677 		.handle_interrupt = xway_gphy_handle_interrupt,
678 		.config_intr	= xway_gphy_config_intr,
679 		.suspend	= genphy_suspend,
680 		.resume		= genphy_resume,
681 		.led_brightness_set = xway_gphy_led_brightness_set,
682 		.led_hw_is_supported = xway_gphy_led_hw_is_supported,
683 		.led_hw_control_get = xway_gphy_led_hw_control_get,
684 		.led_hw_control_set = xway_gphy_led_hw_control_set,
685 		.led_polarity_set = xway_gphy_led_polarity_set,
686 		.update_stats	= xway_gphy_update_stats,
687 		.get_phy_stats	= xway_gphy_get_phy_stats,
688 	}, {
689 		.phy_id		= PHY_ID_PHY11G_1_5,
690 		.phy_id_mask	= 0xffffffff,
691 		.name		= "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6",
692 		/* PHY_GBIT_FEATURES */
693 		.config_init	= xway_gphy_config_init,
694 		.probe		= xway_gphy_probe,
695 		.handle_interrupt = xway_gphy_handle_interrupt,
696 		.config_intr	= xway_gphy_config_intr,
697 		.suspend	= genphy_suspend,
698 		.resume		= genphy_resume,
699 		.led_brightness_set = xway_gphy_led_brightness_set,
700 		.led_hw_is_supported = xway_gphy_led_hw_is_supported,
701 		.led_hw_control_get = xway_gphy_led_hw_control_get,
702 		.led_hw_control_set = xway_gphy_led_hw_control_set,
703 		.led_polarity_set = xway_gphy_led_polarity_set,
704 		.update_stats	= xway_gphy_update_stats,
705 		.get_phy_stats	= xway_gphy_get_phy_stats,
706 	}, {
707 		.phy_id		= PHY_ID_PHY22F_1_5,
708 		.phy_id_mask	= 0xffffffff,
709 		.name		= "Intel XWAY PHY22F (PEF 7061) v1.5 / v1.6",
710 		/* PHY_BASIC_FEATURES */
711 		.config_init	= xway_gphy_config_init,
712 		.probe		= xway_gphy_probe,
713 		.handle_interrupt = xway_gphy_handle_interrupt,
714 		.config_intr	= xway_gphy_config_intr,
715 		.suspend	= genphy_suspend,
716 		.resume		= genphy_resume,
717 		.led_brightness_set = xway_gphy_led_brightness_set,
718 		.led_hw_is_supported = xway_gphy_led_hw_is_supported,
719 		.led_hw_control_get = xway_gphy_led_hw_control_get,
720 		.led_hw_control_set = xway_gphy_led_hw_control_set,
721 		.led_polarity_set = xway_gphy_led_polarity_set,
722 		.update_stats	= xway_gphy_update_stats,
723 		.get_phy_stats	= xway_gphy_get_phy_stats,
724 	}, {
725 		.phy_id		= PHY_ID_PHY11G_VR9_1_1,
726 		.phy_id_mask	= 0xffffffff,
727 		.name		= "Intel XWAY PHY11G (xRX v1.1 integrated)",
728 		/* PHY_GBIT_FEATURES */
729 		.config_init	= xway_gphy_config_init,
730 		.probe		= xway_gphy_probe,
731 		.handle_interrupt = xway_gphy_handle_interrupt,
732 		.config_intr	= xway_gphy_config_intr,
733 		.suspend	= genphy_suspend,
734 		.resume		= genphy_resume,
735 		.led_brightness_set = xway_gphy_led_brightness_set,
736 		.led_hw_is_supported = xway_gphy_led_hw_is_supported,
737 		.led_hw_control_get = xway_gphy_led_hw_control_get,
738 		.led_hw_control_set = xway_gphy_led_hw_control_set,
739 		.led_polarity_set = xway_gphy_led_polarity_set,
740 		.update_stats	= xway_gphy_update_stats,
741 		.get_phy_stats	= xway_gphy_get_phy_stats,
742 	}, {
743 		.phy_id		= PHY_ID_PHY22F_VR9_1_1,
744 		.phy_id_mask	= 0xffffffff,
745 		.name		= "Intel XWAY PHY22F (xRX v1.1 integrated)",
746 		/* PHY_BASIC_FEATURES */
747 		.config_init	= xway_gphy_config_init,
748 		.probe		= xway_gphy_probe,
749 		.handle_interrupt = xway_gphy_handle_interrupt,
750 		.config_intr	= xway_gphy_config_intr,
751 		.suspend	= genphy_suspend,
752 		.resume		= genphy_resume,
753 		.led_brightness_set = xway_gphy_led_brightness_set,
754 		.led_hw_is_supported = xway_gphy_led_hw_is_supported,
755 		.led_hw_control_get = xway_gphy_led_hw_control_get,
756 		.led_hw_control_set = xway_gphy_led_hw_control_set,
757 		.led_polarity_set = xway_gphy_led_polarity_set,
758 		.update_stats	= xway_gphy_update_stats,
759 		.get_phy_stats	= xway_gphy_get_phy_stats,
760 	}, {
761 		.phy_id		= PHY_ID_PHY11G_VR9_1_2,
762 		.phy_id_mask	= 0xffffffff,
763 		.name		= "Intel XWAY PHY11G (xRX v1.2 integrated)",
764 		/* PHY_GBIT_FEATURES */
765 		.config_init	= xway_11g_int_config_init,
766 		.probe		= xway_gphy_probe,
767 		.handle_interrupt = xway_gphy_handle_interrupt,
768 		.config_intr	= xway_gphy_config_intr,
769 		.suspend	= genphy_suspend,
770 		.resume		= genphy_resume,
771 		.led_brightness_set = xway_gphy_led_brightness_set,
772 		.led_hw_is_supported = xway_gphy_led_hw_is_supported,
773 		.led_hw_control_get = xway_gphy_led_hw_control_get,
774 		.led_hw_control_set = xway_gphy_led_hw_control_set,
775 		.led_polarity_set = xway_gphy_led_polarity_set,
776 		.update_stats	= xway_gphy_update_stats,
777 		.get_phy_stats	= xway_gphy_get_phy_stats,
778 	}, {
779 		.phy_id		= PHY_ID_PHY22F_VR9_1_2,
780 		.phy_id_mask	= 0xffffffff,
781 		.name		= "Intel XWAY PHY22F (xRX v1.2 integrated)",
782 		/* PHY_BASIC_FEATURES */
783 		.config_init	= xway_gphy_config_init,
784 		.probe		= xway_gphy_probe,
785 		.handle_interrupt = xway_gphy_handle_interrupt,
786 		.config_intr	= xway_gphy_config_intr,
787 		.suspend	= genphy_suspend,
788 		.resume		= genphy_resume,
789 		.led_brightness_set = xway_gphy_led_brightness_set,
790 		.led_hw_is_supported = xway_gphy_led_hw_is_supported,
791 		.led_hw_control_get = xway_gphy_led_hw_control_get,
792 		.led_hw_control_set = xway_gphy_led_hw_control_set,
793 		.led_polarity_set = xway_gphy_led_polarity_set,
794 		.update_stats	= xway_gphy_update_stats,
795 		.get_phy_stats	= xway_gphy_get_phy_stats,
796 	},
797 };
798 module_phy_driver(xway_gphy);
799 
800 static const struct mdio_device_id __maybe_unused xway_gphy_tbl[] = {
801 	{ PHY_ID_PHY11G_1_3, 0xffffffff },
802 	{ PHY_ID_PHY22F_1_3, 0xffffffff },
803 	{ PHY_ID_PHY11G_1_4, 0xffffffff },
804 	{ PHY_ID_PHY22F_1_4, 0xffffffff },
805 	{ PHY_ID_PHY11G_1_5, 0xffffffff },
806 	{ PHY_ID_PHY22F_1_5, 0xffffffff },
807 	{ PHY_ID_PHY11G_VR9_1_1, 0xffffffff },
808 	{ PHY_ID_PHY22F_VR9_1_1, 0xffffffff },
809 	{ PHY_ID_PHY11G_VR9_1_2, 0xffffffff },
810 	{ PHY_ID_PHY22F_VR9_1_2, 0xffffffff },
811 	{ }
812 };
813 MODULE_DEVICE_TABLE(mdio, xway_gphy_tbl);
814 
815 MODULE_DESCRIPTION("Intel XWAY PHY driver");
816 MODULE_LICENSE("GPL");
817