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