ikphy.c revision 1.15 1 1.15 msaitoh /* $NetBSD: ikphy.c,v 1.15 2019/03/25 07:34:13 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.15 msaitoh __KERNEL_RCSID(0, "$NetBSD: ikphy.c,v 1.15 2019/03/25 07:34:13 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.3 christos sc->mii_anegticks = MII_ANEGTICKS;
132 1.1 bouyer
133 1.1 bouyer PHY_RESET(sc);
134 1.1 bouyer
135 1.13 msaitoh PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
136 1.13 msaitoh sc->mii_capabilities &= ma->mii_capmask;
137 1.1 bouyer if (sc->mii_capabilities & BMSR_EXTSTAT)
138 1.13 msaitoh PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities);
139 1.7 xtraeme aprint_normal_dev(self, "");
140 1.1 bouyer if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
141 1.1 bouyer (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
142 1.1 bouyer aprint_error("no media present");
143 1.1 bouyer else
144 1.1 bouyer mii_phy_add_media(sc);
145 1.1 bouyer aprint_normal("\n");
146 1.1 bouyer }
147 1.1 bouyer
148 1.1 bouyer static int
149 1.1 bouyer ikphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
150 1.1 bouyer {
151 1.1 bouyer struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
152 1.13 msaitoh uint16_t reg;
153 1.1 bouyer
154 1.1 bouyer switch (cmd) {
155 1.1 bouyer case MII_POLLSTAT:
156 1.15 msaitoh /* If we're not polling our PHY instance, just return. */
157 1.1 bouyer if (IFM_INST(ife->ifm_media) != sc->mii_inst)
158 1.15 msaitoh return 0;
159 1.1 bouyer break;
160 1.1 bouyer
161 1.1 bouyer case MII_MEDIACHG:
162 1.1 bouyer /*
163 1.1 bouyer * If the media indicates a different PHY instance,
164 1.1 bouyer * isolate ourselves.
165 1.1 bouyer */
166 1.1 bouyer if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
167 1.13 msaitoh PHY_READ(sc, MII_BMCR, ®);
168 1.1 bouyer PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
169 1.15 msaitoh return 0;
170 1.1 bouyer }
171 1.1 bouyer
172 1.15 msaitoh /* If the interface is not up, don't do anything. */
173 1.1 bouyer if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
174 1.1 bouyer break;
175 1.1 bouyer
176 1.1 bouyer ikphy_setmedia(sc);
177 1.1 bouyer break;
178 1.1 bouyer
179 1.1 bouyer case MII_TICK:
180 1.15 msaitoh /* If we're not currently selected, just return. */
181 1.1 bouyer if (IFM_INST(ife->ifm_media) != sc->mii_inst)
182 1.15 msaitoh return 0;
183 1.1 bouyer
184 1.1 bouyer if (mii_phy_tick(sc) == EJUSTRETURN)
185 1.15 msaitoh return 0;
186 1.1 bouyer break;
187 1.1 bouyer
188 1.1 bouyer case MII_DOWN:
189 1.1 bouyer mii_phy_down(sc);
190 1.15 msaitoh return 0;
191 1.1 bouyer }
192 1.1 bouyer
193 1.1 bouyer /* Update the media status. */
194 1.1 bouyer mii_phy_status(sc);
195 1.1 bouyer
196 1.1 bouyer /* Callback if something changed. */
197 1.1 bouyer mii_phy_update(sc, cmd);
198 1.15 msaitoh return 0;
199 1.1 bouyer }
200 1.1 bouyer
201 1.1 bouyer static void
202 1.1 bouyer ikphy_setmedia(struct mii_softc *sc)
203 1.1 bouyer {
204 1.1 bouyer uint16_t phy_data;
205 1.1 bouyer struct mii_data *mii = sc->mii_pdata;
206 1.1 bouyer struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
207 1.1 bouyer
208 1.1 bouyer /* Enable CRS on TX for half-duplex operation. */
209 1.13 msaitoh PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
210 1.1 bouyer phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
211 1.1 bouyer /* Use 25MHz for both link down and 1000BASE-T for Tx clock */
212 1.1 bouyer phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
213 1.1 bouyer PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
214 1.1 bouyer
215 1.1 bouyer /* set mdi/mid-x options */
216 1.13 msaitoh PHY_READ(sc, GG82563_PHY_SPEC_CTRL, &phy_data);
217 1.1 bouyer phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
218 1.1 bouyer if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
219 1.1 bouyer phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
220 1.1 bouyer else
221 1.1 bouyer phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
222 1.1 bouyer /* set polarity correction */
223 1.1 bouyer phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
224 1.1 bouyer PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL, phy_data);
225 1.1 bouyer
226 1.1 bouyer /* SW Reset the PHY so all changes take effect */
227 1.1 bouyer PHY_RESET(sc);
228 1.1 bouyer
229 1.1 bouyer /* for the i80003 */
230 1.13 msaitoh PHY_READ(sc, GG82563_PHY_SPEC_CTRL_2, &phy_data);
231 1.1 bouyer phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
232 1.1 bouyer PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL_2, phy_data);
233 1.1 bouyer
234 1.1 bouyer /* Enable Electrical Idle on the PHY */
235 1.13 msaitoh PHY_READ(sc, GG82563_PHY_PWR_MGMT_CTRL, &phy_data);
236 1.1 bouyer phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
237 1.1 bouyer PHY_WRITE(sc, GG82563_PHY_PWR_MGMT_CTRL, phy_data);
238 1.1 bouyer
239 1.13 msaitoh PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL, &phy_data);
240 1.1 bouyer phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
241 1.1 bouyer PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, phy_data);
242 1.1 bouyer
243 1.1 bouyer /*
244 1.1 bouyer * Workaround: Disable padding in Kumeran interface in the MAC
245 1.1 bouyer * and in the PHY to avoid CRC errors.
246 1.1 bouyer */
247 1.13 msaitoh PHY_READ(sc, GG82563_PHY_INBAND_CTRL, &phy_data);
248 1.1 bouyer phy_data |= GG82563_ICR_DIS_PADDING;
249 1.1 bouyer PHY_WRITE(sc, GG82563_PHY_INBAND_CTRL, phy_data);
250 1.1 bouyer
251 1.1 bouyer mii_phy_setmedia(sc);
252 1.1 bouyer if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
253 1.1 bouyer /*
254 1.15 msaitoh * When not in auto mode, we need to restart nego
255 1.1 bouyer * anyway, or a switch from a fixed mode to another
256 1.1 bouyer * fixed mode may not be seen by the switch.
257 1.1 bouyer */
258 1.13 msaitoh PHY_READ(sc, MII_BMCR, &phy_data);
259 1.13 msaitoh PHY_WRITE(sc, MII_BMCR, phy_data | BMCR_STARTNEG);
260 1.1 bouyer }
261 1.13 msaitoh PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
262 1.1 bouyer phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
263 1.1 bouyer switch(IFM_SUBTYPE(ife->ifm_media)) {
264 1.1 bouyer case IFM_10_T:
265 1.1 bouyer phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ;
266 1.1 bouyer break;
267 1.1 bouyer case IFM_100_TX:
268 1.1 bouyer phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25MHZ;
269 1.1 bouyer break;
270 1.1 bouyer case IFM_1000_T:
271 1.1 bouyer phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
272 1.1 bouyer break;
273 1.1 bouyer }
274 1.1 bouyer phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
275 1.1 bouyer PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
276 1.1 bouyer }
277 1.1 bouyer
278 1.1 bouyer static void
279 1.1 bouyer ikphy_status(struct mii_softc *sc)
280 1.1 bouyer {
281 1.1 bouyer struct mii_data *mii = sc->mii_pdata;
282 1.1 bouyer struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
283 1.13 msaitoh uint16_t pssr, bmcr, gtsr, kmrn;
284 1.1 bouyer
285 1.1 bouyer mii->mii_media_status = IFM_AVALID;
286 1.1 bouyer mii->mii_media_active = IFM_ETHER;
287 1.1 bouyer
288 1.13 msaitoh PHY_READ(sc, GG82563_PHY_SPEC_STATUS, &pssr);
289 1.1 bouyer
290 1.1 bouyer if (pssr & GG82563_PSSR_LINK)
291 1.1 bouyer mii->mii_media_status |= IFM_ACTIVE;
292 1.1 bouyer
293 1.13 msaitoh PHY_READ(sc, MII_BMCR, &bmcr);
294 1.1 bouyer if (bmcr & BMCR_ISO) {
295 1.1 bouyer mii->mii_media_active |= IFM_NONE;
296 1.1 bouyer mii->mii_media_status = 0;
297 1.1 bouyer return;
298 1.1 bouyer }
299 1.1 bouyer
300 1.1 bouyer if (bmcr & BMCR_LOOP)
301 1.1 bouyer mii->mii_media_active |= IFM_LOOP;
302 1.1 bouyer
303 1.1 bouyer if (bmcr & BMCR_AUTOEN) {
304 1.1 bouyer /*
305 1.1 bouyer * The media status bits are only valid of autonegotiation
306 1.1 bouyer * has completed (or it's disabled).
307 1.1 bouyer */
308 1.1 bouyer if ((pssr & GG82563_PSSR_SPEED_DUPLEX_RESOLVED) == 0) {
309 1.1 bouyer /* Erg, still trying, I guess... */
310 1.1 bouyer mii->mii_media_active |= IFM_NONE;
311 1.1 bouyer return;
312 1.1 bouyer }
313 1.1 bouyer
314 1.1 bouyer switch (pssr & GG82563_PSSR_SPEED_MASK) {
315 1.1 bouyer case GG82563_PSSR_SPEED_1000MBPS:
316 1.1 bouyer mii->mii_media_active |= IFM_1000_T;
317 1.13 msaitoh PHY_READ(sc, MII_100T2SR, >sr);
318 1.1 bouyer if (gtsr & GTSR_MS_RES)
319 1.1 bouyer mii->mii_media_active |= IFM_ETH_MASTER;
320 1.1 bouyer break;
321 1.1 bouyer
322 1.1 bouyer case GG82563_PSSR_SPEED_100MBPS:
323 1.1 bouyer mii->mii_media_active |= IFM_100_TX;
324 1.1 bouyer break;
325 1.1 bouyer
326 1.1 bouyer case GG82563_PSSR_SPEED_10MBPS:
327 1.1 bouyer mii->mii_media_active |= IFM_10_T;
328 1.1 bouyer break;
329 1.1 bouyer
330 1.1 bouyer default:
331 1.1 bouyer mii->mii_media_active |= IFM_NONE;
332 1.1 bouyer mii->mii_media_status = 0;
333 1.1 bouyer return;
334 1.1 bouyer }
335 1.1 bouyer
336 1.1 bouyer if (pssr & GG82563_PSSR_DUPLEX)
337 1.1 bouyer mii->mii_media_active |=
338 1.1 bouyer IFM_FDX | mii_phy_flowstatus(sc);
339 1.10 msaitoh else
340 1.10 msaitoh mii->mii_media_active |= IFM_HDX;
341 1.1 bouyer } else
342 1.1 bouyer mii->mii_media_active = ife->ifm_media;
343 1.13 msaitoh PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL, &kmrn);
344 1.1 bouyer if (mii->mii_media_active & IFM_FDX)
345 1.1 bouyer kmrn &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
346 1.1 bouyer else
347 1.1 bouyer kmrn |= GG82563_KMCR_PASS_FALSE_CARRIER;
348 1.1 bouyer PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, kmrn);
349 1.1 bouyer }
350