1/**************************************************************************
2SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3
4Copyright (c) 2009 Chelsio Inc.
5All rights reserved.
6
7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are met:
9
10 1. Redistributions of source code must retain the above copyright notice,
11    this list of conditions and the following disclaimer.
12
13 2. Neither the name of the Chelsio Corporation nor the names of its
14    contributors may be used to endorse or promote products derived from
15    this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27POSSIBILITY OF SUCH DAMAGE.
28
29***************************************************************************/
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#include <cxgb_include.h>
35
36#undef msleep
37#define msleep t3_os_sleep
38
39enum {
40	/* MDIO_DEV_PMA_PMD registers */
41	AQ_LINK_STAT	= 0xe800,
42
43	/* MDIO_DEV_XGXS registers */
44	AQ_XAUI_RX_CFG	= 0xc400,
45	AQ_XAUI_KX_CFG	= 0xc440,
46	AQ_XAUI_TX_CFG	= 0xe400,
47
48	/* MDIO_DEV_ANEG registers */
49	AQ_100M_CTRL	= 0x0010,
50	AQ_10G_CTRL	= 0x0020,
51	AQ_1G_CTRL	= 0xc400,
52	AQ_ANEG_STAT	= 0xc800,
53
54	/* MDIO_DEV_VEND1 registers */
55	AQ_FW_VERSION	= 0x0020,
56	AQ_THERMAL_THR	= 0xc421,
57	AQ_THERMAL1	= 0xc820,
58	AQ_THERMAL2	= 0xc821,
59	AQ_IFLAG_GLOBAL	= 0xfc00,
60	AQ_IMASK_GLOBAL	= 0xff00,
61};
62
63#define AQBIT(x)	(1 << (0x##x))
64#define ADV_1G_FULL	AQBIT(f)
65#define ADV_1G_HALF	AQBIT(e)
66#define ADV_10G_FULL	AQBIT(c)
67
68#define AQ_WRITE_REGS(phy, regs) do { \
69	int i; \
70	for (i = 0; i < ARRAY_SIZE(regs); i++) { \
71		(void) mdio_write(phy, regs[i].mmd, regs[i].reg, regs[i].val); \
72	} \
73} while (0)
74#define AQ_READ_REGS(phy, regs) do { \
75	unsigned i, v; \
76	for (i = 0; i < ARRAY_SIZE(regs); i++) { \
77		(void) mdio_read(phy, regs[i].mmd, regs[i].reg, &v); \
78	} \
79} while (0)
80
81/*
82 * Return value is temperature in celcius, 0xffff for error or don't know.
83 */
84static int
85aq100x_temperature(struct cphy *phy)
86{
87	unsigned int v;
88
89	if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL2, &v) ||
90	    v == 0xffff || (v & 1) != 1)
91		return (0xffff);
92
93	if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL1, &v))
94		return (0xffff);
95
96	return ((int)((signed char)(v >> 8)));
97}
98
99static int
100aq100x_set_defaults(struct cphy *phy)
101{
102	return mdio_write(phy, MDIO_DEV_VEND1, AQ_THERMAL_THR, 0x6c00);
103}
104
105static int
106aq100x_reset(struct cphy *phy, int wait)
107{
108	int err;
109	err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
110	if (!err)
111		err = aq100x_set_defaults(phy);
112	return (err);
113}
114
115static int
116aq100x_intr_enable(struct cphy *phy)
117{
118	struct {
119		int mmd;
120		int reg;
121		int val;
122	} imasks[] = {
123		{MDIO_DEV_VEND1, 0xd400, AQBIT(e)},
124		{MDIO_DEV_VEND1, 0xff01, AQBIT(2)},
125		{MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, AQBIT(0)}
126	};
127
128	AQ_WRITE_REGS(phy, imasks);
129
130	return (0);
131}
132
133static int
134aq100x_intr_disable(struct cphy *phy)
135{
136	struct {
137		int mmd;
138		int reg;
139		int val;
140	} imasks[] = {
141		{MDIO_DEV_VEND1, 0xd400, 0},
142		{MDIO_DEV_VEND1, 0xff01, 0},
143		{MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, 0}
144	};
145
146	AQ_WRITE_REGS(phy, imasks);
147
148	return (0);
149}
150
151static int
152aq100x_intr_clear(struct cphy *phy)
153{
154	struct {
155		int mmd;
156		int reg;
157	} iclr[] = {
158		{MDIO_DEV_VEND1, 0xcc00},
159		{MDIO_DEV_VEND1, AQ_IMASK_GLOBAL} /* needed? */
160	};
161
162	AQ_READ_REGS(phy, iclr);
163
164	return (0);
165}
166
167static int
168aq100x_vendor_intr(struct cphy *phy, int *rc)
169{
170	int err;
171	unsigned int cause, v;
172
173	err = mdio_read(phy, MDIO_DEV_VEND1, 0xfc01, &cause);
174	if (err)
175		return (err);
176
177	if (cause & AQBIT(2)) {
178		err = mdio_read(phy, MDIO_DEV_VEND1, 0xcc00, &v);
179		if (err)
180			return (err);
181
182		if (v & AQBIT(e)) {
183			CH_WARN(phy->adapter, "PHY%d: temperature is now %dC\n",
184			    phy->addr, aq100x_temperature(phy));
185
186			t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN,
187			    phy->addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL, 0);
188
189			*rc |= cphy_cause_alarm;
190		}
191
192		cause &= ~4;
193	}
194
195	if (cause)
196		CH_WARN(phy->adapter, "PHY%d: unhandled vendor interrupt"
197		    " (0x%x)\n", phy->addr, cause);
198
199	return (0);
200
201}
202
203static int
204aq100x_intr_handler(struct cphy *phy)
205{
206	int err, rc = 0;
207	unsigned int cause;
208
209	err = mdio_read(phy, MDIO_DEV_VEND1, AQ_IFLAG_GLOBAL, &cause);
210	if (err)
211		return (err);
212
213	if (cause & AQBIT(0)) {
214		err = aq100x_vendor_intr(phy, &rc);
215		if (err)
216			return (err);
217		cause &= ~AQBIT(0);
218	}
219
220	if (cause)
221		CH_WARN(phy->adapter, "PHY%d: unhandled interrupt (0x%x)\n",
222		    phy->addr, cause);
223
224	return (rc);
225}
226
227static int
228aq100x_power_down(struct cphy *phy, int off)
229{
230	int err, wait = 500;
231	unsigned int v;
232
233	err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, BMCR_PDOWN,
234	    off ? BMCR_PDOWN : 0);
235	if (err || off)
236		return (err);
237
238	msleep(300);
239	do {
240		err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
241		if (err)
242			return (err);
243		v &= BMCR_RESET;
244		if (v)
245			msleep(10);
246	} while (v && --wait);
247	if (v) {
248		CH_WARN(phy->adapter, "PHY%d: power-up timed out (0x%x).\n",
249		    phy->addr, v);
250		return (ETIMEDOUT);
251	}
252
253	return (0);
254}
255
256static int
257aq100x_autoneg_enable(struct cphy *phy)
258{
259	int err;
260
261	err = aq100x_power_down(phy, 0);
262	if (!err)
263		err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR,
264		    BMCR_RESET, BMCR_ANENABLE | BMCR_ANRESTART);
265
266	return (err);
267}
268
269static int
270aq100x_autoneg_restart(struct cphy *phy)
271{
272	return aq100x_autoneg_enable(phy);
273}
274
275static int
276aq100x_advertise(struct cphy *phy, unsigned int advertise_map)
277{
278	unsigned int adv;
279	int err;
280
281	/* 10G advertisement */
282	adv = 0;
283	if (advertise_map & ADVERTISED_10000baseT_Full)
284		adv |= ADV_10G_FULL;
285	err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_10G_CTRL,
286				  ADV_10G_FULL, adv);
287	if (err)
288		return (err);
289
290	/* 1G advertisement */
291	adv = 0;
292	if (advertise_map & ADVERTISED_1000baseT_Full)
293		adv |= ADV_1G_FULL;
294	if (advertise_map & ADVERTISED_1000baseT_Half)
295		adv |= ADV_1G_HALF;
296	err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_1G_CTRL,
297				  ADV_1G_FULL | ADV_1G_HALF, adv);
298	if (err)
299		return (err);
300
301	/* 100M, pause advertisement */
302	adv = 0;
303	if (advertise_map & ADVERTISED_100baseT_Half)
304		adv |= ADVERTISE_100HALF;
305	if (advertise_map & ADVERTISED_100baseT_Full)
306		adv |= ADVERTISE_100FULL;
307	if (advertise_map & ADVERTISED_Pause)
308		adv |= ADVERTISE_PAUSE_CAP;
309	if (advertise_map & ADVERTISED_Asym_Pause)
310		adv |= ADVERTISE_PAUSE_ASYM;
311	err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_100M_CTRL, 0xfe0, adv);
312
313	return (err);
314}
315
316static int
317aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable)
318{
319	return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
320				   BMCR_LOOPBACK, enable ? BMCR_LOOPBACK : 0);
321}
322
323static int
324aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex)
325{
326	int err, set;
327
328	if (speed == SPEED_100)
329		set = BMCR_SPEED100;
330	else if (speed == SPEED_1000)
331		set = BMCR_SPEED1000;
332	else if (speed == SPEED_10000)
333		set = BMCR_SPEED1000 | BMCR_SPEED100;
334	else
335		return (EINVAL);
336
337	if (duplex != DUPLEX_FULL)
338		return (EINVAL);
339
340	err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR,
341	    BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART, 0);
342	if (err)
343		return (err);
344
345	err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
346	    BMCR_SPEED1000 | BMCR_SPEED100, set);
347	if (err)
348		return (err);
349
350	return (0);
351}
352
353static int
354aq100x_get_link_status(struct cphy *phy, int *link_state, int *speed, int *duplex,
355		       int *fc)
356{
357	int err;
358	unsigned int v, link = 0;
359
360	err = mdio_read(phy, MDIO_DEV_PMA_PMD, AQ_LINK_STAT, &v);
361	if (err)
362		return (err);
363	if (v == 0xffff || !(v & 1))
364		goto done;
365
366	err = mdio_read(phy, MDIO_DEV_ANEG, MII_BMCR, &v);
367	if (err)
368		return (err);
369	if (v & 0x8000)
370		goto done;
371	if (v & BMCR_ANENABLE) {
372
373		err = mdio_read(phy, MDIO_DEV_ANEG, 1, &v);
374		if (err)
375			return (err);
376		if ((v & 0x20) == 0)
377			goto done;
378
379		err = mdio_read(phy, MDIO_DEV_ANEG, AQ_ANEG_STAT, &v);
380		if (err)
381			return (err);
382
383		if (speed) {
384			switch (v & 0x6) {
385			case 0x6: *speed = SPEED_10000;
386				break;
387			case 0x4: *speed = SPEED_1000;
388				break;
389			case 0x2: *speed = SPEED_100;
390				break;
391			case 0x0: *speed = SPEED_10;
392				break;
393			}
394		}
395
396		if (duplex)
397			*duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF;
398
399		if (fc) {
400			unsigned int lpa, adv;
401			err = mdio_read(phy, MDIO_DEV_ANEG, 0x13, &lpa);
402			if (!err)
403				err = mdio_read(phy, MDIO_DEV_ANEG,
404				    AQ_100M_CTRL, &adv);
405			if (err)
406				return err;
407
408			if (lpa & adv & ADVERTISE_PAUSE_CAP)
409				*fc = PAUSE_RX | PAUSE_TX;
410			else if (lpa & ADVERTISE_PAUSE_CAP &&
411			    lpa & ADVERTISE_PAUSE_ASYM &&
412			    adv & ADVERTISE_PAUSE_ASYM)
413				*fc = PAUSE_TX;
414			else if (lpa & ADVERTISE_PAUSE_ASYM &&
415			    adv & ADVERTISE_PAUSE_CAP)
416				*fc = PAUSE_RX;
417			else
418				*fc = 0;
419		}
420
421	} else {
422		err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
423		if (err)
424			return (err);
425
426		v &= BMCR_SPEED1000 | BMCR_SPEED100;
427		if (speed) {
428			if (v == (BMCR_SPEED1000 | BMCR_SPEED100))
429				*speed = SPEED_10000;
430			else if (v == BMCR_SPEED1000)
431				*speed = SPEED_1000;
432			else if (v == BMCR_SPEED100)
433				*speed = SPEED_100;
434			else
435				*speed = SPEED_10;
436		}
437
438		if (duplex)
439			*duplex = DUPLEX_FULL;
440	}
441
442	link = 1;
443done:
444	if (link_state)
445		*link_state = link ? PHY_LINK_UP : PHY_LINK_DOWN;
446	return (0);
447}
448
449static struct cphy_ops aq100x_ops = {
450	.reset             = aq100x_reset,
451	.intr_enable       = aq100x_intr_enable,
452	.intr_disable      = aq100x_intr_disable,
453	.intr_clear        = aq100x_intr_clear,
454	.intr_handler      = aq100x_intr_handler,
455	.autoneg_enable    = aq100x_autoneg_enable,
456	.autoneg_restart   = aq100x_autoneg_restart,
457	.advertise         = aq100x_advertise,
458	.set_loopback      = aq100x_set_loopback,
459	.set_speed_duplex  = aq100x_set_speed_duplex,
460	.get_link_status   = aq100x_get_link_status,
461	.power_down        = aq100x_power_down,
462};
463
464int
465t3_aq100x_phy_prep(pinfo_t *pinfo, int phy_addr,
466		       const struct mdio_ops *mdio_ops)
467{
468	struct cphy *phy = &pinfo->phy;
469	unsigned int v, v2, gpio, wait;
470	int err;
471	adapter_t *adapter = pinfo->adapter;
472
473	cphy_init(&pinfo->phy, adapter, pinfo, phy_addr, &aq100x_ops, mdio_ops,
474		  SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
475		  SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI |
476		  SUPPORTED_MISC_IRQ, "1000/10GBASE-T");
477
478	/*
479	 * Hard reset the PHY.
480	 */
481	gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL;
482	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0);
483	msleep(1);
484	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio);
485
486	/*
487	 * Give it enough time to load the firmware and get ready for mdio.
488	 */
489	msleep(1000);
490	wait = 500; /* in 10ms increments */
491	do {
492		err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
493		if (err || v == 0xffff) {
494
495			/* Allow prep_adapter to succeed when ffff is read */
496
497			CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n",
498				phy_addr, err, v);
499			goto done;
500		}
501
502		v &= BMCR_RESET;
503		if (v)
504			msleep(10);
505	} while (v && --wait);
506	if (v) {
507		CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n",
508			phy_addr, v);
509
510		goto done; /* let prep_adapter succeed */
511	}
512
513	/* Firmware version check. */
514	(void) mdio_read(phy, MDIO_DEV_VEND1, AQ_FW_VERSION, &v);
515	if (v < 0x115)
516		CH_WARN(adapter, "PHY%d: unknown firmware %d.%d\n", phy_addr,
517		    v >> 8, v & 0xff);
518
519	/* The PHY should start in really-low-power mode. */
520	(void) mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
521	if ((v & BMCR_PDOWN) == 0)
522		CH_WARN(adapter, "PHY%d does not start in low power mode.\n",
523			phy_addr);
524
525	/*
526	 * Verify XAUI and 1000-X settings, but let prep succeed no matter what.
527	 */
528	v = v2 = 0;
529	(void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_RX_CFG, &v);
530	(void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_TX_CFG, &v2);
531	if (v != 0x1b || v2 != 0x1b)
532		CH_WARN(adapter, "PHY%d: incorrect XAUI settings "
533		    "(0x%x, 0x%x).\n", phy_addr, v, v2);
534	v = 0;
535	(void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_KX_CFG, &v);
536	if ((v & 0xf) != 0xf)
537		CH_WARN(adapter, "PHY%d: incorrect 1000-X settings "
538		    "(0x%x).\n", phy_addr, v);
539
540	(void) aq100x_set_defaults(phy);
541done:
542	return (err);
543}
544