1167514Skmacy/**************************************************************************
2167514Skmacy
3167514SkmacyCopyright (c) 2007, Chelsio Inc.
4167514SkmacyAll rights reserved.
5167514Skmacy
6167514SkmacyRedistribution and use in source and binary forms, with or without
7167514Skmacymodification, are permitted provided that the following conditions are met:
8167514Skmacy
9167514Skmacy 1. Redistributions of source code must retain the above copyright notice,
10167514Skmacy    this list of conditions and the following disclaimer.
11167514Skmacy
12170076Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its
13167514Skmacy    contributors may be used to endorse or promote products derived from
14167514Skmacy    this software without specific prior written permission.
15167514Skmacy
16167514SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17167514SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18167514SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19167514SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20167514SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21167514SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22167514SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23167514SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24167514SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25167514SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26167514SkmacyPOSSIBILITY OF SUCH DAMAGE.
27167514Skmacy
28167514Skmacy***************************************************************************/
29167514Skmacy
30167514Skmacy#include <sys/cdefs.h>
31167514Skmacy__FBSDID("$FreeBSD$");
32167514Skmacy
33170076Skmacy#include <cxgb_include.h>
34167514Skmacy
35176472Skmacy#undef msleep
36176472Skmacy#define msleep t3_os_sleep
37176472Skmacy
38167514Skmacy/* VSC8211 PHY specific registers. */
39167514Skmacyenum {
40176472Skmacy	VSC8211_SIGDET_CTRL   = 19,
41176472Skmacy	VSC8211_EXT_CTRL      = 23,
42197791Snp	VSC8211_PHY_CTRL      = 24,
43167514Skmacy	VSC8211_INTR_ENABLE   = 25,
44167514Skmacy	VSC8211_INTR_STATUS   = 26,
45180583Skmacy	VSC8211_LED_CTRL      = 27,
46167514Skmacy	VSC8211_AUX_CTRL_STAT = 28,
47176472Skmacy	VSC8211_EXT_PAGE_AXS  = 31,
48167514Skmacy};
49167514Skmacy
50167514Skmacyenum {
51167514Skmacy	VSC_INTR_RX_ERR     = 1 << 0,
52167514Skmacy	VSC_INTR_MS_ERR     = 1 << 1,  /* master/slave resolution error */
53167514Skmacy	VSC_INTR_CABLE      = 1 << 2,  /* cable impairment */
54167514Skmacy	VSC_INTR_FALSE_CARR = 1 << 3,  /* false carrier */
55167514Skmacy	VSC_INTR_MEDIA_CHG  = 1 << 4,  /* AMS media change */
56167514Skmacy	VSC_INTR_RX_FIFO    = 1 << 5,  /* Rx FIFO over/underflow */
57167514Skmacy	VSC_INTR_TX_FIFO    = 1 << 6,  /* Tx FIFO over/underflow */
58167514Skmacy	VSC_INTR_DESCRAMBL  = 1 << 7,  /* descrambler lock-lost */
59167514Skmacy	VSC_INTR_SYMBOL_ERR = 1 << 8,  /* symbol error */
60167514Skmacy	VSC_INTR_NEG_DONE   = 1 << 10, /* autoneg done */
61167514Skmacy	VSC_INTR_NEG_ERR    = 1 << 11, /* autoneg error */
62176472Skmacy	VSC_INTR_DPLX_CHG   = 1 << 12, /* duplex change */
63167514Skmacy	VSC_INTR_LINK_CHG   = 1 << 13, /* link change */
64176472Skmacy	VSC_INTR_SPD_CHG    = 1 << 14, /* speed change */
65167514Skmacy	VSC_INTR_ENABLE     = 1 << 15, /* interrupt enable */
66167514Skmacy};
67167514Skmacy
68176472Skmacyenum {
69176472Skmacy	VSC_CTRL_CLAUSE37_VIEW = 1 << 4,   /* Switch to Clause 37 view */
70176472Skmacy	VSC_CTRL_MEDIA_MODE_HI = 0xf000    /* High part of media mode select */
71176472Skmacy};
72176472Skmacy
73167514Skmacy#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
74176472Skmacy			   VSC_INTR_DPLX_CHG | VSC_INTR_SPD_CHG | \
75167514Skmacy	 		   VSC_INTR_NEG_DONE)
76167514Skmacy#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
77167514Skmacy		   VSC_INTR_ENABLE)
78167514Skmacy
79167514Skmacy/* PHY specific auxiliary control & status register fields */
80167514Skmacy#define S_ACSR_ACTIPHY_TMR    0
81167514Skmacy#define M_ACSR_ACTIPHY_TMR    0x3
82167514Skmacy#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
83167514Skmacy
84167514Skmacy#define S_ACSR_SPEED    3
85167514Skmacy#define M_ACSR_SPEED    0x3
86167514Skmacy#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
87167514Skmacy
88167514Skmacy#define S_ACSR_DUPLEX 5
89167514Skmacy#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
90167514Skmacy
91167514Skmacy#define S_ACSR_ACTIPHY 6
92167514Skmacy#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
93167514Skmacy
94167514Skmacy/*
95167514Skmacy * Reset the PHY.  This PHY completes reset immediately so we never wait.
96167514Skmacy */
97167514Skmacystatic int vsc8211_reset(struct cphy *cphy, int wait)
98167514Skmacy{
99167514Skmacy	return t3_phy_reset(cphy, 0, 0);
100167514Skmacy}
101167514Skmacy
102167514Skmacystatic int vsc8211_intr_enable(struct cphy *cphy)
103167514Skmacy{
104167514Skmacy	return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK);
105167514Skmacy}
106167514Skmacy
107167514Skmacystatic int vsc8211_intr_disable(struct cphy *cphy)
108167514Skmacy{
109167514Skmacy	return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0);
110167514Skmacy}
111167514Skmacy
112167514Skmacystatic int vsc8211_intr_clear(struct cphy *cphy)
113167514Skmacy{
114167514Skmacy	u32 val;
115167514Skmacy
116167514Skmacy	/* Clear PHY interrupts by reading the register. */
117167514Skmacy	return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val);
118167514Skmacy}
119167514Skmacy
120167514Skmacystatic int vsc8211_autoneg_enable(struct cphy *cphy)
121167514Skmacy{
122167514Skmacy	return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
123167514Skmacy				   BMCR_ANENABLE | BMCR_ANRESTART);
124167514Skmacy}
125167514Skmacy
126167514Skmacystatic int vsc8211_autoneg_restart(struct cphy *cphy)
127167514Skmacy{
128167514Skmacy	return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
129167514Skmacy				   BMCR_ANRESTART);
130167514Skmacy}
131167514Skmacy
132167514Skmacystatic int vsc8211_get_link_status(struct cphy *cphy, int *link_ok,
133167514Skmacy				     int *speed, int *duplex, int *fc)
134167514Skmacy{
135167514Skmacy	unsigned int bmcr, status, lpa, adv;
136167514Skmacy	int err, sp = -1, dplx = -1, pause = 0;
137167514Skmacy
138167514Skmacy	err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
139167514Skmacy	if (!err)
140167514Skmacy		err = mdio_read(cphy, 0, MII_BMSR, &status);
141167514Skmacy	if (err)
142167514Skmacy		return err;
143167514Skmacy
144167514Skmacy	if (link_ok) {
145167514Skmacy		/*
146167514Skmacy		 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
147167514Skmacy		 * once more to get the current link state.
148167514Skmacy		 */
149167514Skmacy		if (!(status & BMSR_LSTATUS))
150167514Skmacy			err = mdio_read(cphy, 0, MII_BMSR, &status);
151167514Skmacy		if (err)
152167514Skmacy			return err;
153167514Skmacy		*link_ok = (status & BMSR_LSTATUS) != 0;
154167514Skmacy	}
155167514Skmacy	if (!(bmcr & BMCR_ANENABLE)) {
156167514Skmacy		dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
157167514Skmacy		if (bmcr & BMCR_SPEED1000)
158167514Skmacy			sp = SPEED_1000;
159167514Skmacy		else if (bmcr & BMCR_SPEED100)
160167514Skmacy			sp = SPEED_100;
161167514Skmacy		else
162167514Skmacy			sp = SPEED_10;
163167514Skmacy	} else if (status & BMSR_ANEGCOMPLETE) {
164167514Skmacy		err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status);
165167514Skmacy		if (err)
166167514Skmacy			return err;
167167514Skmacy
168167514Skmacy		dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
169167514Skmacy		sp = G_ACSR_SPEED(status);
170167514Skmacy		if (sp == 0)
171167514Skmacy			sp = SPEED_10;
172167514Skmacy		else if (sp == 1)
173167514Skmacy			sp = SPEED_100;
174167514Skmacy		else
175167514Skmacy			sp = SPEED_1000;
176167514Skmacy
177167514Skmacy		if (fc && dplx == DUPLEX_FULL) {
178167514Skmacy			err = mdio_read(cphy, 0, MII_LPA, &lpa);
179167514Skmacy			if (!err)
180167514Skmacy				err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
181167514Skmacy			if (err)
182167514Skmacy				return err;
183167514Skmacy
184167514Skmacy			if (lpa & adv & ADVERTISE_PAUSE_CAP)
185167514Skmacy				pause = PAUSE_RX | PAUSE_TX;
186167514Skmacy			else if ((lpa & ADVERTISE_PAUSE_CAP) &&
187167514Skmacy				 (lpa & ADVERTISE_PAUSE_ASYM) &&
188167514Skmacy				 (adv & ADVERTISE_PAUSE_ASYM))
189167514Skmacy				pause = PAUSE_TX;
190167514Skmacy			else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
191167514Skmacy				 (adv & ADVERTISE_PAUSE_CAP))
192167514Skmacy				pause = PAUSE_RX;
193167514Skmacy		}
194167514Skmacy	}
195167514Skmacy	if (speed)
196167514Skmacy		*speed = sp;
197167514Skmacy	if (duplex)
198167514Skmacy		*duplex = dplx;
199167514Skmacy	if (fc)
200167514Skmacy		*fc = pause;
201167514Skmacy	return 0;
202167514Skmacy}
203167514Skmacy
204176472Skmacystatic int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok,
205176472Skmacy					 int *speed, int *duplex, int *fc)
206176472Skmacy{
207176472Skmacy	unsigned int bmcr, status, lpa, adv;
208176472Skmacy	int err, sp = -1, dplx = -1, pause = 0;
209176472Skmacy
210176472Skmacy	err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
211176472Skmacy	if (!err)
212176472Skmacy		err = mdio_read(cphy, 0, MII_BMSR, &status);
213176472Skmacy	if (err)
214176472Skmacy		return err;
215176472Skmacy
216176472Skmacy	if (link_ok) {
217176472Skmacy		/*
218176472Skmacy		 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
219176472Skmacy		 * once more to get the current link state.
220176472Skmacy		 */
221176472Skmacy		if (!(status & BMSR_LSTATUS))
222176472Skmacy			err = mdio_read(cphy, 0, MII_BMSR, &status);
223176472Skmacy		if (err)
224176472Skmacy			return err;
225176472Skmacy		*link_ok = (status & BMSR_LSTATUS) != 0;
226176472Skmacy	}
227176472Skmacy	if (!(bmcr & BMCR_ANENABLE)) {
228176472Skmacy		dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
229176472Skmacy		if (bmcr & BMCR_SPEED1000)
230176472Skmacy			sp = SPEED_1000;
231176472Skmacy		else if (bmcr & BMCR_SPEED100)
232176472Skmacy			sp = SPEED_100;
233176472Skmacy		else
234176472Skmacy			sp = SPEED_10;
235176472Skmacy	} else if (status & BMSR_ANEGCOMPLETE) {
236176472Skmacy		err = mdio_read(cphy, 0, MII_LPA, &lpa);
237176472Skmacy		if (!err)
238176472Skmacy			err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
239176472Skmacy		if (err)
240176472Skmacy			return err;
241176472Skmacy
242176472Skmacy		if (adv & lpa & ADVERTISE_1000XFULL) {
243176472Skmacy			dplx = DUPLEX_FULL;
244176472Skmacy			sp = SPEED_1000;
245176472Skmacy		} else if (adv & lpa & ADVERTISE_1000XHALF) {
246176472Skmacy			dplx = DUPLEX_HALF;
247176472Skmacy			sp = SPEED_1000;
248176472Skmacy		}
249176472Skmacy
250176472Skmacy		if (fc && dplx == DUPLEX_FULL) {
251176472Skmacy			if (lpa & adv & ADVERTISE_1000XPAUSE)
252176472Skmacy				pause = PAUSE_RX | PAUSE_TX;
253176472Skmacy			else if ((lpa & ADVERTISE_1000XPAUSE) &&
254176472Skmacy				 (adv & lpa & ADVERTISE_1000XPSE_ASYM))
255176472Skmacy				pause = PAUSE_TX;
256176472Skmacy			else if ((lpa & ADVERTISE_1000XPSE_ASYM) &&
257176472Skmacy				 (adv & ADVERTISE_1000XPAUSE))
258176472Skmacy				pause = PAUSE_RX;
259176472Skmacy		}
260176472Skmacy	}
261176472Skmacy	if (speed)
262176472Skmacy		*speed = sp;
263176472Skmacy	if (duplex)
264176472Skmacy		*duplex = dplx;
265176472Skmacy	if (fc)
266176472Skmacy		*fc = pause;
267176472Skmacy	return 0;
268176472Skmacy}
269176472Skmacy
270176472Skmacy/*
271176472Skmacy * Enable/disable auto MDI/MDI-X in forced link speed mode.
272176472Skmacy */
273176472Skmacystatic int vsc8211_set_automdi(struct cphy *phy, int enable)
274176472Skmacy{
275176472Skmacy	int err;
276176472Skmacy
277176472Skmacy	if ((err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0x52b5)) != 0 ||
278176472Skmacy	    (err = mdio_write(phy, 0, 18, 0x12)) != 0 ||
279176472Skmacy	    (err = mdio_write(phy, 0, 17, enable ? 0x2803 : 0x3003)) != 0 ||
280176472Skmacy	    (err = mdio_write(phy, 0, 16, 0x87fa)) != 0 ||
281176472Skmacy	    (err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0)) != 0)
282176472Skmacy		return err;
283176472Skmacy	return 0;
284176472Skmacy}
285176472Skmacy
286176472Skmacystatic int vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex)
287176472Skmacy{
288176472Skmacy	int err;
289176472Skmacy
290176472Skmacy	err = t3_set_phy_speed_duplex(phy, speed, duplex);
291176472Skmacy	if (!err)
292176472Skmacy		err = vsc8211_set_automdi(phy, 1);
293176472Skmacy	return err;
294176472Skmacy}
295176472Skmacy
296167514Skmacystatic int vsc8211_power_down(struct cphy *cphy, int enable)
297167514Skmacy{
298167514Skmacy	return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
299167514Skmacy				   enable ? BMCR_PDOWN : 0);
300167514Skmacy}
301167514Skmacy
302167514Skmacystatic int vsc8211_intr_handler(struct cphy *cphy)
303167514Skmacy{
304167514Skmacy	unsigned int cause;
305167514Skmacy	int err, cphy_cause = 0;
306167514Skmacy
307167514Skmacy	err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause);
308167514Skmacy	if (err)
309167514Skmacy		return err;
310167514Skmacy
311167514Skmacy	cause &= INTR_MASK;
312167514Skmacy	if (cause & CFG_CHG_INTR_MASK)
313167514Skmacy		cphy_cause |= cphy_cause_link_change;
314167514Skmacy	if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
315167514Skmacy		cphy_cause |= cphy_cause_fifo_error;
316167514Skmacy	return cphy_cause;
317167514Skmacy}
318167514Skmacy
319167514Skmacy#ifdef C99_NOT_SUPPORTED
320167514Skmacystatic struct cphy_ops vsc8211_ops = {
321167514Skmacy	vsc8211_reset,
322167514Skmacy	vsc8211_intr_enable,
323167514Skmacy	vsc8211_intr_disable,
324167514Skmacy	vsc8211_intr_clear,
325167514Skmacy	vsc8211_intr_handler,
326167514Skmacy	vsc8211_autoneg_enable,
327167514Skmacy	vsc8211_autoneg_restart,
328167514Skmacy	t3_phy_advertise,
329167514Skmacy	NULL,
330176472Skmacy	vsc8211_set_speed_duplex,
331167514Skmacy	vsc8211_get_link_status,
332167514Skmacy	vsc8211_power_down,
333167514Skmacy};
334176472Skmacy
335176472Skmacystatic struct cphy_ops vsc8211_fiber_ops = {
336176472Skmacy	vsc8211_reset,
337176472Skmacy	vsc8211_intr_enable,
338176472Skmacy	vsc8211_intr_disable,
339176472Skmacy	vsc8211_intr_clear,
340176472Skmacy	vsc8211_intr_handler,
341176472Skmacy	vsc8211_autoneg_enable,
342176472Skmacy	vsc8211_autoneg_restart,
343176472Skmacy	t3_phy_advertise_fiber,
344176472Skmacy	NULL,
345176472Skmacy	t3_set_phy_speed_duplex,
346176472Skmacy	vsc8211_get_link_status_fiber,
347176472Skmacy	vsc8211_power_down,
348176472Skmacy};
349167514Skmacy#else
350167514Skmacystatic struct cphy_ops vsc8211_ops = {
351167514Skmacy	.reset             = vsc8211_reset,
352167514Skmacy	.intr_enable       = vsc8211_intr_enable,
353167514Skmacy	.intr_disable      = vsc8211_intr_disable,
354167514Skmacy	.intr_clear        = vsc8211_intr_clear,
355167514Skmacy	.intr_handler      = vsc8211_intr_handler,
356167514Skmacy	.autoneg_enable    = vsc8211_autoneg_enable,
357167514Skmacy	.autoneg_restart   = vsc8211_autoneg_restart,
358167514Skmacy	.advertise         = t3_phy_advertise,
359176472Skmacy	.set_speed_duplex  = vsc8211_set_speed_duplex,
360167514Skmacy	.get_link_status   = vsc8211_get_link_status,
361167514Skmacy	.power_down        = vsc8211_power_down,
362167514Skmacy};
363176472Skmacy
364176472Skmacystatic struct cphy_ops vsc8211_fiber_ops = {
365176472Skmacy	.reset             = vsc8211_reset,
366176472Skmacy	.intr_enable       = vsc8211_intr_enable,
367176472Skmacy	.intr_disable      = vsc8211_intr_disable,
368176472Skmacy	.intr_clear        = vsc8211_intr_clear,
369176472Skmacy	.intr_handler      = vsc8211_intr_handler,
370176472Skmacy	.autoneg_enable    = vsc8211_autoneg_enable,
371176472Skmacy	.autoneg_restart   = vsc8211_autoneg_restart,
372176472Skmacy	.advertise         = t3_phy_advertise_fiber,
373176472Skmacy	.set_speed_duplex  = t3_set_phy_speed_duplex,
374176472Skmacy	.get_link_status   = vsc8211_get_link_status_fiber,
375176472Skmacy	.power_down        = vsc8211_power_down,
376176472Skmacy};
377167514Skmacy#endif
378167514Skmacy
379197791Snp#define VSC8211_PHY_CTRL 24
380197791Snp
381197791Snp#define S_VSC8211_TXFIFODEPTH    7
382197791Snp#define M_VSC8211_TXFIFODEPTH    0x7
383197791Snp#define V_VSC8211_TXFIFODEPTH(x) ((x) << S_VSC8211_TXFIFODEPTH)
384197791Snp#define G_VSC8211_TXFIFODEPTH(x) (((x) >> S_VSC8211_TXFIFODEPTH) & M_VSC8211_TXFIFODEPTH)
385197791Snp
386197791Snp#define S_VSC8211_RXFIFODEPTH    4
387197791Snp#define M_VSC8211_RXFIFODEPTH    0x7
388197791Snp#define V_VSC8211_RXFIFODEPTH(x) ((x) << S_VSC8211_RXFIFODEPTH)
389197791Snp#define G_VSC8211_RXFIFODEPTH(x) (((x) >> S_VSC8211_RXFIFODEPTH) & M_VSC8211_RXFIFODEPTH)
390197791Snp
391197791Snpint t3_vsc8211_fifo_depth(adapter_t *adap, unsigned int mtu, int port)
392197791Snp{
393197791Snp	/* TX FIFO Depth set bits 9:7 to 100 (IEEE mode) */
394197791Snp	unsigned int val = 4;
395197791Snp	unsigned int currentregval;
396197791Snp	unsigned int regval;
397197791Snp	int err;
398197791Snp
399197791Snp	/* Retrieve the port info structure from adater_t */
400197791Snp	struct port_info *portinfo = adap2pinfo(adap, port);
401197791Snp
402197791Snp	/* What phy is this */
403197791Snp	struct cphy *phy = &portinfo->phy;
404197791Snp
405197791Snp	/* Read the current value of the PHY control Register */
406197791Snp	err = mdio_read(phy, 0, VSC8211_PHY_CTRL, &currentregval);
407197791Snp
408197791Snp	if (err)
409197791Snp		return err;
410197791Snp
411197791Snp	/* IEEE mode supports up to 1518 bytes */
412197791Snp	/* mtu does not contain the header + FCS (18 bytes) */
413197791Snp	if (mtu > 1500)
414197791Snp		/*
415197791Snp		 * If using a packet size > 1500  set TX FIFO Depth bits
416197791Snp		 * 9:7 to 011 (Jumbo packet mode)
417197791Snp		 */
418197791Snp		val = 3;
419197791Snp
420197791Snp	regval = V_VSC8211_TXFIFODEPTH(val) | V_VSC8211_RXFIFODEPTH(val) |
421197791Snp		(currentregval & ~V_VSC8211_TXFIFODEPTH(M_VSC8211_TXFIFODEPTH) &
422197791Snp		~V_VSC8211_RXFIFODEPTH(M_VSC8211_RXFIFODEPTH));
423197791Snp
424197791Snp	return  mdio_write(phy, 0, VSC8211_PHY_CTRL, regval);
425197791Snp}
426197791Snp
427197791Snpint t3_vsc8211_phy_prep(pinfo_t *pinfo, int phy_addr,
428176472Skmacy			const struct mdio_ops *mdio_ops)
429167514Skmacy{
430197791Snp	struct cphy *phy = &pinfo->phy;
431176472Skmacy	int err;
432176472Skmacy	unsigned int val;
433176472Skmacy
434197791Snp	cphy_init(&pinfo->phy, pinfo->adapter, pinfo, phy_addr, &vsc8211_ops, mdio_ops,
435176472Skmacy		  SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full |
436176472Skmacy		  SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII |
437176472Skmacy		  SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T");
438176472Skmacy	msleep(20);       /* PHY needs ~10ms to start responding to MDIO */
439176472Skmacy
440176472Skmacy	err = mdio_read(phy, 0, VSC8211_EXT_CTRL, &val);
441176472Skmacy	if (err)
442176472Skmacy		return err;
443180583Skmacy	if (val & VSC_CTRL_MEDIA_MODE_HI) {
444180583Skmacy		/* copper interface, just need to configure the LEDs */
445180583Skmacy		return mdio_write(phy, 0, VSC8211_LED_CTRL, 0x100);
446180583Skmacy	}
447176472Skmacy
448176472Skmacy	phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
449176472Skmacy		    SUPPORTED_MII | SUPPORTED_FIBRE | SUPPORTED_IRQ;
450176472Skmacy	phy->desc = "1000BASE-X";
451176472Skmacy	phy->ops = &vsc8211_fiber_ops;
452176472Skmacy
453176472Skmacy	if ((err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 1)) != 0 ||
454176472Skmacy	    (err = mdio_write(phy, 0, VSC8211_SIGDET_CTRL, 1)) != 0 ||
455176472Skmacy	    (err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0)) != 0 ||
456176472Skmacy	    (err = mdio_write(phy, 0, VSC8211_EXT_CTRL,
457176472Skmacy			      val | VSC_CTRL_CLAUSE37_VIEW)) != 0 ||
458176472Skmacy	    (err = vsc8211_reset(phy, 0)) != 0)
459176472Skmacy		return err;
460176472Skmacy
461176472Skmacy	udelay(5); /* delay after reset before next SMI */
462176472Skmacy	return 0;
463167514Skmacy}
464