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