1 /* $NetBSD: amhphy.c,v 1.18 2008/05/04 17:06:09 xtraeme Exp $ */
4 * Copyright 2001 Wasabi Systems, Inc.
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
39 * Driver for the 10BASE-T portion of the AMD Am79c901 PHY.
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: amhphy.c,v 1.18 2008/05/04 17:06:09 xtraeme Exp $");
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/device.h>
49 #include <sys/socket.h>
50 #include <sys/errno.h>
53 #include <net/if_media.h>
55 #include <dev/mii/mii.h>
56 #include <dev/mii/miivar.h>
57 #include <dev/mii/miidevs.h>
59 #include <dev/mii/amhphyreg.h>
61 static int amhphymatch(device_t
, cfdata_t
, void *);
62 static void amhphyattach(device_t
, device_t
, void *);
64 CFATTACH_DECL_NEW(amhphy
, sizeof(struct mii_softc
),
65 amhphymatch
, amhphyattach
, mii_phy_detach
, mii_phy_activate
);
67 static int amhphy_service(struct mii_softc
*, struct mii_data
*, int);
68 static void amhphy_status(struct mii_softc
*);
70 static const struct mii_phy_funcs amhphy_funcs
= {
71 amhphy_service
, amhphy_status
, mii_phy_reset
,
74 static const struct mii_phydesc amhphys
[] = {
75 { MII_OUI_yyAMD
, MII_MODEL_yyAMD_79c901
,
76 MII_STR_yyAMD_79c901
},
83 amhphymatch(device_t parent
, cfdata_t match
, void *aux
)
85 struct mii_attach_args
*ma
= aux
;
87 if (mii_phy_match(ma
, amhphys
) != NULL
)
94 amhphyattach(device_t parent
, device_t self
, void *aux
)
96 struct mii_softc
*sc
= device_private(self
);
97 struct mii_attach_args
*ma
= aux
;
98 struct mii_data
*mii
= ma
->mii_data
;
99 const struct mii_phydesc
*mpd
;
101 mpd
= mii_phy_match(ma
, amhphys
);
102 aprint_naive(": Media interface\n");
103 aprint_normal(": %s, rev. %d\n", mpd
->mpd_name
, MII_REV(ma
->mii_id2
));
106 sc
->mii_inst
= mii
->mii_instance
;
107 sc
->mii_phy
= ma
->mii_phyno
;
108 sc
->mii_funcs
= &amhphy_funcs
;
110 sc
->mii_flags
= ma
->mii_flags
;
111 sc
->mii_anegticks
= MII_ANEGTICKS
;
115 sc
->mii_capabilities
=
116 PHY_READ(sc
, MII_BMSR
) & ma
->mii_capmask
;
117 aprint_normal_dev(self
, "");
118 if ((sc
->mii_capabilities
& BMSR_MEDIAMASK
) == 0)
119 aprint_error("no media present");
121 mii_phy_add_media(sc
);
126 amhphy_service(struct mii_softc
*sc
, struct mii_data
*mii
, int cmd
)
128 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
134 * If we're not polling our PHY instance, just return.
136 if (IFM_INST(ife
->ifm_media
) != sc
->mii_inst
)
142 * If the media indicates a different PHY instance,
145 if (IFM_INST(ife
->ifm_media
) != sc
->mii_inst
) {
146 reg
= PHY_READ(sc
, MII_BMCR
);
147 PHY_WRITE(sc
, MII_BMCR
, reg
| BMCR_ISO
);
152 * If the interface is not up, don't do anything.
154 if ((mii
->mii_ifp
->if_flags
& IFF_UP
) == 0)
157 mii_phy_setmedia(sc
);
162 * If we're not currently selected, just return.
164 if (IFM_INST(ife
->ifm_media
) != sc
->mii_inst
)
167 if (mii_phy_tick(sc
) == EJUSTRETURN
)
176 /* Update the media status. */
179 /* Callback if something changed. */
180 mii_phy_update(sc
, cmd
);
185 amhphy_status(struct mii_softc
*sc
)
187 struct mii_data
*mii
= sc
->mii_pdata
;
188 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
191 mii
->mii_media_status
= IFM_AVALID
;
192 mii
->mii_media_active
= IFM_ETHER
;
194 bmsr
= PHY_READ(sc
, MII_BMSR
);
195 ssr
= PHY_READ(sc
, MII_AMHPHY_SSR
);
198 mii
->mii_media_status
|= IFM_ACTIVE
;
200 bmcr
= PHY_READ(sc
, MII_BMCR
);
201 if (bmcr
& BMCR_ISO
) {
202 mii
->mii_media_active
|= IFM_NONE
;
203 mii
->mii_media_status
= 0;
207 if (bmcr
& BMCR_LOOP
)
208 mii
->mii_media_active
|= IFM_LOOP
;
210 if (bmcr
& BMCR_AUTOEN
) {
212 * The media status bits are only valid of autonegotiation
213 * has completed (or it's disabled).
215 if ((bmsr
& BMSR_ACOMP
) == 0) {
216 /* Erg, still trying, I guess... */
217 mii
->mii_media_active
|= IFM_NONE
;
223 * This should't really ever happen, since it's
224 * a 10BASE-T only PHY. But the bit exists,
225 * according to the documentation, so we pay
228 mii
->mii_media_active
|= IFM_100_TX
;
230 mii
->mii_media_active
|= IFM_10_T
;
232 mii
->mii_media_active
|= IFM_FDX
;
234 mii
->mii_media_active
= ife
->ifm_media
;