1*7a9a30c5Sthorpej /* $NetBSD: iophy.c,v 1.43 2020/03/15 23:04:50 thorpej Exp $ */
2b8e941e9Ssoren
3b8e941e9Ssoren /*
449014bf5Sthorpej * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
5b8e941e9Ssoren * All rights reserved.
6b8e941e9Ssoren *
7b8e941e9Ssoren * This code is derived from software contributed to The NetBSD Foundation
8b8e941e9Ssoren * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9b8e941e9Ssoren * NASA Ames Research Center.
10b8e941e9Ssoren *
11b8e941e9Ssoren * Redistribution and use in source and binary forms, with or without
12b8e941e9Ssoren * modification, are permitted provided that the following conditions
13b8e941e9Ssoren * are met:
14b8e941e9Ssoren * 1. Redistributions of source code must retain the above copyright
15b8e941e9Ssoren * notice, this list of conditions and the following disclaimer.
16b8e941e9Ssoren * 2. Redistributions in binary form must reproduce the above copyright
17b8e941e9Ssoren * notice, this list of conditions and the following disclaimer in the
18b8e941e9Ssoren * documentation and/or other materials provided with the distribution.
19b8e941e9Ssoren *
20b8e941e9Ssoren * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21b8e941e9Ssoren * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22b8e941e9Ssoren * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23b8e941e9Ssoren * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24b8e941e9Ssoren * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25b8e941e9Ssoren * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26b8e941e9Ssoren * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27b8e941e9Ssoren * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28b8e941e9Ssoren * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29b8e941e9Ssoren * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30b8e941e9Ssoren * POSSIBILITY OF SUCH DAMAGE.
31b8e941e9Ssoren */
32b8e941e9Ssoren
33b8e941e9Ssoren /*
34b8e941e9Ssoren * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
35b8e941e9Ssoren *
36b8e941e9Ssoren * Redistribution and use in source and binary forms, with or without
37b8e941e9Ssoren * modification, are permitted provided that the following conditions
38b8e941e9Ssoren * are met:
39b8e941e9Ssoren * 1. Redistributions of source code must retain the above copyright
40b8e941e9Ssoren * notice, this list of conditions and the following disclaimer.
41b8e941e9Ssoren * 2. Redistributions in binary form must reproduce the above copyright
42b8e941e9Ssoren * notice, this list of conditions and the following disclaimer in the
43b8e941e9Ssoren * documentation and/or other materials provided with the distribution.
44b8e941e9Ssoren *
45b8e941e9Ssoren * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46b8e941e9Ssoren * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47b8e941e9Ssoren * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48b8e941e9Ssoren * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49b8e941e9Ssoren * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50b8e941e9Ssoren * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51b8e941e9Ssoren * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52b8e941e9Ssoren * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53b8e941e9Ssoren * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
54b8e941e9Ssoren * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55b8e941e9Ssoren */
56b8e941e9Ssoren
57b8e941e9Ssoren /*
58b8e941e9Ssoren * Intel 82553 PHY driver
59b8e941e9Ssoren */
60b8e941e9Ssoren
618b7bb912Slukem #include <sys/cdefs.h>
62*7a9a30c5Sthorpej __KERNEL_RCSID(0, "$NetBSD: iophy.c,v 1.43 2020/03/15 23:04:50 thorpej Exp $");
638b7bb912Slukem
64b8e941e9Ssoren #include <sys/param.h>
65b8e941e9Ssoren #include <sys/systm.h>
66b8e941e9Ssoren #include <sys/kernel.h>
67b8e941e9Ssoren #include <sys/device.h>
68b8e941e9Ssoren #include <sys/socket.h>
69b8e941e9Ssoren
70b8e941e9Ssoren #include <net/if.h>
71b8e941e9Ssoren #include <net/if_media.h>
72b8e941e9Ssoren
73b8e941e9Ssoren #include <dev/mii/mii.h>
74b8e941e9Ssoren #include <dev/mii/miivar.h>
75b8e941e9Ssoren #include <dev/mii/miidevs.h>
76b8e941e9Ssoren
77b8e941e9Ssoren #include <dev/mii/iophyreg.h>
78b8e941e9Ssoren
797db0e577Sxtraeme static int iophymatch(device_t, cfdata_t, void *);
807db0e577Sxtraeme static void iophyattach(device_t, device_t, void *);
81b8e941e9Ssoren
827db0e577Sxtraeme CFATTACH_DECL_NEW(iophy, sizeof(struct mii_softc),
83c9b3657cSthorpej iophymatch, iophyattach, mii_phy_detach, mii_phy_activate);
84b8e941e9Ssoren
851efb3da0Sthorpej static int iophy_service(struct mii_softc *, struct mii_data *, int);
861efb3da0Sthorpej static void iophy_status(struct mii_softc *);
87b8e941e9Ssoren
881efb3da0Sthorpej static const struct mii_phy_funcs iophy_funcs = {
8949014bf5Sthorpej iophy_service, iophy_status, mii_phy_reset,
9049014bf5Sthorpej };
9149014bf5Sthorpej
921efb3da0Sthorpej static const struct mii_phydesc iophys[] = {
937b43da1bSchristos MII_PHY_DESC(xxINTEL, I82553),
947b43da1bSchristos MII_PHY_DESC(yyINTEL, I82553),
957b43da1bSchristos MII_PHY_END,
96424f7a1eSthorpej };
97424f7a1eSthorpej
981efb3da0Sthorpej static int
iophymatch(device_t parent,cfdata_t match,void * aux)997db0e577Sxtraeme iophymatch(device_t parent, cfdata_t match, void *aux)
100b8e941e9Ssoren {
101b8e941e9Ssoren struct mii_attach_args *ma = aux;
102b8e941e9Ssoren
103424f7a1eSthorpej if (mii_phy_match(ma, iophys) != NULL)
1048e65e831Smsaitoh return 10;
105b8e941e9Ssoren
1068e65e831Smsaitoh return 0;
107b8e941e9Ssoren }
108b8e941e9Ssoren
1091efb3da0Sthorpej static void
iophyattach(device_t parent,device_t self,void * aux)1107db0e577Sxtraeme iophyattach(device_t parent, device_t self, void *aux)
111b8e941e9Ssoren {
112838ee1e0Sthorpej struct mii_softc *sc = device_private(self);
113b8e941e9Ssoren struct mii_attach_args *ma = aux;
114b8e941e9Ssoren struct mii_data *mii = ma->mii_data;
115424f7a1eSthorpej const struct mii_phydesc *mpd;
116b8e941e9Ssoren
117424f7a1eSthorpej mpd = mii_phy_match(ma, iophys);
118c31f87a5Sthorpej aprint_naive(": Media interface\n");
119c31f87a5Sthorpej aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
120b8e941e9Ssoren
1217db0e577Sxtraeme sc->mii_dev = self;
122b8e941e9Ssoren sc->mii_inst = mii->mii_instance;
123b8e941e9Ssoren sc->mii_phy = ma->mii_phyno;
12449014bf5Sthorpej sc->mii_funcs = &iophy_funcs;
125b8e941e9Ssoren sc->mii_pdata = mii;
126b0178985Sthorpej sc->mii_flags = ma->mii_flags;
127b8e941e9Ssoren
128*7a9a30c5Sthorpej mii_lock(mii);
129*7a9a30c5Sthorpej
13049014bf5Sthorpej PHY_RESET(sc);
131b8e941e9Ssoren
132a5cdd4b4Smsaitoh PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
133a5cdd4b4Smsaitoh sc->mii_capabilities &= ma->mii_capmask;
134509697f3Smsaitoh
135*7a9a30c5Sthorpej mii_unlock(mii);
136*7a9a30c5Sthorpej
13784dc99fdSthorpej mii_phy_add_media(sc);
138b8e941e9Ssoren }
139b8e941e9Ssoren
1401efb3da0Sthorpej static int
iophy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)14189893e42Sthorpej iophy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
142b8e941e9Ssoren {
143b8e941e9Ssoren struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
144a5cdd4b4Smsaitoh uint16_t reg;
145b8e941e9Ssoren
146*7a9a30c5Sthorpej KASSERT(mii_locked(mii));
147*7a9a30c5Sthorpej
148b8e941e9Ssoren switch (cmd) {
149b8e941e9Ssoren case MII_POLLSTAT:
1508e65e831Smsaitoh /* If we're not polling our PHY instance, just return. */
151b8e941e9Ssoren if (IFM_INST(ife->ifm_media) != sc->mii_inst)
1528e65e831Smsaitoh return 0;
153b8e941e9Ssoren break;
154b8e941e9Ssoren
155b8e941e9Ssoren case MII_MEDIACHG:
156b8e941e9Ssoren /*
157b8e941e9Ssoren * If the media indicates a different PHY instance,
158b8e941e9Ssoren * isolate ourselves.
159b8e941e9Ssoren */
160b8e941e9Ssoren if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
161a5cdd4b4Smsaitoh PHY_READ(sc, MII_BMCR, ®);
162b8e941e9Ssoren PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
1638e65e831Smsaitoh return 0;
164b8e941e9Ssoren }
165b8e941e9Ssoren
1668e65e831Smsaitoh /* If the interface is not up, don't do anything. */
167b8e941e9Ssoren if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
168b8e941e9Ssoren break;
169b8e941e9Ssoren
1708fc600c3Sthorpej mii_phy_setmedia(sc);
171b8e941e9Ssoren break;
172b8e941e9Ssoren
173b8e941e9Ssoren case MII_TICK:
1748e65e831Smsaitoh /* If we're not currently selected, just return. */
175b8e941e9Ssoren if (IFM_INST(ife->ifm_media) != sc->mii_inst)
1768e65e831Smsaitoh return 0;
177b8e941e9Ssoren
178ad61d101Sthorpej if (mii_phy_tick(sc) == EJUSTRETURN)
1798e65e831Smsaitoh return 0;
180b8e941e9Ssoren break;
181bca88a28Sthorpej
182bca88a28Sthorpej case MII_DOWN:
183bca88a28Sthorpej mii_phy_down(sc);
1848e65e831Smsaitoh return 0;
185b8e941e9Ssoren }
186b8e941e9Ssoren
187b8e941e9Ssoren /* Update the media status. */
1888923ca0bSthorpej mii_phy_status(sc);
189b8e941e9Ssoren
190b8e941e9Ssoren /* Callback if something changed. */
191ad61d101Sthorpej mii_phy_update(sc, cmd);
1928e65e831Smsaitoh return 0;
193b8e941e9Ssoren }
194b8e941e9Ssoren
1951efb3da0Sthorpej static void
iophy_status(struct mii_softc * sc)19689893e42Sthorpej iophy_status(struct mii_softc *sc)
197b8e941e9Ssoren {
198b8e941e9Ssoren struct mii_data *mii = sc->mii_pdata;
1998fc600c3Sthorpej struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
200a5cdd4b4Smsaitoh uint16_t bmsr, bmcr, ext0;
201b8e941e9Ssoren
202*7a9a30c5Sthorpej KASSERT(mii_locked(mii));
203*7a9a30c5Sthorpej
204b8e941e9Ssoren mii->mii_media_status = IFM_AVALID;
205b8e941e9Ssoren mii->mii_media_active = IFM_ETHER;
206b8e941e9Ssoren
207a5cdd4b4Smsaitoh PHY_READ(sc, MII_BMSR, &bmsr);
208b8e941e9Ssoren if (bmsr & BMSR_LINK)
209b8e941e9Ssoren mii->mii_media_status |= IFM_ACTIVE;
210b8e941e9Ssoren
211a5cdd4b4Smsaitoh PHY_READ(sc, MII_BMCR, &bmcr);
212b8e941e9Ssoren if (bmcr & BMCR_ISO) {
213b8e941e9Ssoren mii->mii_media_active |= IFM_NONE;
214b8e941e9Ssoren mii->mii_media_status = 0;
215b8e941e9Ssoren return;
216b8e941e9Ssoren }
217b8e941e9Ssoren
218b8e941e9Ssoren if (bmcr & BMCR_LOOP)
219b8e941e9Ssoren mii->mii_media_active |= IFM_LOOP;
220b8e941e9Ssoren
221b8e941e9Ssoren if (bmcr & BMCR_AUTOEN) {
222b8e941e9Ssoren if ((bmsr & BMSR_ACOMP) == 0) {
223b8e941e9Ssoren /* Erg, still trying, I guess... */
224b8e941e9Ssoren mii->mii_media_active |= IFM_NONE;
225b8e941e9Ssoren return;
226b8e941e9Ssoren }
227a5cdd4b4Smsaitoh PHY_READ(sc, MII_IOPHY_EXT0, &ext0);
228b8e941e9Ssoren
229add29455Scegger if (ext0 & EXT0_SPEED) {
2308e65e831Smsaitoh if ((bmsr & BMSR_100TXFDX) || (bmsr & BMSR_100TXHDX))
231b8e941e9Ssoren mii->mii_media_active |= IFM_100_TX;
2328e65e831Smsaitoh else if (bmsr & BMSR_100T4)
233add29455Scegger mii->mii_media_active |= IFM_100_T4;
234add29455Scegger } else
235b8e941e9Ssoren mii->mii_media_active |= IFM_10_T;
236b8e941e9Ssoren
237b8e941e9Ssoren if (ext0 & EXT0_DUPLEX)
238b8e941e9Ssoren mii->mii_media_active |= IFM_FDX;
239b211437bSmsaitoh else
240b211437bSmsaitoh mii->mii_media_active |= IFM_HDX;
241b8e941e9Ssoren } else
2428fc600c3Sthorpej mii->mii_media_active = ife->ifm_media;
243b8e941e9Ssoren }
244