xref: /netbsd-src/sys/dev/mii/ikphy.c (revision f3cfa6f6ce31685c6c4a758bc430e69eb99f50a4)
1 /*	$NetBSD: ikphy.c,v 1.15 2019/03/25 07:34:13 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.15 2019/03/25 07:34:13 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_PHY_DESC(xxMARVELL, I82563),
96 	MII_PHY_END,
97 };
98 
99 static int
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
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 	sc->mii_anegticks = MII_ANEGTICKS;
132 
133 	PHY_RESET(sc);
134 
135 	PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
136 	sc->mii_capabilities &= ma->mii_capmask;
137 	if (sc->mii_capabilities & BMSR_EXTSTAT)
138 		PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities);
139 	aprint_normal_dev(self, "");
140 	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
141 	    (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
142 		aprint_error("no media present");
143 	else
144 		mii_phy_add_media(sc);
145 	aprint_normal("\n");
146 }
147 
148 static int
149 ikphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
150 {
151 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
152 	uint16_t reg;
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
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 	/* Enable CRS on TX for half-duplex operation. */
209 	PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
210 	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
211 	/* Use 25MHz for both link down and 1000BASE-T for Tx clock */
212 	phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
213 	PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
214 
215 	/* set mdi/mid-x options */
216 	PHY_READ(sc, GG82563_PHY_SPEC_CTRL, &phy_data);
217 	phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
218 	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
219 		phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
220 	else
221 		phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
222 	/* set polarity correction */
223 	phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
224 	PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL, phy_data);
225 
226 	/* SW Reset the PHY so all changes take effect */
227 	PHY_RESET(sc);
228 
229 	/* for the i80003 */
230 	PHY_READ(sc, GG82563_PHY_SPEC_CTRL_2, &phy_data);
231 	phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
232 	PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL_2, phy_data);
233 
234 	/* Enable Electrical Idle on the PHY */
235 	PHY_READ(sc, GG82563_PHY_PWR_MGMT_CTRL, &phy_data);
236 	phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
237 	PHY_WRITE(sc, GG82563_PHY_PWR_MGMT_CTRL, phy_data);
238 
239 	PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL, &phy_data);
240 	phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
241 	PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, phy_data);
242 
243 	/*
244 	 * Workaround: Disable padding in Kumeran interface in the MAC
245 	 * and in the PHY to avoid CRC errors.
246 	 */
247 	PHY_READ(sc, GG82563_PHY_INBAND_CTRL, &phy_data);
248 	phy_data |= GG82563_ICR_DIS_PADDING;
249 	PHY_WRITE(sc, GG82563_PHY_INBAND_CTRL, phy_data);
250 
251 	mii_phy_setmedia(sc);
252 	if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
253 		/*
254 		 * When not in auto mode, we need to restart nego
255 		 * anyway, or a switch from a fixed mode to another
256 		 * fixed mode may not be seen by the switch.
257 		 */
258 		PHY_READ(sc, MII_BMCR, &phy_data);
259 		PHY_WRITE(sc, MII_BMCR, phy_data | BMCR_STARTNEG);
260 	}
261 	PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
262 	phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
263 	switch(IFM_SUBTYPE(ife->ifm_media)) {
264 	case IFM_10_T:
265 		phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ;
266 		break;
267 	case IFM_100_TX:
268 		phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25MHZ;
269 		break;
270 	case IFM_1000_T:
271 		phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
272 		break;
273 	}
274 	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
275 	PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
276 }
277 
278 static void
279 ikphy_status(struct mii_softc *sc)
280 {
281 	struct mii_data *mii = sc->mii_pdata;
282 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
283 	uint16_t pssr, bmcr, gtsr, kmrn;
284 
285 	mii->mii_media_status = IFM_AVALID;
286 	mii->mii_media_active = IFM_ETHER;
287 
288 	PHY_READ(sc, GG82563_PHY_SPEC_STATUS, &pssr);
289 
290 	if (pssr & GG82563_PSSR_LINK)
291 		mii->mii_media_status |= IFM_ACTIVE;
292 
293 	PHY_READ(sc, MII_BMCR, &bmcr);
294 	if (bmcr & BMCR_ISO) {
295 		mii->mii_media_active |= IFM_NONE;
296 		mii->mii_media_status = 0;
297 		return;
298 	}
299 
300 	if (bmcr & BMCR_LOOP)
301 		mii->mii_media_active |= IFM_LOOP;
302 
303 	if (bmcr & BMCR_AUTOEN) {
304 		/*
305 		 * The media status bits are only valid of autonegotiation
306 		 * has completed (or it's disabled).
307 		 */
308 		if ((pssr & GG82563_PSSR_SPEED_DUPLEX_RESOLVED) == 0) {
309 			/* Erg, still trying, I guess... */
310 			mii->mii_media_active |= IFM_NONE;
311 			return;
312 		}
313 
314 		switch (pssr & GG82563_PSSR_SPEED_MASK) {
315 		case GG82563_PSSR_SPEED_1000MBPS:
316 			mii->mii_media_active |= IFM_1000_T;
317 			PHY_READ(sc, MII_100T2SR, &gtsr);
318 			if (gtsr & GTSR_MS_RES)
319 				mii->mii_media_active |= IFM_ETH_MASTER;
320 			break;
321 
322 		case GG82563_PSSR_SPEED_100MBPS:
323 			mii->mii_media_active |= IFM_100_TX;
324 			break;
325 
326 		case GG82563_PSSR_SPEED_10MBPS:
327 			mii->mii_media_active |= IFM_10_T;
328 			break;
329 
330 		default:
331 			mii->mii_media_active |= IFM_NONE;
332 			mii->mii_media_status = 0;
333 			return;
334 		}
335 
336 		if (pssr & GG82563_PSSR_DUPLEX)
337 			mii->mii_media_active |=
338 			    IFM_FDX | mii_phy_flowstatus(sc);
339 		else
340 			mii->mii_media_active |= IFM_HDX;
341 	} else
342 		mii->mii_media_active = ife->ifm_media;
343 	PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL, &kmrn);
344 	if (mii->mii_media_active & IFM_FDX)
345 		kmrn &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
346 	else
347 		kmrn |= GG82563_KMCR_PASS_FALSE_CARRIER;
348 	PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, kmrn);
349 }
350