urlphy.c revision 1.3 1 /* $NetBSD: urlphy.c,v 1.3 2002/09/27 02:24:30 thorpej Exp $ */
2 /*
3 * Copyright (c) 2001, 2002
4 * Shingo WATANABE <nabe (at) nabechan.org>. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Shingo WATANABE.
17 * 4. Neither the name of the author nor the names of any co-contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * 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 AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 */
34
35 /*
36 * driver for Realtek RL8150L internal phy
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: urlphy.c,v 1.3 2002/09/27 02:24:30 thorpej Exp $");
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/device.h>
46 #include <sys/socket.h>
47
48 #include <net/if.h>
49 #include <net/if_media.h>
50
51 #include <dev/mii/mii.h>
52 #include <dev/mii/miivar.h>
53 #include <dev/mii/miidevs.h>
54 #include <dev/mii/urlphyreg.h>
55
56 #define URLPHY_DEBUG 0
57 #ifdef URLPHY_DEBUG
58 #define DPRINTF(x) if (urlphydebug) printf x
59 #define DPRINTFN(n,x) if (urlphydebug>(n)) printf x
60 int urlphydebug = URLPHY_DEBUG;
61 #else
62 #define DPRINTF(x)
63 #define DPRINTFN(n,x)
64 #endif
65
66 int urlphy_match(struct device *, struct cfdata *, void *);
67 void urlphy_attach(struct device *, struct device *, void *);
68
69 struct cfattach urlphy_ca = {
70 sizeof(struct mii_softc), urlphy_match, urlphy_attach, mii_phy_detach,
71 mii_phy_activate
72 };
73
74 int urlphy_service(struct mii_softc *, struct mii_data *, int);
75 void urlphy_status(struct mii_softc *);
76
77 const struct mii_phy_funcs urlphy_funcs = {
78 urlphy_service, urlphy_status, mii_phy_reset,
79 };
80
81 int
82 urlphy_match(struct device *parent, struct cfdata *match, void *aux)
83 {
84 struct mii_attach_args *ma = aux;
85
86 /*
87 * RTL8150 reports OUT == 0, MODEL == 0
88 */
89 if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 &&
90 MII_MODEL(ma->mii_id2) != 0)
91 return (0);
92
93 /*
94 * Make sure the parent is an 'url' device.
95 */
96 if (strcmp(parent->dv_cfdata->cf_name, "url") != 0)
97 return(0);
98
99 return (10);
100 }
101
102 void
103 urlphy_attach(struct device *parent, struct device *self, void *aux)
104 {
105 struct mii_softc *sc = (struct mii_softc *)self;
106 struct mii_attach_args *ma = aux;
107 struct mii_data *mii = ma->mii_data;
108
109 printf(": Realtek RTL8150L internal media interface\n");
110
111 DPRINTF(("%s: %s: enter\n", sc->mii_dev.dv_xname, __FUNCTION__));
112
113 sc->mii_inst = mii->mii_instance;
114 sc->mii_phy = ma->mii_phyno;
115 sc->mii_funcs = &urlphy_funcs;
116 sc->mii_pdata = mii;
117 sc->mii_flags = mii->mii_flags;
118 sc->mii_anegticks = 10;
119
120 /* Don't do loopback on this PHY. */
121 sc->mii_flags |= MIIF_NOLOOP;
122 /* Don't do isolate on this PHY. */
123 sc->mii_flags |= MIIF_NOISOLATE;
124
125 if (mii->mii_instance != 0) {
126 printf("%s: ignoring this PHY, non-zero instance\n",
127 sc->mii_dev.dv_xname);
128 return;
129 }
130 PHY_RESET(sc);
131
132 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
133 printf("%s: ", sc->mii_dev.dv_xname);
134 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
135 printf("no media present");
136 else
137 mii_phy_add_media(sc);
138 printf("\n");
139 }
140
141 int
142 urlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
143 {
144 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
145 int reg;
146
147 DPRINTF(("%s: %s: enter\n", sc->mii_dev.dv_xname, __FUNCTION__));
148
149 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
150 return (ENXIO);
151
152 switch (cmd) {
153 case MII_POLLSTAT:
154 /*
155 * If we're not polling our PHY instance, just return.
156 */
157 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
158 return (0);
159 break;
160
161 case MII_MEDIACHG:
162 /*
163 * If we're not currently selected, just return.
164 */
165 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
166 return (0);
167
168 /* If the interface is not up, don't do anything. */
169 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
170 break;
171
172 mii_phy_setmedia(sc);
173 break;
174
175 case MII_TICK:
176 /*
177 * If we're not currently selected, just return.
178 */
179 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
180 return (0);
181
182 /* Just bail now if the interface is down. */
183 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
184 return (0);
185
186 /*
187 * If we're not doing autonegotiation, we don't need to do
188 * any extra work here. However, we need to check the link
189 * status so we can generate an announcement if the status
190 * changes.
191 */
192 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
193 return (0);
194
195 /* Read the status register twice; MSR_LINK is latch-low. */
196 reg = PHY_READ(sc, URLPHY_MSR) | PHY_READ(sc, URLPHY_MSR);
197 if (reg & URLPHY_MSR_LINK)
198 return (0);
199
200 /*
201 * Only retry autonegotiation every N seconds.
202 */
203 KASSERT(sc->mii_anegticks != 0);
204 if (++sc->mii_ticks != sc->mii_anegticks)
205 return (0);
206
207 sc->mii_ticks = 0;
208 PHY_RESET(sc);
209
210 if (mii_phy_auto(sc, 0) == EJUSTRETURN)
211 return (0);
212
213 break;
214
215 case MII_DOWN:
216 mii_phy_down(sc);
217 return (0);
218 }
219
220 /* Update the media status. */
221 mii_phy_status(sc);
222
223 /* Callback if something changed. */
224 mii_phy_update(sc, cmd);
225
226 return (0);
227 }
228
229 void
230 urlphy_status(struct mii_softc *sc)
231 {
232 struct mii_data *mii = sc->mii_pdata;
233 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
234 int msr, bmsr, bmcr;
235
236 DPRINTF(("%s: %s: enter\n", sc->mii_dev.dv_xname, __FUNCTION__));
237
238 mii->mii_media_status = IFM_AVALID;
239 mii->mii_media_active = IFM_ETHER;
240
241 /*
242 * The link status bit is not exist in the BMSR register,
243 * so we need to read the MSR register to get link status.
244 */
245 msr = PHY_READ(sc, URLPHY_MSR) | PHY_READ(sc, URLPHY_MSR);
246 if (msr & URLPHY_MSR_LINK)
247 mii->mii_media_status |= IFM_ACTIVE;
248
249 DPRINTF(("%s: %s: link %s\n", sc->mii_dev.dv_xname, __FUNCTION__,
250 mii->mii_media_status & IFM_ACTIVE ? "up" : "down"));
251
252 bmcr = PHY_READ(sc, MII_BMCR);
253 if (bmcr & BMCR_AUTOEN) {
254 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
255 if ((bmsr & BMSR_ACOMP) == 0) {
256 /* Erg, still trying, I guess... */
257 mii->mii_media_active |= IFM_NONE;
258 return;
259 }
260
261 if (msr & URLPHY_MSR_SPEED_100)
262 mii->mii_media_active |= IFM_100_TX;
263 else
264 mii->mii_media_active |= IFM_10_T;
265 if (msr & URLPHY_MSR_DUPLEX)
266 mii->mii_media_active |= IFM_FDX;
267 } else
268 mii->mii_media_active = ife->ifm_media;
269 }
270