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