xref: /freebsd/sys/dev/cxgb/common/cxgb_vsc8211.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
1b6d90eb7SKip Macy /**************************************************************************
2*4d846d26SWarner Losh SPDX-License-Identifier: BSD-2-Clause
3b6d90eb7SKip Macy 
4b6d90eb7SKip Macy Copyright (c) 2007, Chelsio Inc.
5b6d90eb7SKip Macy All rights reserved.
6b6d90eb7SKip Macy 
7b6d90eb7SKip Macy Redistribution and use in source and binary forms, with or without
8b6d90eb7SKip Macy modification, are permitted provided that the following conditions are met:
9b6d90eb7SKip Macy 
10b6d90eb7SKip Macy  1. Redistributions of source code must retain the above copyright notice,
11b6d90eb7SKip Macy     this list of conditions and the following disclaimer.
12b6d90eb7SKip Macy 
1310faa568SKip Macy  2. Neither the name of the Chelsio Corporation nor the names of its
14b6d90eb7SKip Macy     contributors may be used to endorse or promote products derived from
15b6d90eb7SKip Macy     this software without specific prior written permission.
16b6d90eb7SKip Macy 
17b6d90eb7SKip Macy THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18b6d90eb7SKip Macy AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19b6d90eb7SKip Macy IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20b6d90eb7SKip Macy ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21b6d90eb7SKip Macy LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22b6d90eb7SKip Macy CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23b6d90eb7SKip Macy SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24b6d90eb7SKip Macy INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25b6d90eb7SKip Macy CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26b6d90eb7SKip Macy ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27b6d90eb7SKip Macy POSSIBILITY OF SUCH DAMAGE.
28b6d90eb7SKip Macy 
29b6d90eb7SKip Macy ***************************************************************************/
30b6d90eb7SKip Macy 
31b6d90eb7SKip Macy #include <sys/cdefs.h>
32b6d90eb7SKip Macy __FBSDID("$FreeBSD$");
33b6d90eb7SKip Macy 
3410faa568SKip Macy #include <cxgb_include.h>
35b6d90eb7SKip Macy 
368e10660fSKip Macy #undef msleep
378e10660fSKip Macy #define msleep t3_os_sleep
388e10660fSKip Macy 
39b6d90eb7SKip Macy /* VSC8211 PHY specific registers. */
40b6d90eb7SKip Macy enum {
418e10660fSKip Macy 	VSC8211_SIGDET_CTRL   = 19,
428e10660fSKip Macy 	VSC8211_EXT_CTRL      = 23,
43c01f2b83SNavdeep Parhar 	VSC8211_PHY_CTRL      = 24,
44b6d90eb7SKip Macy 	VSC8211_INTR_ENABLE   = 25,
45b6d90eb7SKip Macy 	VSC8211_INTR_STATUS   = 26,
464af83c8cSKip Macy 	VSC8211_LED_CTRL      = 27,
47b6d90eb7SKip Macy 	VSC8211_AUX_CTRL_STAT = 28,
488e10660fSKip Macy 	VSC8211_EXT_PAGE_AXS  = 31,
49b6d90eb7SKip Macy };
50b6d90eb7SKip Macy 
51b6d90eb7SKip Macy enum {
52b6d90eb7SKip Macy 	VSC_INTR_RX_ERR     = 1 << 0,
53b6d90eb7SKip Macy 	VSC_INTR_MS_ERR     = 1 << 1,  /* master/slave resolution error */
54b6d90eb7SKip Macy 	VSC_INTR_CABLE      = 1 << 2,  /* cable impairment */
55b6d90eb7SKip Macy 	VSC_INTR_FALSE_CARR = 1 << 3,  /* false carrier */
56b6d90eb7SKip Macy 	VSC_INTR_MEDIA_CHG  = 1 << 4,  /* AMS media change */
57b6d90eb7SKip Macy 	VSC_INTR_RX_FIFO    = 1 << 5,  /* Rx FIFO over/underflow */
58b6d90eb7SKip Macy 	VSC_INTR_TX_FIFO    = 1 << 6,  /* Tx FIFO over/underflow */
59b6d90eb7SKip Macy 	VSC_INTR_DESCRAMBL  = 1 << 7,  /* descrambler lock-lost */
60b6d90eb7SKip Macy 	VSC_INTR_SYMBOL_ERR = 1 << 8,  /* symbol error */
61b6d90eb7SKip Macy 	VSC_INTR_NEG_DONE   = 1 << 10, /* autoneg done */
62b6d90eb7SKip Macy 	VSC_INTR_NEG_ERR    = 1 << 11, /* autoneg error */
638e10660fSKip Macy 	VSC_INTR_DPLX_CHG   = 1 << 12, /* duplex change */
64b6d90eb7SKip Macy 	VSC_INTR_LINK_CHG   = 1 << 13, /* link change */
658e10660fSKip Macy 	VSC_INTR_SPD_CHG    = 1 << 14, /* speed change */
66b6d90eb7SKip Macy 	VSC_INTR_ENABLE     = 1 << 15, /* interrupt enable */
67b6d90eb7SKip Macy };
68b6d90eb7SKip Macy 
698e10660fSKip Macy enum {
708e10660fSKip Macy 	VSC_CTRL_CLAUSE37_VIEW = 1 << 4,   /* Switch to Clause 37 view */
718e10660fSKip Macy 	VSC_CTRL_MEDIA_MODE_HI = 0xf000    /* High part of media mode select */
728e10660fSKip Macy };
738e10660fSKip Macy 
74b6d90eb7SKip Macy #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
758e10660fSKip Macy 			   VSC_INTR_DPLX_CHG | VSC_INTR_SPD_CHG | \
76b6d90eb7SKip Macy 	 		   VSC_INTR_NEG_DONE)
77b6d90eb7SKip Macy #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
78b6d90eb7SKip Macy 		   VSC_INTR_ENABLE)
79b6d90eb7SKip Macy 
80b6d90eb7SKip Macy /* PHY specific auxiliary control & status register fields */
81b6d90eb7SKip Macy #define S_ACSR_ACTIPHY_TMR    0
82b6d90eb7SKip Macy #define M_ACSR_ACTIPHY_TMR    0x3
83b6d90eb7SKip Macy #define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
84b6d90eb7SKip Macy 
85b6d90eb7SKip Macy #define S_ACSR_SPEED    3
86b6d90eb7SKip Macy #define M_ACSR_SPEED    0x3
87b6d90eb7SKip Macy #define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
88b6d90eb7SKip Macy 
89b6d90eb7SKip Macy #define S_ACSR_DUPLEX 5
90b6d90eb7SKip Macy #define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
91b6d90eb7SKip Macy 
92b6d90eb7SKip Macy #define S_ACSR_ACTIPHY 6
93b6d90eb7SKip Macy #define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
94b6d90eb7SKip Macy 
95b6d90eb7SKip Macy /*
96b6d90eb7SKip Macy  * Reset the PHY.  This PHY completes reset immediately so we never wait.
97b6d90eb7SKip Macy  */
98b6d90eb7SKip Macy static int vsc8211_reset(struct cphy *cphy, int wait)
99b6d90eb7SKip Macy {
100b6d90eb7SKip Macy 	return t3_phy_reset(cphy, 0, 0);
101b6d90eb7SKip Macy }
102b6d90eb7SKip Macy 
103b6d90eb7SKip Macy static int vsc8211_intr_enable(struct cphy *cphy)
104b6d90eb7SKip Macy {
105b6d90eb7SKip Macy 	return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK);
106b6d90eb7SKip Macy }
107b6d90eb7SKip Macy 
108b6d90eb7SKip Macy static int vsc8211_intr_disable(struct cphy *cphy)
109b6d90eb7SKip Macy {
110b6d90eb7SKip Macy 	return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0);
111b6d90eb7SKip Macy }
112b6d90eb7SKip Macy 
113b6d90eb7SKip Macy static int vsc8211_intr_clear(struct cphy *cphy)
114b6d90eb7SKip Macy {
115b6d90eb7SKip Macy 	u32 val;
116b6d90eb7SKip Macy 
117b6d90eb7SKip Macy 	/* Clear PHY interrupts by reading the register. */
118b6d90eb7SKip Macy 	return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val);
119b6d90eb7SKip Macy }
120b6d90eb7SKip Macy 
121b6d90eb7SKip Macy static int vsc8211_autoneg_enable(struct cphy *cphy)
122b6d90eb7SKip Macy {
123b6d90eb7SKip Macy 	return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
124b6d90eb7SKip Macy 				   BMCR_ANENABLE | BMCR_ANRESTART);
125b6d90eb7SKip Macy }
126b6d90eb7SKip Macy 
127b6d90eb7SKip Macy static int vsc8211_autoneg_restart(struct cphy *cphy)
128b6d90eb7SKip Macy {
129b6d90eb7SKip Macy 	return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
130b6d90eb7SKip Macy 				   BMCR_ANRESTART);
131b6d90eb7SKip Macy }
132b6d90eb7SKip Macy 
133a5eb009bSNavdeep Parhar static int vsc8211_get_link_status(struct cphy *cphy, int *link_state,
134b6d90eb7SKip Macy 				     int *speed, int *duplex, int *fc)
135b6d90eb7SKip Macy {
136b6d90eb7SKip Macy 	unsigned int bmcr, status, lpa, adv;
137b6d90eb7SKip Macy 	int err, sp = -1, dplx = -1, pause = 0;
138b6d90eb7SKip Macy 
139b6d90eb7SKip Macy 	err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
140b6d90eb7SKip Macy 	if (!err)
141b6d90eb7SKip Macy 		err = mdio_read(cphy, 0, MII_BMSR, &status);
142b6d90eb7SKip Macy 	if (err)
143b6d90eb7SKip Macy 		return err;
144b6d90eb7SKip Macy 
145a5eb009bSNavdeep Parhar 	if (link_state) {
146b6d90eb7SKip Macy 		/*
147b6d90eb7SKip Macy 		 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
148b6d90eb7SKip Macy 		 * once more to get the current link state.
149b6d90eb7SKip Macy 		 */
150b6d90eb7SKip Macy 		if (!(status & BMSR_LSTATUS))
151b6d90eb7SKip Macy 			err = mdio_read(cphy, 0, MII_BMSR, &status);
152b6d90eb7SKip Macy 		if (err)
153b6d90eb7SKip Macy 			return err;
154a5eb009bSNavdeep Parhar 		*link_state = status & BMSR_LSTATUS ? PHY_LINK_UP :
155a5eb009bSNavdeep Parhar 		    PHY_LINK_DOWN;
156b6d90eb7SKip Macy 	}
157b6d90eb7SKip Macy 	if (!(bmcr & BMCR_ANENABLE)) {
158b6d90eb7SKip Macy 		dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
159b6d90eb7SKip Macy 		if (bmcr & BMCR_SPEED1000)
160b6d90eb7SKip Macy 			sp = SPEED_1000;
161b6d90eb7SKip Macy 		else if (bmcr & BMCR_SPEED100)
162b6d90eb7SKip Macy 			sp = SPEED_100;
163b6d90eb7SKip Macy 		else
164b6d90eb7SKip Macy 			sp = SPEED_10;
165b6d90eb7SKip Macy 	} else if (status & BMSR_ANEGCOMPLETE) {
166b6d90eb7SKip Macy 		err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status);
167b6d90eb7SKip Macy 		if (err)
168b6d90eb7SKip Macy 			return err;
169b6d90eb7SKip Macy 
170b6d90eb7SKip Macy 		dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
171b6d90eb7SKip Macy 		sp = G_ACSR_SPEED(status);
172b6d90eb7SKip Macy 		if (sp == 0)
173b6d90eb7SKip Macy 			sp = SPEED_10;
174b6d90eb7SKip Macy 		else if (sp == 1)
175b6d90eb7SKip Macy 			sp = SPEED_100;
176b6d90eb7SKip Macy 		else
177b6d90eb7SKip Macy 			sp = SPEED_1000;
178b6d90eb7SKip Macy 
179b6d90eb7SKip Macy 		if (fc && dplx == DUPLEX_FULL) {
180b6d90eb7SKip Macy 			err = mdio_read(cphy, 0, MII_LPA, &lpa);
181b6d90eb7SKip Macy 			if (!err)
182b6d90eb7SKip Macy 				err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
183b6d90eb7SKip Macy 			if (err)
184b6d90eb7SKip Macy 				return err;
185b6d90eb7SKip Macy 
186b6d90eb7SKip Macy 			if (lpa & adv & ADVERTISE_PAUSE_CAP)
187b6d90eb7SKip Macy 				pause = PAUSE_RX | PAUSE_TX;
188b6d90eb7SKip Macy 			else if ((lpa & ADVERTISE_PAUSE_CAP) &&
189b6d90eb7SKip Macy 				 (lpa & ADVERTISE_PAUSE_ASYM) &&
190b6d90eb7SKip Macy 				 (adv & ADVERTISE_PAUSE_ASYM))
191b6d90eb7SKip Macy 				pause = PAUSE_TX;
192b6d90eb7SKip Macy 			else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
193b6d90eb7SKip Macy 				 (adv & ADVERTISE_PAUSE_CAP))
194b6d90eb7SKip Macy 				pause = PAUSE_RX;
195b6d90eb7SKip Macy 		}
196b6d90eb7SKip Macy 	}
197b6d90eb7SKip Macy 	if (speed)
198b6d90eb7SKip Macy 		*speed = sp;
199b6d90eb7SKip Macy 	if (duplex)
200b6d90eb7SKip Macy 		*duplex = dplx;
201b6d90eb7SKip Macy 	if (fc)
202b6d90eb7SKip Macy 		*fc = pause;
203b6d90eb7SKip Macy 	return 0;
204b6d90eb7SKip Macy }
205b6d90eb7SKip Macy 
206a5eb009bSNavdeep Parhar static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_state,
2078e10660fSKip Macy 					 int *speed, int *duplex, int *fc)
2088e10660fSKip Macy {
2098e10660fSKip Macy 	unsigned int bmcr, status, lpa, adv;
2108e10660fSKip Macy 	int err, sp = -1, dplx = -1, pause = 0;
2118e10660fSKip Macy 
2128e10660fSKip Macy 	err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
2138e10660fSKip Macy 	if (!err)
2148e10660fSKip Macy 		err = mdio_read(cphy, 0, MII_BMSR, &status);
2158e10660fSKip Macy 	if (err)
2168e10660fSKip Macy 		return err;
2178e10660fSKip Macy 
218a5eb009bSNavdeep Parhar 	if (link_state) {
2198e10660fSKip Macy 		/*
2208e10660fSKip Macy 		 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
2218e10660fSKip Macy 		 * once more to get the current link state.
2228e10660fSKip Macy 		 */
2238e10660fSKip Macy 		if (!(status & BMSR_LSTATUS))
2248e10660fSKip Macy 			err = mdio_read(cphy, 0, MII_BMSR, &status);
2258e10660fSKip Macy 		if (err)
2268e10660fSKip Macy 			return err;
227a5eb009bSNavdeep Parhar 		*link_state = status & BMSR_LSTATUS ? PHY_LINK_UP :
228a5eb009bSNavdeep Parhar 		    PHY_LINK_DOWN;
2298e10660fSKip Macy 	}
2308e10660fSKip Macy 	if (!(bmcr & BMCR_ANENABLE)) {
2318e10660fSKip Macy 		dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
2328e10660fSKip Macy 		if (bmcr & BMCR_SPEED1000)
2338e10660fSKip Macy 			sp = SPEED_1000;
2348e10660fSKip Macy 		else if (bmcr & BMCR_SPEED100)
2358e10660fSKip Macy 			sp = SPEED_100;
2368e10660fSKip Macy 		else
2378e10660fSKip Macy 			sp = SPEED_10;
2388e10660fSKip Macy 	} else if (status & BMSR_ANEGCOMPLETE) {
2398e10660fSKip Macy 		err = mdio_read(cphy, 0, MII_LPA, &lpa);
2408e10660fSKip Macy 		if (!err)
2418e10660fSKip Macy 			err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
2428e10660fSKip Macy 		if (err)
2438e10660fSKip Macy 			return err;
2448e10660fSKip Macy 
2458e10660fSKip Macy 		if (adv & lpa & ADVERTISE_1000XFULL) {
2468e10660fSKip Macy 			dplx = DUPLEX_FULL;
2478e10660fSKip Macy 			sp = SPEED_1000;
2488e10660fSKip Macy 		} else if (adv & lpa & ADVERTISE_1000XHALF) {
2498e10660fSKip Macy 			dplx = DUPLEX_HALF;
2508e10660fSKip Macy 			sp = SPEED_1000;
2518e10660fSKip Macy 		}
2528e10660fSKip Macy 
2538e10660fSKip Macy 		if (fc && dplx == DUPLEX_FULL) {
2548e10660fSKip Macy 			if (lpa & adv & ADVERTISE_1000XPAUSE)
2558e10660fSKip Macy 				pause = PAUSE_RX | PAUSE_TX;
2568e10660fSKip Macy 			else if ((lpa & ADVERTISE_1000XPAUSE) &&
2578e10660fSKip Macy 				 (adv & lpa & ADVERTISE_1000XPSE_ASYM))
2588e10660fSKip Macy 				pause = PAUSE_TX;
2598e10660fSKip Macy 			else if ((lpa & ADVERTISE_1000XPSE_ASYM) &&
2608e10660fSKip Macy 				 (adv & ADVERTISE_1000XPAUSE))
2618e10660fSKip Macy 				pause = PAUSE_RX;
2628e10660fSKip Macy 		}
2638e10660fSKip Macy 	}
2648e10660fSKip Macy 	if (speed)
2658e10660fSKip Macy 		*speed = sp;
2668e10660fSKip Macy 	if (duplex)
2678e10660fSKip Macy 		*duplex = dplx;
2688e10660fSKip Macy 	if (fc)
2698e10660fSKip Macy 		*fc = pause;
2708e10660fSKip Macy 	return 0;
2718e10660fSKip Macy }
2728e10660fSKip Macy 
2738e10660fSKip Macy /*
2748e10660fSKip Macy  * Enable/disable auto MDI/MDI-X in forced link speed mode.
2758e10660fSKip Macy  */
2768e10660fSKip Macy static int vsc8211_set_automdi(struct cphy *phy, int enable)
2778e10660fSKip Macy {
2788e10660fSKip Macy 	int err;
2798e10660fSKip Macy 
2808e10660fSKip Macy 	if ((err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0x52b5)) != 0 ||
2818e10660fSKip Macy 	    (err = mdio_write(phy, 0, 18, 0x12)) != 0 ||
2828e10660fSKip Macy 	    (err = mdio_write(phy, 0, 17, enable ? 0x2803 : 0x3003)) != 0 ||
2838e10660fSKip Macy 	    (err = mdio_write(phy, 0, 16, 0x87fa)) != 0 ||
2848e10660fSKip Macy 	    (err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0)) != 0)
2858e10660fSKip Macy 		return err;
2868e10660fSKip Macy 	return 0;
2878e10660fSKip Macy }
2888e10660fSKip Macy 
2898e10660fSKip Macy static int vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex)
2908e10660fSKip Macy {
2918e10660fSKip Macy 	int err;
2928e10660fSKip Macy 
2938e10660fSKip Macy 	err = t3_set_phy_speed_duplex(phy, speed, duplex);
2948e10660fSKip Macy 	if (!err)
2958e10660fSKip Macy 		err = vsc8211_set_automdi(phy, 1);
2968e10660fSKip Macy 	return err;
2978e10660fSKip Macy }
2988e10660fSKip Macy 
299b6d90eb7SKip Macy static int vsc8211_power_down(struct cphy *cphy, int enable)
300b6d90eb7SKip Macy {
301b6d90eb7SKip Macy 	return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
302b6d90eb7SKip Macy 				   enable ? BMCR_PDOWN : 0);
303b6d90eb7SKip Macy }
304b6d90eb7SKip Macy 
305b6d90eb7SKip Macy static int vsc8211_intr_handler(struct cphy *cphy)
306b6d90eb7SKip Macy {
307b6d90eb7SKip Macy 	unsigned int cause;
308b6d90eb7SKip Macy 	int err, cphy_cause = 0;
309b6d90eb7SKip Macy 
310b6d90eb7SKip Macy 	err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause);
311b6d90eb7SKip Macy 	if (err)
312b6d90eb7SKip Macy 		return err;
313b6d90eb7SKip Macy 
314b6d90eb7SKip Macy 	cause &= INTR_MASK;
315b6d90eb7SKip Macy 	if (cause & CFG_CHG_INTR_MASK)
316b6d90eb7SKip Macy 		cphy_cause |= cphy_cause_link_change;
317b6d90eb7SKip Macy 	if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
318b6d90eb7SKip Macy 		cphy_cause |= cphy_cause_fifo_error;
319b6d90eb7SKip Macy 	return cphy_cause;
320b6d90eb7SKip Macy }
321b6d90eb7SKip Macy 
322b6d90eb7SKip Macy #ifdef C99_NOT_SUPPORTED
323b6d90eb7SKip Macy static struct cphy_ops vsc8211_ops = {
324b6d90eb7SKip Macy 	vsc8211_reset,
325b6d90eb7SKip Macy 	vsc8211_intr_enable,
326b6d90eb7SKip Macy 	vsc8211_intr_disable,
327b6d90eb7SKip Macy 	vsc8211_intr_clear,
328b6d90eb7SKip Macy 	vsc8211_intr_handler,
329b6d90eb7SKip Macy 	vsc8211_autoneg_enable,
330b6d90eb7SKip Macy 	vsc8211_autoneg_restart,
331b6d90eb7SKip Macy 	t3_phy_advertise,
332b6d90eb7SKip Macy 	NULL,
3338e10660fSKip Macy 	vsc8211_set_speed_duplex,
334b6d90eb7SKip Macy 	vsc8211_get_link_status,
335b6d90eb7SKip Macy 	vsc8211_power_down,
336b6d90eb7SKip Macy };
3378e10660fSKip Macy 
3388e10660fSKip Macy static struct cphy_ops vsc8211_fiber_ops = {
3398e10660fSKip Macy 	vsc8211_reset,
3408e10660fSKip Macy 	vsc8211_intr_enable,
3418e10660fSKip Macy 	vsc8211_intr_disable,
3428e10660fSKip Macy 	vsc8211_intr_clear,
3438e10660fSKip Macy 	vsc8211_intr_handler,
3448e10660fSKip Macy 	vsc8211_autoneg_enable,
3458e10660fSKip Macy 	vsc8211_autoneg_restart,
3468e10660fSKip Macy 	t3_phy_advertise_fiber,
3478e10660fSKip Macy 	NULL,
3488e10660fSKip Macy 	t3_set_phy_speed_duplex,
3498e10660fSKip Macy 	vsc8211_get_link_status_fiber,
3508e10660fSKip Macy 	vsc8211_power_down,
3518e10660fSKip Macy };
352b6d90eb7SKip Macy #else
353b6d90eb7SKip Macy static struct cphy_ops vsc8211_ops = {
354b6d90eb7SKip Macy 	.reset             = vsc8211_reset,
355b6d90eb7SKip Macy 	.intr_enable       = vsc8211_intr_enable,
356b6d90eb7SKip Macy 	.intr_disable      = vsc8211_intr_disable,
357b6d90eb7SKip Macy 	.intr_clear        = vsc8211_intr_clear,
358b6d90eb7SKip Macy 	.intr_handler      = vsc8211_intr_handler,
359b6d90eb7SKip Macy 	.autoneg_enable    = vsc8211_autoneg_enable,
360b6d90eb7SKip Macy 	.autoneg_restart   = vsc8211_autoneg_restart,
361b6d90eb7SKip Macy 	.advertise         = t3_phy_advertise,
3628e10660fSKip Macy 	.set_speed_duplex  = vsc8211_set_speed_duplex,
363b6d90eb7SKip Macy 	.get_link_status   = vsc8211_get_link_status,
364b6d90eb7SKip Macy 	.power_down        = vsc8211_power_down,
365b6d90eb7SKip Macy };
3668e10660fSKip Macy 
3678e10660fSKip Macy static struct cphy_ops vsc8211_fiber_ops = {
3688e10660fSKip Macy 	.reset             = vsc8211_reset,
3698e10660fSKip Macy 	.intr_enable       = vsc8211_intr_enable,
3708e10660fSKip Macy 	.intr_disable      = vsc8211_intr_disable,
3718e10660fSKip Macy 	.intr_clear        = vsc8211_intr_clear,
3728e10660fSKip Macy 	.intr_handler      = vsc8211_intr_handler,
3738e10660fSKip Macy 	.autoneg_enable    = vsc8211_autoneg_enable,
3748e10660fSKip Macy 	.autoneg_restart   = vsc8211_autoneg_restart,
3758e10660fSKip Macy 	.advertise         = t3_phy_advertise_fiber,
3768e10660fSKip Macy 	.set_speed_duplex  = t3_set_phy_speed_duplex,
3778e10660fSKip Macy 	.get_link_status   = vsc8211_get_link_status_fiber,
3788e10660fSKip Macy 	.power_down        = vsc8211_power_down,
3798e10660fSKip Macy };
380b6d90eb7SKip Macy #endif
381b6d90eb7SKip Macy 
382c01f2b83SNavdeep Parhar #define VSC8211_PHY_CTRL 24
383c01f2b83SNavdeep Parhar 
384c01f2b83SNavdeep Parhar #define S_VSC8211_TXFIFODEPTH    7
385c01f2b83SNavdeep Parhar #define M_VSC8211_TXFIFODEPTH    0x7
386c01f2b83SNavdeep Parhar #define V_VSC8211_TXFIFODEPTH(x) ((x) << S_VSC8211_TXFIFODEPTH)
387c01f2b83SNavdeep Parhar #define G_VSC8211_TXFIFODEPTH(x) (((x) >> S_VSC8211_TXFIFODEPTH) & M_VSC8211_TXFIFODEPTH)
388c01f2b83SNavdeep Parhar 
389c01f2b83SNavdeep Parhar #define S_VSC8211_RXFIFODEPTH    4
390c01f2b83SNavdeep Parhar #define M_VSC8211_RXFIFODEPTH    0x7
391c01f2b83SNavdeep Parhar #define V_VSC8211_RXFIFODEPTH(x) ((x) << S_VSC8211_RXFIFODEPTH)
392c01f2b83SNavdeep Parhar #define G_VSC8211_RXFIFODEPTH(x) (((x) >> S_VSC8211_RXFIFODEPTH) & M_VSC8211_RXFIFODEPTH)
393c01f2b83SNavdeep Parhar 
394c01f2b83SNavdeep Parhar int t3_vsc8211_fifo_depth(adapter_t *adap, unsigned int mtu, int port)
395c01f2b83SNavdeep Parhar {
396c01f2b83SNavdeep Parhar 	/* TX FIFO Depth set bits 9:7 to 100 (IEEE mode) */
397c01f2b83SNavdeep Parhar 	unsigned int val = 4;
398c01f2b83SNavdeep Parhar 	unsigned int currentregval;
399c01f2b83SNavdeep Parhar 	unsigned int regval;
400c01f2b83SNavdeep Parhar 	int err;
401c01f2b83SNavdeep Parhar 
402c01f2b83SNavdeep Parhar 	/* Retrieve the port info structure from adater_t */
403c01f2b83SNavdeep Parhar 	struct port_info *portinfo = adap2pinfo(adap, port);
404c01f2b83SNavdeep Parhar 
405c01f2b83SNavdeep Parhar 	/* What phy is this */
406c01f2b83SNavdeep Parhar 	struct cphy *phy = &portinfo->phy;
407c01f2b83SNavdeep Parhar 
408c01f2b83SNavdeep Parhar 	/* Read the current value of the PHY control Register */
409c01f2b83SNavdeep Parhar 	err = mdio_read(phy, 0, VSC8211_PHY_CTRL, &currentregval);
410c01f2b83SNavdeep Parhar 
411c01f2b83SNavdeep Parhar 	if (err)
412c01f2b83SNavdeep Parhar 		return err;
413c01f2b83SNavdeep Parhar 
414c01f2b83SNavdeep Parhar 	/* IEEE mode supports up to 1518 bytes */
415c01f2b83SNavdeep Parhar 	/* mtu does not contain the header + FCS (18 bytes) */
416c01f2b83SNavdeep Parhar 	if (mtu > 1500)
417c01f2b83SNavdeep Parhar 		/*
418c01f2b83SNavdeep Parhar 		 * If using a packet size > 1500  set TX FIFO Depth bits
419c01f2b83SNavdeep Parhar 		 * 9:7 to 011 (Jumbo packet mode)
420c01f2b83SNavdeep Parhar 		 */
421c01f2b83SNavdeep Parhar 		val = 3;
422c01f2b83SNavdeep Parhar 
423c01f2b83SNavdeep Parhar 	regval = V_VSC8211_TXFIFODEPTH(val) | V_VSC8211_RXFIFODEPTH(val) |
424c01f2b83SNavdeep Parhar 		(currentregval & ~V_VSC8211_TXFIFODEPTH(M_VSC8211_TXFIFODEPTH) &
425c01f2b83SNavdeep Parhar 		~V_VSC8211_RXFIFODEPTH(M_VSC8211_RXFIFODEPTH));
426c01f2b83SNavdeep Parhar 
427c01f2b83SNavdeep Parhar 	return  mdio_write(phy, 0, VSC8211_PHY_CTRL, regval);
428c01f2b83SNavdeep Parhar }
429c01f2b83SNavdeep Parhar 
430c01f2b83SNavdeep Parhar int t3_vsc8211_phy_prep(pinfo_t *pinfo, int phy_addr,
431b6d90eb7SKip Macy 			const struct mdio_ops *mdio_ops)
432b6d90eb7SKip Macy {
433c01f2b83SNavdeep Parhar 	struct cphy *phy = &pinfo->phy;
4348e10660fSKip Macy 	int err;
4358e10660fSKip Macy 	unsigned int val;
4368e10660fSKip Macy 
437c01f2b83SNavdeep Parhar 	cphy_init(&pinfo->phy, pinfo->adapter, pinfo, phy_addr, &vsc8211_ops, mdio_ops,
4388e10660fSKip Macy 		  SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full |
4398e10660fSKip Macy 		  SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII |
4408e10660fSKip Macy 		  SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T");
4418e10660fSKip Macy 	msleep(20);       /* PHY needs ~10ms to start responding to MDIO */
4428e10660fSKip Macy 
4438e10660fSKip Macy 	err = mdio_read(phy, 0, VSC8211_EXT_CTRL, &val);
4448e10660fSKip Macy 	if (err)
4458e10660fSKip Macy 		return err;
4464af83c8cSKip Macy 	if (val & VSC_CTRL_MEDIA_MODE_HI) {
4474af83c8cSKip Macy 		/* copper interface, just need to configure the LEDs */
4484af83c8cSKip Macy 		return mdio_write(phy, 0, VSC8211_LED_CTRL, 0x100);
4494af83c8cSKip Macy 	}
4508e10660fSKip Macy 
4518e10660fSKip Macy 	phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
4528e10660fSKip Macy 		    SUPPORTED_MII | SUPPORTED_FIBRE | SUPPORTED_IRQ;
4538e10660fSKip Macy 	phy->desc = "1000BASE-X";
4548e10660fSKip Macy 	phy->ops = &vsc8211_fiber_ops;
4558e10660fSKip Macy 
4568e10660fSKip Macy 	if ((err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 1)) != 0 ||
4578e10660fSKip Macy 	    (err = mdio_write(phy, 0, VSC8211_SIGDET_CTRL, 1)) != 0 ||
4588e10660fSKip Macy 	    (err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0)) != 0 ||
4598e10660fSKip Macy 	    (err = mdio_write(phy, 0, VSC8211_EXT_CTRL,
4608e10660fSKip Macy 			      val | VSC_CTRL_CLAUSE37_VIEW)) != 0 ||
4618e10660fSKip Macy 	    (err = vsc8211_reset(phy, 0)) != 0)
4628e10660fSKip Macy 		return err;
4638e10660fSKip Macy 
4648e10660fSKip Macy 	udelay(5); /* delay after reset before next SMI */
4658e10660fSKip Macy 	return 0;
466b6d90eb7SKip Macy }
467