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