xref: /netbsd-src/sys/dev/mii/ikphy.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /*	$NetBSD: ikphy.c,v 1.8 2008/11/17 03:04:27 dyoung Exp $	*/
2 
3 /*******************************************************************************
4 Copyright (c) 2001-2005, Intel Corporation
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10  1. Redistributions of source code must retain the above copyright notice,
11     this list of conditions and the following disclaimer.
12 
13  2. Redistributions in binary form must reproduce the above copyright
14     notice, this list of conditions and the following disclaimer in the
15     documentation and/or other materials provided with the distribution.
16 
17  3. Neither the name of the Intel Corporation nor the names of its
18     contributors may be used to endorse or promote products derived from
19     this software without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32 *******************************************************************************/
33 /*
34  * Copyright (c) 2006 Manuel Bouyer.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *	This product includes software developed by Manuel Bouyer.
47  * 4. The name of the author may not be used to endorse or promote products
48  *    derived from this software without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
51  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
52  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
54  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
55  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
59  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60  */
61 
62 /*
63  * driver for Intel's i82563 ethernet 10/100/1000 PHY
64  */
65 
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(0, "$NetBSD: ikphy.c,v 1.8 2008/11/17 03:04:27 dyoung Exp $");
68 
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/kernel.h>
72 #include <sys/device.h>
73 #include <sys/socket.h>
74 #include <sys/errno.h>
75 
76 #include <net/if.h>
77 #include <net/if_media.h>
78 
79 #include <dev/mii/mii.h>
80 #include <dev/mii/miivar.h>
81 #include <dev/mii/miidevs.h>
82 
83 #include <dev/mii/ikphyreg.h>
84 
85 static int	ikphymatch(device_t, cfdata_t, void *);
86 static void	ikphyattach(device_t, device_t, void *);
87 
88 CFATTACH_DECL_NEW(ikphy, sizeof(struct mii_softc),
89     ikphymatch, ikphyattach, mii_phy_detach, mii_phy_activate);
90 
91 static int	ikphy_service(struct mii_softc *, struct mii_data *, int);
92 static void	ikphy_status(struct mii_softc *);
93 static void	ikphy_setmedia(struct mii_softc *);
94 
95 static const struct mii_phy_funcs ikphy_funcs = {
96 	ikphy_service, ikphy_status, mii_phy_reset,
97 };
98 
99 static const struct mii_phydesc ikphys[] = {
100 	{ MII_OUI_xxMARVELL,		MII_MODEL_xxMARVELL_I82563,
101 	  MII_STR_xxMARVELL_I82563 },
102 
103 	{ 0,				0,
104 	  NULL },
105 };
106 
107 static int
108 ikphymatch(device_t parent, cfdata_t match, void *aux)
109 {
110 	struct mii_attach_args *ma = aux;
111 
112 	if (mii_phy_match(ma, ikphys) != NULL)
113 		return (10);
114 
115 	return (0);
116 }
117 
118 static void
119 ikphyattach(device_t parent, device_t self, void *aux)
120 {
121 	struct mii_softc *sc = device_private(self);
122 	struct mii_attach_args *ma = aux;
123 	struct mii_data *mii = ma->mii_data;
124 	const struct mii_phydesc *mpd;
125 
126 	mpd = mii_phy_match(ma, ikphys);
127 	aprint_naive(": Media interface\n");
128 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
129 
130 	sc->mii_dev = self;
131 	sc->mii_inst = mii->mii_instance;
132 	sc->mii_phy = ma->mii_phyno;
133 	sc->mii_funcs = &ikphy_funcs;
134 	sc->mii_pdata = mii;
135 	sc->mii_flags = ma->mii_flags;
136 	sc->mii_anegticks = MII_ANEGTICKS;
137 
138 	PHY_RESET(sc);
139 
140 	sc->mii_capabilities =
141 	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
142 	if (sc->mii_capabilities & BMSR_EXTSTAT)
143 	    sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
144 	aprint_normal_dev(self, "");
145 	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
146 	    (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
147 		aprint_error("no media present");
148 	else
149 		mii_phy_add_media(sc);
150 	aprint_normal("\n");
151 }
152 
153 static int
154 ikphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
155 {
156 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
157 	int reg;
158 
159 	switch (cmd) {
160 	case MII_POLLSTAT:
161 		/*
162 		 * If we're not polling our PHY instance, just return.
163 		 */
164 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
165 			return (0);
166 		break;
167 
168 	case MII_MEDIACHG:
169 		/*
170 		 * If the media indicates a different PHY instance,
171 		 * isolate ourselves.
172 		 */
173 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
174 			reg = PHY_READ(sc, MII_BMCR);
175 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
176 			return (0);
177 		}
178 
179 		/*
180 		 * If the interface is not up, don't do anything.
181 		 */
182 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
183 			break;
184 
185 		ikphy_setmedia(sc);
186 		break;
187 
188 	case MII_TICK:
189 		/*
190 		 * If we're not currently selected, just return.
191 		 */
192 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
193 			return (0);
194 
195 		if (mii_phy_tick(sc) == EJUSTRETURN)
196 			return (0);
197 		break;
198 
199 	case MII_DOWN:
200 		mii_phy_down(sc);
201 		return (0);
202 	}
203 
204 	/* Update the media status. */
205 	mii_phy_status(sc);
206 
207 	/* Callback if something changed. */
208 	mii_phy_update(sc, cmd);
209 	return (0);
210 }
211 
212 static void
213 ikphy_setmedia(struct mii_softc *sc)
214 {
215 	uint16_t phy_data;
216 	struct mii_data *mii = sc->mii_pdata;
217 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
218 
219 	/* Enable CRS on TX for half-duplex operation. */
220 	phy_data = PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL);
221 	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
222 	/* Use 25MHz for both link down and 1000BASE-T for Tx clock */
223 	phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
224 	PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
225 
226 	/* set mdi/mid-x options */
227 	phy_data = PHY_READ(sc, GG82563_PHY_SPEC_CTRL);
228 	phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
229 	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
230 		phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
231 	else
232 		phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
233 	/* set polarity correction */
234 	phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
235 	PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL, phy_data);
236 
237 	/* SW Reset the PHY so all changes take effect */
238 	PHY_RESET(sc);
239 
240 	/* for the i80003 */
241 	phy_data = PHY_READ(sc, GG82563_PHY_SPEC_CTRL_2);
242 	phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
243 	PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL_2, phy_data);
244 
245 	/* Enable Electrical Idle on the PHY */
246 	phy_data = PHY_READ(sc, GG82563_PHY_PWR_MGMT_CTRL);
247 	phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
248 	PHY_WRITE(sc, GG82563_PHY_PWR_MGMT_CTRL, phy_data);
249 
250 	phy_data = PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL);
251 	phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
252 	PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, phy_data);
253 
254 	/*
255 	 * Workaround: Disable padding in Kumeran interface in the MAC
256 	 * and in the PHY to avoid CRC errors.
257 	 */
258 	phy_data = PHY_READ(sc, GG82563_PHY_INBAND_CTRL);
259 	phy_data |= GG82563_ICR_DIS_PADDING;
260 	PHY_WRITE(sc, GG82563_PHY_INBAND_CTRL, phy_data);
261 
262 	mii_phy_setmedia(sc);
263 	if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
264 		/*
265 		 * when not in auto mode, we need to restart nego
266 		 * anyway, or a switch from a fixed mode to another
267 		 * fixed mode may not be seen by the switch.
268 		 */
269 		PHY_WRITE(sc, MII_BMCR,
270 		    PHY_READ(sc, MII_BMCR) | BMCR_STARTNEG);
271 	}
272 	phy_data = PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL);
273 	phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
274 	switch(IFM_SUBTYPE(ife->ifm_media)) {
275 	case IFM_10_T:
276 		phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ;
277 		break;
278 	case IFM_100_TX:
279 		phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25MHZ;
280 		break;
281 	case IFM_1000_T:
282 		phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
283 		break;
284 	}
285 	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
286 	PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
287 }
288 
289 static void
290 ikphy_status(struct mii_softc *sc)
291 {
292 	struct mii_data *mii = sc->mii_pdata;
293 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
294 	int pssr, bmcr, gtsr, kmrn;
295 
296 	mii->mii_media_status = IFM_AVALID;
297 	mii->mii_media_active = IFM_ETHER;
298 
299 	pssr = PHY_READ(sc, GG82563_PHY_SPEC_STATUS);
300 
301 	if (pssr & GG82563_PSSR_LINK)
302 		mii->mii_media_status |= IFM_ACTIVE;
303 
304 	bmcr = PHY_READ(sc, MII_BMCR);
305 	if (bmcr & BMCR_ISO) {
306 		mii->mii_media_active |= IFM_NONE;
307 		mii->mii_media_status = 0;
308 		return;
309 	}
310 
311 	if (bmcr & BMCR_LOOP)
312 		mii->mii_media_active |= IFM_LOOP;
313 
314 	if (bmcr & BMCR_AUTOEN) {
315 		/*
316 		 * The media status bits are only valid of autonegotiation
317 		 * has completed (or it's disabled).
318 		 */
319 		if ((pssr & GG82563_PSSR_SPEED_DUPLEX_RESOLVED) == 0) {
320 			/* Erg, still trying, I guess... */
321 			mii->mii_media_active |= IFM_NONE;
322 			return;
323 		}
324 
325 		switch (pssr & GG82563_PSSR_SPEED_MASK) {
326 		case GG82563_PSSR_SPEED_1000MBPS:
327 			mii->mii_media_active |= IFM_1000_T;
328 			gtsr = PHY_READ(sc, MII_100T2SR);
329 			if (gtsr & GTSR_MS_RES)
330 				mii->mii_media_active |= IFM_ETH_MASTER;
331 			break;
332 
333 		case GG82563_PSSR_SPEED_100MBPS:
334 			mii->mii_media_active |= IFM_100_TX;
335 			break;
336 
337 		case GG82563_PSSR_SPEED_10MBPS:
338 			mii->mii_media_active |= IFM_10_T;
339 			break;
340 
341 		default:
342 			mii->mii_media_active |= IFM_NONE;
343 			mii->mii_media_status = 0;
344 			return;
345 		}
346 
347 		if (pssr & GG82563_PSSR_DUPLEX)
348 			mii->mii_media_active |=
349 			    IFM_FDX | mii_phy_flowstatus(sc);
350 	} else
351 		mii->mii_media_active = ife->ifm_media;
352 	kmrn = PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL);
353 	if (mii->mii_media_active & IFM_FDX)
354 		kmrn &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
355 	else
356 		kmrn |= GG82563_KMCR_PASS_FALSE_CARRIER;
357 	PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, kmrn);
358 }
359