1 /* $NetBSD: acphy.c,v 1.22 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 Altima AC101 PHY.
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: acphy.c,v 1.22 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/acphyreg.h>
61 static int acphymatch(device_t
, cfdata_t
, void *);
62 static void acphyattach(device_t
, device_t
, void *);
64 CFATTACH_DECL_NEW(acphy
, sizeof(struct mii_softc
),
65 acphymatch
, acphyattach
, mii_phy_detach
, mii_phy_activate
);
67 static int acphy_service(struct mii_softc
*, struct mii_data
*, int);
68 static void acphy_status(struct mii_softc
*);
70 static const struct mii_phy_funcs acphy_funcs
= {
71 acphy_service
, acphy_status
, mii_phy_reset
,
74 static const struct mii_phydesc acphys
[] = {
75 { MII_OUI_ALTIMA
, MII_MODEL_ALTIMA_AC101
,
76 MII_STR_ALTIMA_AC101
},
77 { MII_OUI_ALTIMA
, MII_MODEL_ALTIMA_AC101L
,
78 MII_STR_ALTIMA_AC101L
},
79 { MII_OUI_ALTIMA
, MII_MODEL_ALTIMA_Am79C874
,
80 MII_STR_ALTIMA_Am79C874
},
81 { MII_OUI_ALTIMA
, MII_MODEL_ALTIMA_Am79C875
,
82 MII_STR_ALTIMA_Am79C875
},
84 /* XXX This is reported to work, but it's not from any data sheet. */
85 { MII_OUI_ALTIMA
, MII_MODEL_ALTIMA_ACXXX
,
86 MII_STR_ALTIMA_ACXXX
},
93 acphymatch(device_t parent
, cfdata_t match
, void *aux
)
95 struct mii_attach_args
*ma
= aux
;
97 if (mii_phy_match(ma
, acphys
) != NULL
)
104 acphyattach(device_t parent
, device_t self
, void *aux
)
106 struct mii_softc
*sc
= device_private(self
);
107 struct mii_attach_args
*ma
= aux
;
108 struct mii_data
*mii
= ma
->mii_data
;
109 const struct mii_phydesc
*mpd
;
111 mpd
= mii_phy_match(ma
, acphys
);
112 aprint_naive(": Media interface\n");
113 aprint_normal(": %s, rev. %d\n", mpd
->mpd_name
, MII_REV(ma
->mii_id2
));
116 sc
->mii_inst
= mii
->mii_instance
;
117 sc
->mii_phy
= ma
->mii_phyno
;
118 sc
->mii_funcs
= &acphy_funcs
;
120 sc
->mii_flags
= ma
->mii_flags
;
121 sc
->mii_anegticks
= MII_ANEGTICKS
;
126 * XXX Check MCR_FX_SEL to set MIIF_HAVE_FIBER?
129 sc
->mii_capabilities
=
130 PHY_READ(sc
, MII_BMSR
) & ma
->mii_capmask
;
131 aprint_normal_dev(sc
->mii_dev
, "");
133 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
134 if (sc
->mii_flags
& MIIF_HAVEFIBER
) {
135 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_100_FX
, 0, sc
->mii_inst
),
137 aprint_normal("100baseFX, ");
138 ADD(IFM_MAKEWORD(IFM_ETHER
, IFM_100_FX
, IFM_FDX
, sc
->mii_inst
),
140 aprint_normal("100baseFX-FDX, ");
144 if ((sc
->mii_capabilities
& BMSR_MEDIAMASK
) == 0)
145 aprint_error("no media present");
147 mii_phy_add_media(sc
);
152 acphy_service(struct mii_softc
*sc
, struct mii_data
*mii
, int cmd
)
154 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
160 * If we're not polling our PHY instance, just return.
162 if (IFM_INST(ife
->ifm_media
) != sc
->mii_inst
)
168 * If the media indicates a different PHY instance,
171 if (IFM_INST(ife
->ifm_media
) != sc
->mii_inst
) {
172 reg
= PHY_READ(sc
, MII_BMCR
);
173 PHY_WRITE(sc
, MII_BMCR
, reg
| BMCR_ISO
);
178 * If the interface is not up, don't do anything.
180 if ((mii
->mii_ifp
->if_flags
& IFF_UP
) == 0)
183 mii_phy_setmedia(sc
);
188 * If we're not currently selected, just return.
190 if (IFM_INST(ife
->ifm_media
) != sc
->mii_inst
)
193 if (mii_phy_tick(sc
) == EJUSTRETURN
)
202 /* Update the media status. */
205 /* Callback if something changed. */
206 mii_phy_update(sc
, cmd
);
211 acphy_status(struct mii_softc
*sc
)
213 struct mii_data
*mii
= sc
->mii_pdata
;
214 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
217 mii
->mii_media_status
= IFM_AVALID
;
218 mii
->mii_media_active
= IFM_ETHER
;
220 bmsr
= PHY_READ(sc
, MII_BMSR
) | PHY_READ(sc
, MII_BMSR
);
221 dr
= PHY_READ(sc
, MII_ACPHY_DR
);
223 if (bmsr
& BMSR_LINK
)
224 mii
->mii_media_status
|= IFM_ACTIVE
;
226 bmcr
= PHY_READ(sc
, MII_BMCR
);
227 if (bmcr
& BMCR_ISO
) {
228 mii
->mii_media_active
|= IFM_NONE
;
229 mii
->mii_media_status
= 0;
233 if (bmcr
& BMCR_LOOP
)
234 mii
->mii_media_active
|= IFM_LOOP
;
236 if (bmcr
& BMCR_AUTOEN
) {
238 * The media status bits are only valid if autonegotiation
239 * has completed (or it's disabled).
241 if ((bmsr
& BMSR_ACOMP
) == 0) {
242 /* Erg, still trying, I guess... */
243 mii
->mii_media_active
|= IFM_NONE
;
248 mii
->mii_media_active
|= IFM_100_TX
;
250 mii
->mii_media_active
|= IFM_10_T
;
252 mii
->mii_media_active
|= IFM_FDX
;
254 mii
->mii_media_active
= ife
->ifm_media
;