xref: /titanic_51/usr/src/uts/common/io/mii/mii_marvell.c (revision cea606427170954e8cfcfa5417f3b60394180cb9)
1*cea60642SGarrett D'Amore /*
2*cea60642SGarrett D'Amore  * CDDL HEADER START
3*cea60642SGarrett D'Amore  *
4*cea60642SGarrett D'Amore  * The contents of this file are subject to the terms of the
5*cea60642SGarrett D'Amore  * Common Development and Distribution License (the "License").
6*cea60642SGarrett D'Amore  * You may not use this file except in compliance with the License.
7*cea60642SGarrett D'Amore  *
8*cea60642SGarrett D'Amore  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*cea60642SGarrett D'Amore  * or http://www.opensolaris.org/os/licensing.
10*cea60642SGarrett D'Amore  * See the License for the specific language governing permissions
11*cea60642SGarrett D'Amore  * and limitations under the License.
12*cea60642SGarrett D'Amore  *
13*cea60642SGarrett D'Amore  * When distributing Covered Code, include this CDDL HEADER in each
14*cea60642SGarrett D'Amore  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*cea60642SGarrett D'Amore  * If applicable, add the following below this CDDL HEADER, with the
16*cea60642SGarrett D'Amore  * fields enclosed by brackets "[]" replaced with your own identifying
17*cea60642SGarrett D'Amore  * information: Portions Copyright [yyyy] [name of copyright owner]
18*cea60642SGarrett D'Amore  *
19*cea60642SGarrett D'Amore  * CDDL HEADER END
20*cea60642SGarrett D'Amore  */
21*cea60642SGarrett D'Amore /*
22*cea60642SGarrett D'Amore  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*cea60642SGarrett D'Amore  * Use is subject to license terms.
24*cea60642SGarrett D'Amore  */
25*cea60642SGarrett D'Amore 
26*cea60642SGarrett D'Amore /*
27*cea60642SGarrett D'Amore  * MII overrides for Marvell PHYs.
28*cea60642SGarrett D'Amore  */
29*cea60642SGarrett D'Amore 
30*cea60642SGarrett D'Amore #include <sys/types.h>
31*cea60642SGarrett D'Amore #include <sys/ddi.h>
32*cea60642SGarrett D'Amore #include <sys/sunddi.h>
33*cea60642SGarrett D'Amore #include <sys/mii.h>
34*cea60642SGarrett D'Amore #include <sys/miiregs.h>
35*cea60642SGarrett D'Amore #include "miipriv.h"
36*cea60642SGarrett D'Amore 
37*cea60642SGarrett D'Amore #define	MVPHY_PSC	MII_VENDOR(0)	/* PHY specific control */
38*cea60642SGarrett D'Amore 
39*cea60642SGarrett D'Amore #define	MV_PSC_TXFIFO_DEPTH	0xc000
40*cea60642SGarrett D'Amore #define	MV_PSC_RXFIFO_DEPTH	0x3000
41*cea60642SGarrett D'Amore #define	MV_PSC_ASSERT_CRS_TX	0x0800	/* older PHYs */
42*cea60642SGarrett D'Amore #define	MV_PSC_DOWNSHIFT_EN	0x0800	/* newer PHYs */
43*cea60642SGarrett D'Amore #define	MV_PSC_FORCE_GOOD_LINK	0x0400
44*cea60642SGarrett D'Amore #define	MV_PSC_DIS_SCRAMBLER	0x0200
45*cea60642SGarrett D'Amore #define	MV_PSC_MII_5BIT_EN	0x0100
46*cea60642SGarrett D'Amore #define	MV_PSC_EN_DETECT_MASK	0x0300
47*cea60642SGarrett D'Amore #define	MV_PSC_EN_EXT_DISTANCE	0x0080
48*cea60642SGarrett D'Amore #define	MV_PSC_AUTO_X_MODE	0x0060
49*cea60642SGarrett D'Amore #define	MV_PSC_AUTO_X_1000T	0x0040
50*cea60642SGarrett D'Amore #define	MV_PSC_MDIX_MANUAL	0x0010
51*cea60642SGarrett D'Amore #define	MV_PSC_MDI_MANUAL	0x0000
52*cea60642SGarrett D'Amore #define	MV_PSC_RGMII_POWER_UP	0x0008	/* 88E1116, 88E1149 page 2 */
53*cea60642SGarrett D'Amore #define	MV_PSC_POWER_DOWN	0x0004	/* 88E1116 page 0 */
54*cea60642SGarrett D'Amore 
55*cea60642SGarrett D'Amore #define	MV_PSC_MODE_MASK	0x0380	/* 88E1112 page 2 */
56*cea60642SGarrett D'Amore #define	MV_PSC_MODE_AUTO	0x0180
57*cea60642SGarrett D'Amore #define	MV_PSC_MODE_COPPER	0x0280
58*cea60642SGarrett D'Amore #define	MV_PSC_MODE_1000BASEX	0x0380
59*cea60642SGarrett D'Amore 
60*cea60642SGarrett D'Amore #define	MV_PSC_DIS_125CLK	0x0010
61*cea60642SGarrett D'Amore #define	MV_PSC_MAC_PDOWN	0x0008
62*cea60642SGarrett D'Amore #define	MV_PSC_SQE_TEST		0x0004
63*cea60642SGarrett D'Amore #define	MV_PSC_POL_REVERSE	0x0002
64*cea60642SGarrett D'Amore #define	MV_PSC_JABBER_DIS	0x0001
65*cea60642SGarrett D'Amore 
66*cea60642SGarrett D'Amore /* 88E3016 */
67*cea60642SGarrett D'Amore #define	MV_PSC_AUTO_MDIX	0x0030
68*cea60642SGarrett D'Amore #define	MV_PSC_SIGDET_POLARITY	0x0040
69*cea60642SGarrett D'Amore #define	MV_PSC_EXT_DIST		0x0080
70*cea60642SGarrett D'Amore #define	MV_PSC_FEFI_DIS		0x0100
71*cea60642SGarrett D'Amore #define	MV_PSC_NLP_GEN_DIS	0x0800
72*cea60642SGarrett D'Amore #define	MV_PSC_LPNP		0x1000
73*cea60642SGarrett D'Amore #define	MV_PSC_NLP_CHK_DIS	0x2000
74*cea60642SGarrett D'Amore #define	MV_PSC_EN_DETECT	0x4000
75*cea60642SGarrett D'Amore 
76*cea60642SGarrett D'Amore /* LED control page 3, 88E1116, 88E1149 */
77*cea60642SGarrett D'Amore #define	MV_PSC_LED_LOS_MASK	0xf000
78*cea60642SGarrett D'Amore #define	MV_PSC_LED_INIT_MASK	0x0f00
79*cea60642SGarrett D'Amore #define	MV_PSC_LED_STA1_MASK	0x00f0
80*cea60642SGarrett D'Amore #define	MV_PSC_LED_STA0_MASK	0x000f
81*cea60642SGarrett D'Amore 
82*cea60642SGarrett D'Amore #define	MV_PSC_LED_LOS_CTRL(x)	(((x) << 12) & MV_PSC_LED_LOS_MASK)
83*cea60642SGarrett D'Amore #define	MV_PSC_LED_INIT_CTRL(x)	(((x) << 8) & MV_PSC_LED_INIT_MASK)
84*cea60642SGarrett D'Amore #define	MV_PSC_LED_STA1_CTRL(x)	(((x) << 4) & MV_PSC_LED_STA1_MASK)
85*cea60642SGarrett D'Amore #define	MV_PSC_LED_STA0_CTRL(x)	(((x)) & MV_PSC_LED_STA0_MASK)
86*cea60642SGarrett D'Amore 
87*cea60642SGarrett D'Amore 
88*cea60642SGarrett D'Amore #define	MVPHY_INTEN	MII_VENDOR(2)	/* Interrupt enable */
89*cea60642SGarrett D'Amore 
90*cea60642SGarrett D'Amore #define	MV_INTEN_PULSE_MASK	0x7000
91*cea60642SGarrett D'Amore #define	MV_INTEN_PULSE_NOSTR	0x0000
92*cea60642SGarrett D'Amore #define	MV_INTEN_PULSE_21MS	0x1000
93*cea60642SGarrett D'Amore #define	MV_INTEN_PULSE_42MS	0x2000
94*cea60642SGarrett D'Amore #define	MV_INTEN_PULSE_84MS	0x3000
95*cea60642SGarrett D'Amore #define	MV_INTEN_PULSE_170MS	0x4000
96*cea60642SGarrett D'Amore #define	MV_INTEN_PULSE_340MS	0x5000
97*cea60642SGarrett D'Amore #define	MV_INTEN_PULSE_670MS	0x6000
98*cea60642SGarrett D'Amore #define	MV_INTEN_PULSE_1300MS	0x7000
99*cea60642SGarrett D'Amore 
100*cea60642SGarrett D'Amore #define	MV_INTEN_BLINK_MASK	0x0700
101*cea60642SGarrett D'Amore #define	MV_INTEN_BLINK_42MS	0x0000
102*cea60642SGarrett D'Amore #define	MV_INTEN_BLINK_84MS	0x0100
103*cea60642SGarrett D'Amore #define	MV_INTEN_BLINK_170MS	0x0200
104*cea60642SGarrett D'Amore #define	MV_INTEN_BLINK_340MS	0x0300
105*cea60642SGarrett D'Amore #define	MV_INTEN_BLINK_670MS	0x0400
106*cea60642SGarrett D'Amore 
107*cea60642SGarrett D'Amore #define	MVPHY_INTST	MII_VENDOR(3)	/* Interrupt status */
108*cea60642SGarrett D'Amore 
109*cea60642SGarrett D'Amore #define	MVPHY_EPSC	MII_VENDOR(4)	/* Ext. phy specific control */
110*cea60642SGarrett D'Amore #define	MV_EPSC_DOWN_NO_IDLE	0x8000
111*cea60642SGarrett D'Amore #define	MV_EPSC_FIBER_LOOPBACK	0x4000
112*cea60642SGarrett D'Amore #define	MV_EPSC_TX_CLK_2_5	0x0060
113*cea60642SGarrett D'Amore #define	MV_EPSC_TX_CLK_25	0x0070
114*cea60642SGarrett D'Amore #define	MV_EPSC_TX_CLK_0	0x0000
115*cea60642SGarrett D'Amore 
116*cea60642SGarrett D'Amore #define	MVPHY_EADR	MII_VENDOR(6)	/* Extended address */
117*cea60642SGarrett D'Amore 
118*cea60642SGarrett D'Amore #define	MVPHY_LED_PSEL	MII_VENDOR(6)	/* 88E3016 */
119*cea60642SGarrett D'Amore #define	MV_LED_PSEL_COLX	0x00
120*cea60642SGarrett D'Amore #define	MV_LED_PSEL_ERROR	0x01
121*cea60642SGarrett D'Amore #define	MV_LED_PSEL_DUPLEX	0x02
122*cea60642SGarrett D'Amore #define	MV_LED_PSEL_DP_COL	0x03
123*cea60642SGarrett D'Amore #define	MV_LED_PSEL_SPEED	0x04
124*cea60642SGarrett D'Amore #define	MV_LED_PSEL_LINK	0x05
125*cea60642SGarrett D'Amore #define	MV_LED_PSEL_TX		0x06
126*cea60642SGarrett D'Amore #define	MV_LED_PSEL_RX		0x07
127*cea60642SGarrett D'Amore #define	MV_LED_PSEL_ACT		0x08
128*cea60642SGarrett D'Amore #define	MV_LED_PSEL_LNK_RX	0x09
129*cea60642SGarrett D'Amore #define	MV_LED_PSEL_LNK_ACT	0x0a
130*cea60642SGarrett D'Amore #define	MV_LED_PSEL_ACT_BL	0x0b
131*cea60642SGarrett D'Amore #define	MV_LED_PSEL_TX_BL	0x0c
132*cea60642SGarrett D'Amore #define	MV_LED_PSEL_RX_BL	0x0d
133*cea60642SGarrett D'Amore #define	MV_LED_PSEL_COLX_BL	0x0e
134*cea60642SGarrett D'Amore #define	MV_LED_PSEL_INACT	0x0f
135*cea60642SGarrett D'Amore #define	MV_LED_PSEL_LED2(x)	(x << 8)
136*cea60642SGarrett D'Amore #define	MV_LED_PSEL_LED1(x)	(x << 4)
137*cea60642SGarrett D'Amore #define	MV_LED_PSEL_LED0(x)	(x << 0)
138*cea60642SGarrett D'Amore 
139*cea60642SGarrett D'Amore #define	MVPHY_PAGE_ADDR	MII_VENDOR(13)
140*cea60642SGarrett D'Amore #define	MVPHY_PAGE_DATA	MII_VENDOR(14)
141*cea60642SGarrett D'Amore 
142*cea60642SGarrett D'Amore 
143*cea60642SGarrett D'Amore #define	MVPHY_EPSS	MII_VENDOR(11)	/* Ext. phy specific status */
144*cea60642SGarrett D'Amore 
145*cea60642SGarrett D'Amore #define	MV_EPSS_FCAUTOSEL	0x8000		/* fiber/copper autosel */
146*cea60642SGarrett D'Amore #define	MV_EPSS_FCRESOL		0x1000		/* fiber/copper resol */
147*cea60642SGarrett D'Amore 
148*cea60642SGarrett D'Amore static int
149*cea60642SGarrett D'Amore mvphy_reset_88e3016(phy_handle_t *ph)
150*cea60642SGarrett D'Amore {
151*cea60642SGarrett D'Amore 	uint16_t	reg;
152*cea60642SGarrett D'Amore 	int		rv;
153*cea60642SGarrett D'Amore 
154*cea60642SGarrett D'Amore 	rv = phy_reset(ph);
155*cea60642SGarrett D'Amore 
156*cea60642SGarrett D'Amore 	reg = phy_read(ph, MVPHY_PSC);
157*cea60642SGarrett D'Amore 
158*cea60642SGarrett D'Amore 	reg |= MV_PSC_AUTO_MDIX;
159*cea60642SGarrett D'Amore 	reg &= ~(MV_PSC_EN_DETECT | MV_PSC_DIS_SCRAMBLER);
160*cea60642SGarrett D'Amore 	reg |= MV_PSC_LPNP;
161*cea60642SGarrett D'Amore 
162*cea60642SGarrett D'Amore 	/* enable class A driver for Yukon FE+ A0. */
163*cea60642SGarrett D'Amore 	PHY_SET(ph, MII_VENDOR(12), 0x0001);
164*cea60642SGarrett D'Amore 
165*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PSC, reg);
166*cea60642SGarrett D'Amore 
167*cea60642SGarrett D'Amore 	/* LED2 = ACT blink, LED1 = LINK), LED0 = SPEED */
168*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_LED_PSEL,
169*cea60642SGarrett D'Amore 	    MV_LED_PSEL_LED2(MV_LED_PSEL_ACT_BL) |
170*cea60642SGarrett D'Amore 	    MV_LED_PSEL_LED1(MV_LED_PSEL_LINK) |
171*cea60642SGarrett D'Amore 	    MV_LED_PSEL_LED0(MV_LED_PSEL_SPEED));
172*cea60642SGarrett D'Amore 
173*cea60642SGarrett D'Amore 	/* calibration, values not documented */
174*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PAGE_ADDR, 17);
175*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PAGE_DATA, 0x3f60);
176*cea60642SGarrett D'Amore 
177*cea60642SGarrett D'Amore 	/* Normal BMCR reset now */
178*cea60642SGarrett D'Amore 	return (rv);
179*cea60642SGarrett D'Amore }
180*cea60642SGarrett D'Amore 
181*cea60642SGarrett D'Amore static int
182*cea60642SGarrett D'Amore mvphy_loop_88e3016(phy_handle_t *ph)
183*cea60642SGarrett D'Amore {
184*cea60642SGarrett D'Amore 	uint16_t	reg;
185*cea60642SGarrett D'Amore 	int		rv;
186*cea60642SGarrett D'Amore 
187*cea60642SGarrett D'Amore 	rv = phy_loop(ph);
188*cea60642SGarrett D'Amore 
189*cea60642SGarrett D'Amore 	/*
190*cea60642SGarrett D'Amore 	 * The PHY apparently needs a soft reset, but supposedly
191*cea60642SGarrett D'Amore 	 * retains most of the other critical state.
192*cea60642SGarrett D'Amore 	 */
193*cea60642SGarrett D'Amore 	reg = phy_read(ph, MII_CONTROL);
194*cea60642SGarrett D'Amore 	reg |= MII_CONTROL_RESET;
195*cea60642SGarrett D'Amore 	phy_write(ph, MII_CONTROL, reg);
196*cea60642SGarrett D'Amore 
197*cea60642SGarrett D'Amore 	reg = phy_read(ph, MVPHY_PSC);
198*cea60642SGarrett D'Amore 	reg &= ~(MV_PSC_AUTO_MDIX);
199*cea60642SGarrett D'Amore 	reg &= ~(MV_PSC_EN_DETECT | MV_PSC_DIS_SCRAMBLER);
200*cea60642SGarrett D'Amore 	reg |= MV_PSC_LPNP;
201*cea60642SGarrett D'Amore 
202*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PSC, reg);
203*cea60642SGarrett D'Amore 
204*cea60642SGarrett D'Amore 	return (rv);
205*cea60642SGarrett D'Amore }
206*cea60642SGarrett D'Amore 
207*cea60642SGarrett D'Amore static int
208*cea60642SGarrett D'Amore mvphy_reset_88e3082(phy_handle_t *ph)
209*cea60642SGarrett D'Amore {
210*cea60642SGarrett D'Amore 	uint16_t reg;
211*cea60642SGarrett D'Amore 	int	rv;
212*cea60642SGarrett D'Amore 
213*cea60642SGarrett D'Amore 	rv = phy_reset(ph);
214*cea60642SGarrett D'Amore 
215*cea60642SGarrett D'Amore 	reg = phy_read(ph, MVPHY_PSC);
216*cea60642SGarrett D'Amore 	reg |= (MV_PSC_AUTO_X_MODE >> 1);
217*cea60642SGarrett D'Amore 	reg |= MV_PSC_ASSERT_CRS_TX;
218*cea60642SGarrett D'Amore 	reg &= ~MV_PSC_POL_REVERSE;
219*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PSC, reg);
220*cea60642SGarrett D'Amore 
221*cea60642SGarrett D'Amore 	return (rv);
222*cea60642SGarrett D'Amore }
223*cea60642SGarrett D'Amore 
224*cea60642SGarrett D'Amore static int
225*cea60642SGarrett D'Amore mvphy_reset_88e1149(phy_handle_t *ph)
226*cea60642SGarrett D'Amore {
227*cea60642SGarrett D'Amore 	uint16_t reg;
228*cea60642SGarrett D'Amore 	int rv;
229*cea60642SGarrett D'Amore 
230*cea60642SGarrett D'Amore 	/* make sure that this PHY uses page 0 (copper) */
231*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_EADR, 0);
232*cea60642SGarrett D'Amore 
233*cea60642SGarrett D'Amore 	reg = phy_read(ph, MVPHY_PSC);
234*cea60642SGarrett D'Amore 	/* Disable energy detect mode */
235*cea60642SGarrett D'Amore 	reg &= ~MV_PSC_EN_DETECT_MASK;
236*cea60642SGarrett D'Amore 	reg |= MV_PSC_AUTO_X_MODE;
237*cea60642SGarrett D'Amore 	reg |= MV_PSC_DOWNSHIFT_EN;
238*cea60642SGarrett D'Amore 	reg &= ~MV_PSC_POL_REVERSE;
239*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PSC, reg);
240*cea60642SGarrett D'Amore 
241*cea60642SGarrett D'Amore 	rv = phy_reset(ph);
242*cea60642SGarrett D'Amore 
243*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_EADR, 2);
244*cea60642SGarrett D'Amore 	PHY_SET(ph, MVPHY_PSC, MV_PSC_RGMII_POWER_UP);
245*cea60642SGarrett D'Amore 
246*cea60642SGarrett D'Amore 	/*
247*cea60642SGarrett D'Amore 	 * Fix for signal amplitude in 10BASE-T, undocumented.
248*cea60642SGarrett D'Amore 	 * This is from the Marvell reference source code.
249*cea60642SGarrett D'Amore 	 */
250*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_EADR, 255);
251*cea60642SGarrett D'Amore 	phy_write(ph, 0x18, 0xaa99);
252*cea60642SGarrett D'Amore 	phy_write(ph, 0x17, 0x2011);
253*cea60642SGarrett D'Amore 
254*cea60642SGarrett D'Amore 	if (MII_PHY_REV(ph->phy_id) == 0) {
255*cea60642SGarrett D'Amore 		/*
256*cea60642SGarrett D'Amore 		 * EC_U: IEEE A/B 1000BASE-T symmetry failure
257*cea60642SGarrett D'Amore 		 *
258*cea60642SGarrett D'Amore 		 * EC_U is rev 0, Ultra 2 is rev 1 (at least the
259*cea60642SGarrett D'Amore 		 * unit I have), so we trigger on revid.
260*cea60642SGarrett D'Amore 		 */
261*cea60642SGarrett D'Amore 		phy_write(ph, 0x18, 0xa204);
262*cea60642SGarrett D'Amore 		phy_write(ph, 0x17, 0x2002);
263*cea60642SGarrett D'Amore 	}
264*cea60642SGarrett D'Amore 
265*cea60642SGarrett D'Amore 	/* page 3 is led control */
266*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_EADR, 3);
267*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PSC,
268*cea60642SGarrett D'Amore 	    MV_PSC_LED_LOS_CTRL(1) |		/* link/act */
269*cea60642SGarrett D'Amore 	    MV_PSC_LED_INIT_CTRL(8) |		/* 10 Mbps */
270*cea60642SGarrett D'Amore 	    MV_PSC_LED_STA1_CTRL(7) |		/* 100 Mbps */
271*cea60642SGarrett D'Amore 	    MV_PSC_LED_STA0_CTRL(7));		/* 1000 Mbps */
272*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_INTEN, 0);
273*cea60642SGarrett D'Amore 
274*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_EADR, 0);
275*cea60642SGarrett D'Amore 
276*cea60642SGarrett D'Amore 	/*
277*cea60642SGarrett D'Amore 	 * Weird... undocumented logic in the Intel e1000g driver.
278*cea60642SGarrett D'Amore 	 * I'm not sure what these values really do.
279*cea60642SGarrett D'Amore 	 */
280*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PAGE_ADDR, 3);
281*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PAGE_DATA, 0);
282*cea60642SGarrett D'Amore 
283*cea60642SGarrett D'Amore 	return (rv);
284*cea60642SGarrett D'Amore }
285*cea60642SGarrett D'Amore 
286*cea60642SGarrett D'Amore static int
287*cea60642SGarrett D'Amore mvphy_reset_88e1116(phy_handle_t *ph)
288*cea60642SGarrett D'Amore {
289*cea60642SGarrett D'Amore 	uint16_t reg;
290*cea60642SGarrett D'Amore 
291*cea60642SGarrett D'Amore 	/* make sure that this PHY uses page 0 (copper) */
292*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_EADR, 0);
293*cea60642SGarrett D'Amore 
294*cea60642SGarrett D'Amore 	reg = phy_read(ph, MVPHY_PSC);
295*cea60642SGarrett D'Amore 
296*cea60642SGarrett D'Amore 	reg &= ~MV_PSC_POWER_DOWN;
297*cea60642SGarrett D'Amore 	/* Disable energy detect mode */
298*cea60642SGarrett D'Amore 	reg &= ~MV_PSC_EN_DETECT_MASK;
299*cea60642SGarrett D'Amore 	reg |= MV_PSC_AUTO_X_MODE;
300*cea60642SGarrett D'Amore 	reg |= MV_PSC_ASSERT_CRS_TX;
301*cea60642SGarrett D'Amore 	reg &= ~MV_PSC_POL_REVERSE;
302*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PSC, reg);
303*cea60642SGarrett D'Amore 
304*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_EADR, 2);
305*cea60642SGarrett D'Amore 	PHY_SET(ph, MVPHY_PSC, MV_PSC_RGMII_POWER_UP);
306*cea60642SGarrett D'Amore 
307*cea60642SGarrett D'Amore 	/* page 3 is led control */
308*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_EADR, 3);
309*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PSC,
310*cea60642SGarrett D'Amore 	    MV_PSC_LED_LOS_CTRL(1) |		/* link/act */
311*cea60642SGarrett D'Amore 	    MV_PSC_LED_INIT_CTRL(8) |		/* 10 Mbps */
312*cea60642SGarrett D'Amore 	    MV_PSC_LED_STA1_CTRL(7) |		/* 100 Mbps */
313*cea60642SGarrett D'Amore 	    MV_PSC_LED_STA0_CTRL(7));		/* 1000 Mbps */
314*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_INTEN, 0);
315*cea60642SGarrett D'Amore 
316*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_EADR, 0);
317*cea60642SGarrett D'Amore 
318*cea60642SGarrett D'Amore 	return (phy_reset(ph));
319*cea60642SGarrett D'Amore }
320*cea60642SGarrett D'Amore 
321*cea60642SGarrett D'Amore static int
322*cea60642SGarrett D'Amore mvphy_reset_88e1118(phy_handle_t *ph)
323*cea60642SGarrett D'Amore {
324*cea60642SGarrett D'Amore 	uint16_t reg;
325*cea60642SGarrett D'Amore 	reg = phy_read(ph, MVPHY_PSC);
326*cea60642SGarrett D'Amore 
327*cea60642SGarrett D'Amore 	/* Disable energy detect mode */
328*cea60642SGarrett D'Amore 	reg &= ~MV_PSC_EN_DETECT_MASK;
329*cea60642SGarrett D'Amore 	reg |= MV_PSC_AUTO_X_MODE;
330*cea60642SGarrett D'Amore 	reg |= MV_PSC_ASSERT_CRS_TX;
331*cea60642SGarrett D'Amore 	reg &= ~MV_PSC_POL_REVERSE;
332*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PSC, reg);
333*cea60642SGarrett D'Amore 
334*cea60642SGarrett D'Amore 	return (phy_reset(ph));
335*cea60642SGarrett D'Amore }
336*cea60642SGarrett D'Amore 
337*cea60642SGarrett D'Amore static int
338*cea60642SGarrett D'Amore mvphy_reset_88e1111(phy_handle_t *ph)
339*cea60642SGarrett D'Amore {
340*cea60642SGarrett D'Amore 	uint16_t reg;
341*cea60642SGarrett D'Amore 
342*cea60642SGarrett D'Amore 	reg = phy_read(ph, MVPHY_PSC);
343*cea60642SGarrett D'Amore 
344*cea60642SGarrett D'Amore 	/* Disable energy detect mode */
345*cea60642SGarrett D'Amore 	reg &= ~MV_PSC_EN_DETECT_MASK;
346*cea60642SGarrett D'Amore 	reg |= MV_PSC_AUTO_X_MODE;
347*cea60642SGarrett D'Amore 	reg |= MV_PSC_ASSERT_CRS_TX;
348*cea60642SGarrett D'Amore 	reg &= ~MV_PSC_POL_REVERSE;
349*cea60642SGarrett D'Amore 
350*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PSC, reg);
351*cea60642SGarrett D'Amore 
352*cea60642SGarrett D'Amore 	/* force TX CLOCK to 25 MHz */
353*cea60642SGarrett D'Amore 	PHY_SET(ph, MVPHY_EPSC, MV_EPSC_TX_CLK_25);
354*cea60642SGarrett D'Amore 
355*cea60642SGarrett D'Amore 	return (phy_reset(ph));
356*cea60642SGarrett D'Amore 
357*cea60642SGarrett D'Amore }
358*cea60642SGarrett D'Amore 
359*cea60642SGarrett D'Amore static int
360*cea60642SGarrett D'Amore mvphy_reset_88e1112(phy_handle_t *ph)
361*cea60642SGarrett D'Amore {
362*cea60642SGarrett D'Amore 	uint16_t	reg, page;
363*cea60642SGarrett D'Amore 
364*cea60642SGarrett D'Amore 	if (phy_read(ph, MVPHY_EPSS) & MV_EPSS_FCRESOL) {
365*cea60642SGarrett D'Amore 
366*cea60642SGarrett D'Amore 		/* interface indicates fiber */
367*cea60642SGarrett D'Amore 		PHY_CLR(ph, MVPHY_PSC, MV_PSC_AUTO_X_MODE);
368*cea60642SGarrett D'Amore 
369*cea60642SGarrett D'Amore 		page = phy_read(ph, MVPHY_EADR);
370*cea60642SGarrett D'Amore 
371*cea60642SGarrett D'Amore 		/* Go into locked 1000BASE-X mode */
372*cea60642SGarrett D'Amore 		page = phy_read(ph, MVPHY_EADR);
373*cea60642SGarrett D'Amore 		phy_write(ph, MVPHY_EADR, 2);
374*cea60642SGarrett D'Amore 		reg = phy_read(ph, MVPHY_PSC);
375*cea60642SGarrett D'Amore 		reg &= ~MV_PSC_MODE_MASK;
376*cea60642SGarrett D'Amore 		reg |= MV_PSC_MODE_1000BASEX;
377*cea60642SGarrett D'Amore 		phy_write(ph, MVPHY_PSC, reg);
378*cea60642SGarrett D'Amore 		phy_write(ph, MVPHY_EADR, page);
379*cea60642SGarrett D'Amore 
380*cea60642SGarrett D'Amore 	} else {
381*cea60642SGarrett D'Amore 		reg = phy_read(ph, MVPHY_PSC);
382*cea60642SGarrett D'Amore 
383*cea60642SGarrett D'Amore 		/* Disable energy detect mode */
384*cea60642SGarrett D'Amore 		reg &= ~MV_PSC_EN_DETECT_MASK;
385*cea60642SGarrett D'Amore 		reg |= MV_PSC_AUTO_X_MODE;
386*cea60642SGarrett D'Amore 		reg |= MV_PSC_ASSERT_CRS_TX;
387*cea60642SGarrett D'Amore 		reg &= ~MV_PSC_POL_REVERSE;
388*cea60642SGarrett D'Amore 		phy_write(ph, MVPHY_PSC, reg);
389*cea60642SGarrett D'Amore 	}
390*cea60642SGarrett D'Amore 
391*cea60642SGarrett D'Amore 	return (phy_reset(ph));
392*cea60642SGarrett D'Amore }
393*cea60642SGarrett D'Amore 
394*cea60642SGarrett D'Amore static int
395*cea60642SGarrett D'Amore mvphy_reset_88e1011(phy_handle_t *ph)
396*cea60642SGarrett D'Amore {
397*cea60642SGarrett D'Amore 	uint16_t reg;
398*cea60642SGarrett D'Amore 
399*cea60642SGarrett D'Amore 	if (phy_read(ph, MVPHY_EPSS) & MV_EPSS_FCRESOL) {
400*cea60642SGarrett D'Amore 
401*cea60642SGarrett D'Amore 		/* interface indicates fiber */
402*cea60642SGarrett D'Amore 		PHY_CLR(ph, MVPHY_PSC, MV_PSC_AUTO_X_MODE);
403*cea60642SGarrett D'Amore 
404*cea60642SGarrett D'Amore 	} else {
405*cea60642SGarrett D'Amore 		reg = phy_read(ph, MVPHY_PSC);
406*cea60642SGarrett D'Amore 		reg &= ~MV_PSC_AUTO_X_MODE;
407*cea60642SGarrett D'Amore 		reg |= MV_PSC_ASSERT_CRS_TX;
408*cea60642SGarrett D'Amore 		reg &= ~MV_PSC_POL_REVERSE;
409*cea60642SGarrett D'Amore 		phy_write(ph, MVPHY_PSC, reg);
410*cea60642SGarrett D'Amore 	}
411*cea60642SGarrett D'Amore 	/* force TX CLOCK to 25 MHz */
412*cea60642SGarrett D'Amore 	PHY_SET(ph, MVPHY_EPSC, MV_EPSC_TX_CLK_25);
413*cea60642SGarrett D'Amore 
414*cea60642SGarrett D'Amore 	return (phy_reset(ph));
415*cea60642SGarrett D'Amore }
416*cea60642SGarrett D'Amore 
417*cea60642SGarrett D'Amore static int
418*cea60642SGarrett D'Amore mvphy_reset(phy_handle_t *ph)
419*cea60642SGarrett D'Amore {
420*cea60642SGarrett D'Amore 	uint16_t reg;
421*cea60642SGarrett D'Amore 
422*cea60642SGarrett D'Amore 	reg = phy_read(ph, MVPHY_PSC);
423*cea60642SGarrett D'Amore 
424*cea60642SGarrett D'Amore 	reg &= ~MV_PSC_AUTO_X_MODE;
425*cea60642SGarrett D'Amore 	reg |= MV_PSC_ASSERT_CRS_TX;
426*cea60642SGarrett D'Amore 	reg &= ~MV_PSC_POL_REVERSE;
427*cea60642SGarrett D'Amore 	phy_write(ph, MVPHY_PSC, reg);
428*cea60642SGarrett D'Amore 
429*cea60642SGarrett D'Amore 	PHY_SET(ph, MVPHY_EPSC, MV_EPSC_TX_CLK_25);
430*cea60642SGarrett D'Amore 
431*cea60642SGarrett D'Amore 	/* Normal BMCR reset now */
432*cea60642SGarrett D'Amore 	return (phy_reset(ph));
433*cea60642SGarrett D'Amore }
434*cea60642SGarrett D'Amore 
435*cea60642SGarrett D'Amore static int
436*cea60642SGarrett D'Amore mvphy_start(phy_handle_t *ph)
437*cea60642SGarrett D'Amore {
438*cea60642SGarrett D'Amore 	int rv;
439*cea60642SGarrett D'Amore 
440*cea60642SGarrett D'Amore 	rv = phy_start(ph);
441*cea60642SGarrett D'Amore 	/*
442*cea60642SGarrett D'Amore 	 * If not autonegotiating, then we need to reset the PHY according to
443*cea60642SGarrett D'Amore 	 * Marvell.  I don't think this is according to the spec.  Apparently
444*cea60642SGarrett D'Amore 	 * the register states are not lost during this.
445*cea60642SGarrett D'Amore 	 */
446*cea60642SGarrett D'Amore 	if ((rv == 0) && (!ph->phy_adv_aneg)) {
447*cea60642SGarrett D'Amore 		rv = ph->phy_reset(ph);
448*cea60642SGarrett D'Amore 	}
449*cea60642SGarrett D'Amore 	return (rv);
450*cea60642SGarrett D'Amore }
451*cea60642SGarrett D'Amore 
452*cea60642SGarrett D'Amore boolean_t
453*cea60642SGarrett D'Amore phy_marvell_probe(phy_handle_t *ph)
454*cea60642SGarrett D'Amore {
455*cea60642SGarrett D'Amore 	switch (MII_PHY_MFG(ph->phy_id)) {
456*cea60642SGarrett D'Amore 	case MII_OUI_MARVELL:
457*cea60642SGarrett D'Amore 		ph->phy_vendor = "Marvell";
458*cea60642SGarrett D'Amore 		switch (MII_PHY_MODEL(ph->phy_id)) {
459*cea60642SGarrett D'Amore 		case MII_MODEL_MARVELL_88E1000:
460*cea60642SGarrett D'Amore 		case MII_MODEL_MARVELL_88E1000_2:
461*cea60642SGarrett D'Amore 		case MII_MODEL_MARVELL_88E1000_3:
462*cea60642SGarrett D'Amore 			ph->phy_model = "88E1000";
463*cea60642SGarrett D'Amore 			ph->phy_reset = mvphy_reset;
464*cea60642SGarrett D'Amore 			break;
465*cea60642SGarrett D'Amore 		case MII_MODEL_MARVELL_88E1011:
466*cea60642SGarrett D'Amore 			ph->phy_model = "88E1011";
467*cea60642SGarrett D'Amore 			ph->phy_reset = mvphy_reset_88e1011;
468*cea60642SGarrett D'Amore 			break;
469*cea60642SGarrett D'Amore 		case MII_MODEL_MARVELL_88E1111:
470*cea60642SGarrett D'Amore 			ph->phy_model = "88E1111";
471*cea60642SGarrett D'Amore 			ph->phy_reset = mvphy_reset_88e1111;
472*cea60642SGarrett D'Amore 			break;
473*cea60642SGarrett D'Amore 		case MII_MODEL_MARVELL_88E1112:
474*cea60642SGarrett D'Amore 			ph->phy_model = "88E1112";
475*cea60642SGarrett D'Amore 			ph->phy_reset = mvphy_reset_88e1112;
476*cea60642SGarrett D'Amore 			break;
477*cea60642SGarrett D'Amore 		case MII_MODEL_MARVELL_88E1116:
478*cea60642SGarrett D'Amore 			ph->phy_model = "88E1116";
479*cea60642SGarrett D'Amore 			ph->phy_reset = mvphy_reset_88e1116;
480*cea60642SGarrett D'Amore 			break;
481*cea60642SGarrett D'Amore 		case MII_MODEL_MARVELL_88E1116R:
482*cea60642SGarrett D'Amore 			ph->phy_model = "88E1116R";
483*cea60642SGarrett D'Amore 			ph->phy_reset = mvphy_reset;
484*cea60642SGarrett D'Amore 			break;
485*cea60642SGarrett D'Amore 		case MII_MODEL_MARVELL_88E1118:
486*cea60642SGarrett D'Amore 			ph->phy_model = "88E1118";
487*cea60642SGarrett D'Amore 			ph->phy_reset = mvphy_reset_88e1118;
488*cea60642SGarrett D'Amore 			break;
489*cea60642SGarrett D'Amore 		case MII_MODEL_MARVELL_88E1149:
490*cea60642SGarrett D'Amore 			ph->phy_model = "88E1149";
491*cea60642SGarrett D'Amore 			ph->phy_reset = mvphy_reset;
492*cea60642SGarrett D'Amore 			ph->phy_reset = mvphy_reset_88e1149;
493*cea60642SGarrett D'Amore 			break;
494*cea60642SGarrett D'Amore 		case MII_MODEL_MARVELL_88E3016:
495*cea60642SGarrett D'Amore 			ph->phy_model = "88E3016";
496*cea60642SGarrett D'Amore 			ph->phy_reset = mvphy_reset_88e3016;
497*cea60642SGarrett D'Amore 			ph->phy_loop = mvphy_loop_88e3016;
498*cea60642SGarrett D'Amore 			break;
499*cea60642SGarrett D'Amore 		case MII_MODEL_MARVELL_88E3082:
500*cea60642SGarrett D'Amore 			ph->phy_model = "88E3082";
501*cea60642SGarrett D'Amore 			ph->phy_reset = mvphy_reset_88e3082;
502*cea60642SGarrett D'Amore 			break;
503*cea60642SGarrett D'Amore 		default:
504*cea60642SGarrett D'Amore 			/* Unknown PHY model */
505*cea60642SGarrett D'Amore 			return (B_FALSE);
506*cea60642SGarrett D'Amore 		}
507*cea60642SGarrett D'Amore 		break;
508*cea60642SGarrett D'Amore 
509*cea60642SGarrett D'Amore 	default:
510*cea60642SGarrett D'Amore 		return (B_FALSE);
511*cea60642SGarrett D'Amore 	}
512*cea60642SGarrett D'Amore 
513*cea60642SGarrett D'Amore 	ph->phy_start = mvphy_start;
514*cea60642SGarrett D'Amore 
515*cea60642SGarrett D'Amore 	return (B_TRUE);
516*cea60642SGarrett D'Amore }
517