xref: /netbsd-src/sys/dev/mii/ikphy.c (revision 7a9a30c5e763bb556f73924ae04973e33cc385da)
1 /*	$NetBSD: ikphy.c,v 1.19 2020/03/15 23:04:50 thorpej 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.19 2020/03/15 23:04:50 thorpej 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_PHY_DESC(xxMARVELL, I82563),
96 	MII_PHY_END,
97 };
98 
99 static int
ikphymatch(device_t parent,cfdata_t match,void * aux)100 ikphymatch(device_t parent, cfdata_t match, void *aux)
101 {
102 	struct mii_attach_args *ma = aux;
103 
104 	if (mii_phy_match(ma, ikphys) != NULL)
105 		return 10;
106 
107 	return 0;
108 }
109 
110 static void
ikphyattach(device_t parent,device_t self,void * aux)111 ikphyattach(device_t parent, device_t self, void *aux)
112 {
113 	struct mii_softc *sc = device_private(self);
114 	struct mii_attach_args *ma = aux;
115 	struct mii_data *mii = ma->mii_data;
116 	const struct mii_phydesc *mpd;
117 
118 	mpd = mii_phy_match(ma, ikphys);
119 	aprint_naive(": Media interface\n");
120 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
121 
122 	sc->mii_dev = self;
123 	sc->mii_inst = mii->mii_instance;
124 	sc->mii_phy = ma->mii_phyno;
125 	sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
126 	sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
127 	sc->mii_mpd_rev = MII_REV(ma->mii_id2);
128 	sc->mii_funcs = &ikphy_funcs;
129 	sc->mii_pdata = mii;
130 	sc->mii_flags = ma->mii_flags;
131 
132 	mii_lock(mii);
133 
134 	PHY_RESET(sc);
135 
136 	PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
137 	sc->mii_capabilities &= ma->mii_capmask;
138 	if (sc->mii_capabilities & BMSR_EXTSTAT)
139 		PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities);
140 
141 	mii_unlock(mii);
142 
143 	mii_phy_add_media(sc);
144 }
145 
146 static int
ikphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)147 ikphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
148 {
149 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
150 	uint16_t reg;
151 
152 	KASSERT(mii_locked(mii));
153 
154 	switch (cmd) {
155 	case MII_POLLSTAT:
156 		/* If we're not polling our PHY instance, just return. */
157 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
158 			return 0;
159 		break;
160 
161 	case MII_MEDIACHG:
162 		/*
163 		 * If the media indicates a different PHY instance,
164 		 * isolate ourselves.
165 		 */
166 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
167 			PHY_READ(sc, MII_BMCR, &reg);
168 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
169 			return 0;
170 		}
171 
172 		/* If the interface is not up, don't do anything. */
173 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
174 			break;
175 
176 		ikphy_setmedia(sc);
177 		break;
178 
179 	case MII_TICK:
180 		/* If we're not currently selected, just return. */
181 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
182 			return 0;
183 
184 		if (mii_phy_tick(sc) == EJUSTRETURN)
185 			return 0;
186 		break;
187 
188 	case MII_DOWN:
189 		mii_phy_down(sc);
190 		return 0;
191 	}
192 
193 	/* Update the media status. */
194 	mii_phy_status(sc);
195 
196 	/* Callback if something changed. */
197 	mii_phy_update(sc, cmd);
198 	return 0;
199 }
200 
201 static void
ikphy_setmedia(struct mii_softc * sc)202 ikphy_setmedia(struct mii_softc *sc)
203 {
204 	uint16_t phy_data;
205 	struct mii_data *mii = sc->mii_pdata;
206 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
207 
208 	KASSERT(mii_locked(mii));
209 
210 	/* Enable CRS on TX for half-duplex operation. */
211 	PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
212 	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
213 	/* Use 25MHz for both link down and 1000BASE-T for Tx clock */
214 	phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
215 	PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
216 
217 	/* Set mdi/mid-x options */
218 	PHY_READ(sc, GG82563_PHY_SPEC_CTRL, &phy_data);
219 	phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
220 	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
221 		phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
222 	else
223 		phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
224 	/* Set polarity correction */
225 	phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
226 	PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL, phy_data);
227 
228 	/* SW Reset the PHY so all changes take effect */
229 	PHY_RESET(sc);
230 
231 	/* For the i80003 */
232 	PHY_READ(sc, GG82563_PHY_SPEC_CTRL_2, &phy_data);
233 	phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
234 	PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL_2, phy_data);
235 
236 	/* Enable Electrical Idle on the PHY */
237 	PHY_READ(sc, GG82563_PHY_PWR_MGMT_CTRL, &phy_data);
238 	phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
239 	PHY_WRITE(sc, GG82563_PHY_PWR_MGMT_CTRL, phy_data);
240 
241 	PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL, &phy_data);
242 	phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
243 	PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, phy_data);
244 
245 	/*
246 	 * Workaround: Disable padding in Kumeran interface in the MAC
247 	 * and in the PHY to avoid CRC errors.
248 	 */
249 	PHY_READ(sc, GG82563_PHY_INBAND_CTRL, &phy_data);
250 	phy_data |= GG82563_ICR_DIS_PADDING;
251 	PHY_WRITE(sc, GG82563_PHY_INBAND_CTRL, phy_data);
252 
253 	mii_phy_setmedia(sc);
254 	if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
255 		/*
256 		 * When not in auto mode, we need to restart nego
257 		 * anyway, or a switch from a fixed mode to another
258 		 * fixed mode may not be seen by the switch.
259 		 */
260 		PHY_READ(sc, MII_BMCR, &phy_data);
261 		PHY_WRITE(sc, MII_BMCR, phy_data | BMCR_STARTNEG);
262 	}
263 	PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
264 	phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
265 	switch (IFM_SUBTYPE(ife->ifm_media)) {
266 	case IFM_10_T:
267 		phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ;
268 		break;
269 	case IFM_100_TX:
270 		phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25MHZ;
271 		break;
272 	case IFM_1000_T:
273 		phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
274 		break;
275 	}
276 	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
277 	PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
278 }
279 
280 static void
ikphy_status(struct mii_softc * sc)281 ikphy_status(struct mii_softc *sc)
282 {
283 	struct mii_data *mii = sc->mii_pdata;
284 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
285 	uint16_t pssr, bmcr, gtsr, kmrn;
286 
287 	KASSERT(mii_locked(mii));
288 
289 	mii->mii_media_status = IFM_AVALID;
290 	mii->mii_media_active = IFM_ETHER;
291 
292 	PHY_READ(sc, GG82563_PHY_SPEC_STATUS, &pssr);
293 
294 	if (pssr & GG82563_PSSR_LINK)
295 		mii->mii_media_status |= IFM_ACTIVE;
296 
297 	PHY_READ(sc, MII_BMCR, &bmcr);
298 	if (bmcr & BMCR_ISO) {
299 		mii->mii_media_active |= IFM_NONE;
300 		mii->mii_media_status = 0;
301 		return;
302 	}
303 
304 	if (bmcr & BMCR_LOOP)
305 		mii->mii_media_active |= IFM_LOOP;
306 
307 	if (bmcr & BMCR_AUTOEN) {
308 		/*
309 		 * The media status bits are only valid if autonegotiation
310 		 * has completed (or it's disabled).
311 		 */
312 		if ((pssr & GG82563_PSSR_SPEED_DUPLEX_RESOLVED) == 0) {
313 			/* Erg, still trying, I guess... */
314 			mii->mii_media_active |= IFM_NONE;
315 			return;
316 		}
317 
318 		switch (pssr & GG82563_PSSR_SPEED_MASK) {
319 		case GG82563_PSSR_SPEED_1000MBPS:
320 			mii->mii_media_active |= IFM_1000_T;
321 			PHY_READ(sc, MII_100T2SR, &gtsr);
322 			if (gtsr & GTSR_MS_RES)
323 				mii->mii_media_active |= IFM_ETH_MASTER;
324 			break;
325 
326 		case GG82563_PSSR_SPEED_100MBPS:
327 			mii->mii_media_active |= IFM_100_TX;
328 			break;
329 
330 		case GG82563_PSSR_SPEED_10MBPS:
331 			mii->mii_media_active |= IFM_10_T;
332 			break;
333 
334 		default:
335 			mii->mii_media_active |= IFM_NONE;
336 			mii->mii_media_status = 0;
337 			return;
338 		}
339 
340 		if (pssr & GG82563_PSSR_DUPLEX)
341 			mii->mii_media_active |=
342 			    IFM_FDX | mii_phy_flowstatus(sc);
343 		else
344 			mii->mii_media_active |= IFM_HDX;
345 	} else
346 		mii->mii_media_active = ife->ifm_media;
347 	PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL, &kmrn);
348 	if (mii->mii_media_active & IFM_FDX)
349 		kmrn &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
350 	else
351 		kmrn |= GG82563_KMCR_PASS_FALSE_CARRIER;
352 	PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, kmrn);
353 }
354