Line data Source code
1 : /* $OpenBSD: jmphy.c,v 1.6 2015/03/14 03:38:48 jsg Exp $ */
2 : /*-
3 : * Copyright (c) 2008, Pyun YongHyeon <yongari@FreeBSD.org>
4 : * 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 unmodified, this list of conditions, and the following
11 : * disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : *
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 : * SUCH DAMAGE.
27 : *
28 : * $FreeBSD: src/sys/dev/mii/jmphy.c,v 1.1 2008/05/27 01:16:40 yongari Exp $
29 : * $DragonFly: src/sys/dev/netif/mii_layer/jmphy.c,v 1.1 2008/07/22 11:28:49 sephe Exp $
30 : */
31 :
32 : /*
33 : * Driver for the JMicron JMP211 10/100/1000, JMP202 10/100 PHY.
34 : */
35 :
36 : #include <sys/param.h>
37 : #include <sys/systm.h>
38 : #include <sys/device.h>
39 : #include <sys/socket.h>
40 :
41 : #include <net/if.h>
42 : #include <net/if_var.h>
43 : #include <net/if_media.h>
44 :
45 : #include <dev/mii/mii.h>
46 : #include <dev/mii/miivar.h>
47 : #include <dev/mii/miidevs.h>
48 : #include <dev/mii/jmphyreg.h>
49 :
50 : int jmphy_service(struct mii_softc *, struct mii_data *, int);
51 : void jmphy_status(struct mii_softc *);
52 : int jmphy_match(struct device *, void *, void *);
53 : void jmphy_attach(struct device *, struct device *, void *);
54 : void jmphy_reset(struct mii_softc *);
55 : uint16_t jmphy_anar(struct ifmedia_entry *);
56 : int jmphy_auto(struct mii_softc *, struct ifmedia_entry *);
57 :
58 : const struct mii_phy_funcs jmphy_funcs = {
59 : jmphy_service, jmphy_status, jmphy_reset,
60 : };
61 :
62 : struct cfattach jmphy_ca = {
63 : sizeof (struct mii_softc), jmphy_match, jmphy_attach,
64 : mii_phy_detach
65 : };
66 :
67 : struct cfdriver jmphy_cd = {
68 : NULL, "jmphy", DV_DULL
69 : };
70 :
71 : static const struct mii_phydesc jmphys[] = {
72 : { MII_OUI_JMICRON, MII_MODEL_JMICRON_JMP202,
73 : MII_STR_JMICRON_JMP202 },
74 : { MII_OUI_JMICRON, MII_MODEL_JMICRON_JMP211,
75 : MII_STR_JMICRON_JMP211 },
76 : { 0, 0,
77 : NULL },
78 : };
79 :
80 : int
81 0 : jmphy_match(struct device *parent, void *match, void *aux)
82 : {
83 0 : struct mii_attach_args *ma = aux;
84 :
85 0 : if (mii_phy_match(ma, jmphys) != NULL)
86 0 : return (10);
87 :
88 0 : return (0);
89 0 : }
90 :
91 : void
92 0 : jmphy_attach(struct device *parent, struct device *self, void *aux)
93 : {
94 0 : struct mii_softc *sc = (struct mii_softc *)self;
95 0 : struct mii_attach_args *ma = aux;
96 0 : struct mii_data *mii = ma->mii_data;
97 : const struct mii_phydesc *mpd;
98 :
99 0 : mpd = mii_phy_match(ma, jmphys);
100 0 : printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
101 :
102 0 : sc->mii_inst = mii->mii_instance;
103 0 : sc->mii_phy = ma->mii_phyno;
104 0 : sc->mii_funcs = &jmphy_funcs;
105 0 : sc->mii_model = MII_MODEL(ma->mii_id2);
106 0 : sc->mii_pdata = mii;
107 0 : sc->mii_flags = ma->mii_flags;
108 :
109 0 : sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP;
110 :
111 0 : PHY_RESET(sc);
112 :
113 0 : sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
114 0 : if (sc->mii_capabilities & BMSR_EXTSTAT)
115 0 : sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
116 :
117 0 : if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
118 0 : (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
119 : ;
120 : else
121 0 : mii_phy_add_media(sc);
122 0 : }
123 :
124 : int
125 0 : jmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
126 : {
127 0 : struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
128 : uint16_t bmcr;
129 :
130 0 : switch (cmd) {
131 : case MII_POLLSTAT:
132 : /*
133 : * If we're not polling our PHY instance, just return.
134 : */
135 0 : if (IFM_INST(ife->ifm_media) != sc->mii_inst)
136 0 : return (0);
137 : break;
138 :
139 : case MII_MEDIACHG:
140 : /*
141 : * If the media indicates a different PHY instance,
142 : * isolate ourselves.
143 : */
144 0 : if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
145 0 : bmcr = PHY_READ(sc, MII_BMCR);
146 0 : PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO);
147 0 : return (0);
148 : }
149 :
150 : /*
151 : * If the interface is not up, don't do anything.
152 : */
153 0 : if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
154 : break;
155 :
156 0 : if (jmphy_auto(sc, ife) != EJUSTRETURN)
157 0 : return (EINVAL);
158 : break;
159 :
160 : case MII_TICK:
161 : /*
162 : * If we're not currently selected, just return.
163 : */
164 0 : if (IFM_INST(ife->ifm_media) != sc->mii_inst)
165 0 : return (0);
166 :
167 : /*
168 : * Is the interface even up?
169 : */
170 0 : if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
171 0 : return (0);
172 :
173 : /*
174 : * Only used for autonegotiation.
175 : */
176 0 : if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
177 : break;
178 :
179 : /* Check for link. */
180 0 : if (PHY_READ(sc, JMPHY_SSR) & JMPHY_SSR_LINK_UP) {
181 0 : sc->mii_ticks = 0;
182 0 : break;
183 : }
184 :
185 : /* Announce link loss right after it happens. */
186 0 : if (sc->mii_ticks++ == 0)
187 : break;
188 0 : if (sc->mii_ticks <= sc->mii_anegticks)
189 0 : return (0);
190 :
191 0 : sc->mii_ticks = 0;
192 0 : jmphy_auto(sc, ife);
193 0 : break;
194 : }
195 :
196 : /* Update the media status. */
197 0 : jmphy_status(sc);
198 :
199 : /* Callback if something changed. */
200 0 : mii_phy_update(sc, cmd);
201 0 : return (0);
202 0 : }
203 :
204 : void
205 0 : jmphy_status(struct mii_softc *sc)
206 : {
207 0 : struct mii_data *mii = sc->mii_pdata;
208 : int bmcr, ssr;
209 :
210 0 : mii->mii_media_status = IFM_AVALID;
211 0 : mii->mii_media_active = IFM_ETHER;
212 :
213 0 : ssr = PHY_READ(sc, JMPHY_SSR);
214 0 : if ((ssr & JMPHY_SSR_LINK_UP) != 0)
215 0 : mii->mii_media_status |= IFM_ACTIVE;
216 :
217 0 : bmcr = PHY_READ(sc, MII_BMCR);
218 0 : if ((bmcr & BMCR_ISO) != 0) {
219 0 : mii->mii_media_active |= IFM_NONE;
220 0 : mii->mii_media_status = 0;
221 0 : return;
222 : }
223 :
224 0 : if ((bmcr & BMCR_LOOP) != 0)
225 0 : mii->mii_media_active |= IFM_LOOP;
226 :
227 0 : if ((ssr & JMPHY_SSR_SPD_DPLX_RESOLVED) == 0) {
228 : /* Erg, still trying, I guess... */
229 0 : mii->mii_media_active |= IFM_NONE;
230 0 : return;
231 : }
232 :
233 0 : switch ((ssr & JMPHY_SSR_SPEED_MASK)) {
234 : case JMPHY_SSR_SPEED_1000:
235 0 : mii->mii_media_active |= IFM_1000_T;
236 : /*
237 : * jmphy(4) got a valid link so reset mii_ticks.
238 : * Resetting mii_ticks is needed in order to
239 : * detect link loss after auto-negotiation.
240 : */
241 0 : sc->mii_ticks = 0;
242 0 : break;
243 : case JMPHY_SSR_SPEED_100:
244 0 : mii->mii_media_active |= IFM_100_TX;
245 0 : sc->mii_ticks = 0;
246 0 : break;
247 : case JMPHY_SSR_SPEED_10:
248 0 : mii->mii_media_active |= IFM_10_T;
249 0 : sc->mii_ticks = 0;
250 0 : break;
251 : default:
252 0 : mii->mii_media_active |= IFM_NONE;
253 0 : return;
254 : }
255 :
256 0 : if ((ssr & JMPHY_SSR_DUPLEX) != 0)
257 0 : mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc);
258 : else
259 0 : mii->mii_media_active |= IFM_HDX;
260 :
261 0 : if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) {
262 0 : if ((PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) != 0)
263 0 : mii->mii_media_active |= IFM_ETH_MASTER;
264 : }
265 0 : }
266 :
267 : void
268 0 : jmphy_reset(struct mii_softc *sc)
269 : {
270 : int i;
271 :
272 : /* Disable sleep mode. */
273 0 : PHY_WRITE(sc, JMPHY_TMCTL,
274 : PHY_READ(sc, JMPHY_TMCTL) & ~JMPHY_TMCTL_SLEEP_ENB);
275 0 : PHY_WRITE(sc, MII_BMCR, BMCR_RESET | BMCR_AUTOEN);
276 :
277 0 : for (i = 0; i < 1000; i++) {
278 0 : DELAY(1);
279 0 : if ((PHY_READ(sc, MII_BMCR) & BMCR_RESET) == 0)
280 : break;
281 : }
282 0 : }
283 :
284 : uint16_t
285 0 : jmphy_anar(struct ifmedia_entry *ife)
286 : {
287 : uint16_t anar;
288 :
289 : anar = 0;
290 0 : switch (IFM_SUBTYPE(ife->ifm_media)) {
291 : case IFM_AUTO:
292 : anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
293 0 : break;
294 : case IFM_1000_T:
295 : break;
296 : case IFM_100_TX:
297 : anar |= ANAR_TX | ANAR_TX_FD;
298 0 : break;
299 : case IFM_10_T:
300 : anar |= ANAR_10 | ANAR_10_FD;
301 0 : break;
302 : default:
303 : break;
304 : }
305 :
306 0 : return (anar);
307 : }
308 :
309 : int
310 0 : jmphy_auto(struct mii_softc *sc, struct ifmedia_entry *ife)
311 : {
312 : uint16_t anar, bmcr, gig;
313 :
314 : gig = 0;
315 0 : bmcr = PHY_READ(sc, MII_BMCR);
316 0 : switch (IFM_SUBTYPE(ife->ifm_media)) {
317 : case IFM_AUTO:
318 : gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
319 0 : break;
320 : case IFM_1000_T:
321 : gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
322 0 : break;
323 : case IFM_100_TX:
324 : case IFM_10_T:
325 : break;
326 : case IFM_NONE:
327 0 : PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO | BMCR_PDOWN);
328 0 : return (EJUSTRETURN);
329 : default:
330 0 : return (EINVAL);
331 : }
332 :
333 0 : if ((ife->ifm_media & IFM_LOOP) != 0)
334 0 : bmcr |= BMCR_LOOP;
335 :
336 0 : anar = jmphy_anar(ife);
337 0 : if (sc->mii_flags & MIIF_DOPAUSE)
338 0 : anar |= ANAR_PAUSE_TOWARDS;
339 :
340 0 : if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) {
341 : #ifdef notyet
342 : struct mii_data *mii;
343 :
344 : mii = sc->mii_pdata;
345 : if ((mii->mii_media.ifm_media & IFM_ETH_MASTER) != 0)
346 : gig |= GTCR_MAN_MS | GTCR_MAN_ADV;
347 : #endif
348 0 : PHY_WRITE(sc, MII_100T2CR, gig);
349 0 : }
350 0 : PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA);
351 0 : PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_AUTOEN | BMCR_STARTNEG);
352 :
353 0 : return (EJUSTRETURN);
354 0 : }
|