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