1 /* $NetBSD: urlphy.c,v 1.24 2008/11/17 03:04:27 dyoung Exp $ */
3 * Copyright (c) 2001, 2002
4 * Shingo WATANABE <nabe@nabechan.org>. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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. Neither the name of the author nor the names of any co-contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * driver for Realtek RL8150L internal phy
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: urlphy.c,v 1.24 2008/11/17 03:04:27 dyoung Exp $");
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/device.h>
43 #include <sys/socket.h>
46 #include <net/if_media.h>
48 #include <dev/mii/mii.h>
49 #include <dev/mii/miivar.h>
50 #include <dev/mii/miidevs.h>
51 #include <dev/mii/urlphyreg.h>
54 #define DPRINTF(x) if (urlphydebug) printf x
55 #define DPRINTFN(n,x) if (urlphydebug>(n)) printf x
56 int urlphydebug
= URLPHY_DEBUG
;
62 static int urlphy_match(device_t
, cfdata_t
, void *);
63 static void urlphy_attach(device_t
, device_t
, void *);
65 CFATTACH_DECL_NEW(urlphy
, sizeof(struct mii_softc
),
66 urlphy_match
, urlphy_attach
, mii_phy_detach
, mii_phy_activate
);
68 static int urlphy_service(struct mii_softc
*, struct mii_data
*, int);
69 static void urlphy_status(struct mii_softc
*);
71 static const struct mii_phy_funcs urlphy_funcs
= {
72 urlphy_service
, urlphy_status
, mii_phy_reset
,
76 urlphy_match(device_t parent
, cfdata_t match
, void *aux
)
78 struct mii_attach_args
*ma
= aux
;
81 * RTL8150 reports OUI == 0, MODEL == 0
83 if (MII_OUI(ma
->mii_id1
, ma
->mii_id2
) != 0 &&
84 MII_MODEL(ma
->mii_id2
) != 0)
88 * Make sure the parent is an 'url' device.
90 if (!device_is_a(parent
, "url"))
97 urlphy_attach(device_t parent
, device_t self
, void *aux
)
99 struct mii_softc
*sc
= device_private(self
);
100 struct mii_attach_args
*ma
= aux
;
101 struct mii_data
*mii
= ma
->mii_data
;
103 aprint_naive(": Media interface\n");
104 aprint_normal(": Realtek RTL8150L internal media interface\n");
106 DPRINTF(("%s: %s: enter\n", device_xname(self
), __func__
));
109 sc
->mii_inst
= mii
->mii_instance
;
110 sc
->mii_phy
= ma
->mii_phyno
;
111 sc
->mii_funcs
= &urlphy_funcs
;
113 sc
->mii_flags
= mii
->mii_flags
;
114 sc
->mii_anegticks
= MII_ANEGTICKS_GIGE
;
116 /* Don't do loopback on this PHY. */
117 sc
->mii_flags
|= MIIF_NOLOOP
;
118 /* Don't do isolate on this PHY. */
119 sc
->mii_flags
|= MIIF_NOISOLATE
;
121 if (mii
->mii_instance
!= 0) {
122 aprint_error_dev(self
, "ignoring this PHY, non-zero instance\n");
127 sc
->mii_capabilities
= PHY_READ(sc
, MII_BMSR
) & ma
->mii_capmask
;
128 aprint_normal_dev(self
, "");
129 if ((sc
->mii_capabilities
& BMSR_MEDIAMASK
) == 0)
130 aprint_error("no media present");
132 mii_phy_add_media(sc
);
137 urlphy_service(struct mii_softc
*sc
, struct mii_data
*mii
, int cmd
)
139 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
142 DPRINTF(("%s: %s: enter\n", device_xname(sc
->mii_dev
), __func__
));
147 * If we're not polling our PHY instance, just return.
149 if (IFM_INST(ife
->ifm_media
) != sc
->mii_inst
)
155 * If we're not currently selected, just return.
157 if (IFM_INST(ife
->ifm_media
) != sc
->mii_inst
)
160 /* If the interface is not up, don't do anything. */
161 if ((mii
->mii_ifp
->if_flags
& IFF_UP
) == 0)
164 mii_phy_setmedia(sc
);
169 * If we're not currently selected, just return.
171 if (IFM_INST(ife
->ifm_media
) != sc
->mii_inst
)
174 /* Just bail now if the interface is down. */
175 if ((mii
->mii_ifp
->if_flags
& IFF_UP
) == 0)
179 * If we're not doing autonegotiation, we don't need to do
180 * any extra work here. However, we need to check the link
181 * status so we can generate an announcement if the status
184 if (IFM_SUBTYPE(ife
->ifm_media
) != IFM_AUTO
)
187 /* Read the status register twice; MSR_LINK is latch-low. */
188 reg
= PHY_READ(sc
, URLPHY_MSR
) | PHY_READ(sc
, URLPHY_MSR
);
189 if (reg
& URLPHY_MSR_LINK
)
193 * Only retry autonegotiation every N seconds.
195 KASSERT(sc
->mii_anegticks
!= 0);
196 if (++sc
->mii_ticks
<= sc
->mii_anegticks
)
202 if (mii_phy_auto(sc
, 0) == EJUSTRETURN
)
212 /* Update the media status. */
215 /* Callback if something changed. */
216 mii_phy_update(sc
, cmd
);
222 urlphy_status(struct mii_softc
*sc
)
224 struct mii_data
*mii
= sc
->mii_pdata
;
225 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
228 DPRINTF(("%s: %s: enter\n", device_xname(sc
->mii_dev
), __func__
));
230 mii
->mii_media_status
= IFM_AVALID
;
231 mii
->mii_media_active
= IFM_ETHER
;
234 * The link status bit is not exist in the BMSR register,
235 * so we need to read the MSR register to get link status.
237 msr
= PHY_READ(sc
, URLPHY_MSR
) | PHY_READ(sc
, URLPHY_MSR
);
238 if (msr
& URLPHY_MSR_LINK
)
239 mii
->mii_media_status
|= IFM_ACTIVE
;
241 DPRINTF(("%s: %s: link %s\n", device_xname(sc
->mii_dev
), __func__
,
242 mii
->mii_media_status
& IFM_ACTIVE
? "up" : "down"));
244 bmcr
= PHY_READ(sc
, MII_BMCR
);
245 if (bmcr
& BMCR_AUTOEN
) {
246 bmsr
= PHY_READ(sc
, MII_BMSR
) | PHY_READ(sc
, MII_BMSR
);
247 if ((bmsr
& BMSR_ACOMP
) == 0) {
248 /* Erg, still trying, I guess... */
249 mii
->mii_media_active
|= IFM_NONE
;
253 if (msr
& URLPHY_MSR_SPEED_100
)
254 mii
->mii_media_active
|= IFM_100_TX
;
256 mii
->mii_media_active
|= IFM_10_T
;
257 if (msr
& URLPHY_MSR_DUPLEX
)
258 mii
->mii_media_active
|= IFM_FDX
;
260 mii
->mii_media_active
= ife
->ifm_media
;