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