1b011f8c4SOleksandr Tymoshenko /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
4b011f8c4SOleksandr Tymoshenko * Copyright (c) 2006 Benno Rice. All rights reserved.
5b011f8c4SOleksandr Tymoshenko *
6b011f8c4SOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without
7b011f8c4SOleksandr Tymoshenko * modification, are permitted provided that the following conditions
8b011f8c4SOleksandr Tymoshenko * are met:
9b011f8c4SOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright
10b011f8c4SOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer.
11b011f8c4SOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright
12b011f8c4SOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the
13b011f8c4SOleksandr Tymoshenko * documentation and/or other materials provided with the distribution.
14b011f8c4SOleksandr Tymoshenko *
15b011f8c4SOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16b011f8c4SOleksandr Tymoshenko * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17b011f8c4SOleksandr Tymoshenko * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18b011f8c4SOleksandr Tymoshenko * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19b011f8c4SOleksandr Tymoshenko * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20b011f8c4SOleksandr Tymoshenko * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21b011f8c4SOleksandr Tymoshenko * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22b011f8c4SOleksandr Tymoshenko * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23b011f8c4SOleksandr Tymoshenko * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24b011f8c4SOleksandr Tymoshenko * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25b011f8c4SOleksandr Tymoshenko */
26b011f8c4SOleksandr Tymoshenko
27b011f8c4SOleksandr Tymoshenko #include <sys/cdefs.h>
28b011f8c4SOleksandr Tymoshenko /*
29b011f8c4SOleksandr Tymoshenko * Driver for the SMSC LAN8710A
30b011f8c4SOleksandr Tymoshenko */
31b011f8c4SOleksandr Tymoshenko
32b011f8c4SOleksandr Tymoshenko #include <sys/param.h>
33b011f8c4SOleksandr Tymoshenko #include <sys/systm.h>
34b011f8c4SOleksandr Tymoshenko #include <sys/kernel.h>
35b011f8c4SOleksandr Tymoshenko #include <sys/socket.h>
36b011f8c4SOleksandr Tymoshenko #include <sys/errno.h>
37b011f8c4SOleksandr Tymoshenko #include <sys/module.h>
38b011f8c4SOleksandr Tymoshenko #include <sys/bus.h>
39b011f8c4SOleksandr Tymoshenko #include <sys/malloc.h>
40b011f8c4SOleksandr Tymoshenko
41b011f8c4SOleksandr Tymoshenko #include <machine/bus.h>
42b011f8c4SOleksandr Tymoshenko
43b011f8c4SOleksandr Tymoshenko #include <net/if.h>
44b011f8c4SOleksandr Tymoshenko #include <net/if_media.h>
45b011f8c4SOleksandr Tymoshenko
46b011f8c4SOleksandr Tymoshenko #include <dev/mii/mii.h>
47b011f8c4SOleksandr Tymoshenko #include <dev/mii/miivar.h>
48b011f8c4SOleksandr Tymoshenko #include "miidevs.h"
49b011f8c4SOleksandr Tymoshenko
50b011f8c4SOleksandr Tymoshenko #include "miibus_if.h"
51b011f8c4SOleksandr Tymoshenko
52b011f8c4SOleksandr Tymoshenko static int smscphy_probe(device_t);
53b011f8c4SOleksandr Tymoshenko static int smscphy_attach(device_t);
54b011f8c4SOleksandr Tymoshenko
55b011f8c4SOleksandr Tymoshenko static int smscphy_service(struct mii_softc *, struct mii_data *, int);
56b011f8c4SOleksandr Tymoshenko static void smscphy_auto(struct mii_softc *, int);
57b011f8c4SOleksandr Tymoshenko static void smscphy_status(struct mii_softc *);
58b011f8c4SOleksandr Tymoshenko
59b011f8c4SOleksandr Tymoshenko static device_method_t smscphy_methods[] = {
60b011f8c4SOleksandr Tymoshenko /* device interface */
61b011f8c4SOleksandr Tymoshenko DEVMETHOD(device_probe, smscphy_probe),
62b011f8c4SOleksandr Tymoshenko DEVMETHOD(device_attach, smscphy_attach),
63b011f8c4SOleksandr Tymoshenko DEVMETHOD(device_detach, mii_phy_detach),
64b011f8c4SOleksandr Tymoshenko DEVMETHOD(device_shutdown, bus_generic_shutdown),
65b011f8c4SOleksandr Tymoshenko DEVMETHOD_END
66b011f8c4SOleksandr Tymoshenko };
67b011f8c4SOleksandr Tymoshenko
68b011f8c4SOleksandr Tymoshenko static driver_t smscphy_driver = {
69b011f8c4SOleksandr Tymoshenko "smscphy",
70b011f8c4SOleksandr Tymoshenko smscphy_methods,
71b011f8c4SOleksandr Tymoshenko sizeof(struct mii_softc)
72b011f8c4SOleksandr Tymoshenko };
73b011f8c4SOleksandr Tymoshenko
74f438c2ffSJohn Baldwin DRIVER_MODULE(smscphy, miibus, smscphy_driver, 0, 0);
75b011f8c4SOleksandr Tymoshenko
76b011f8c4SOleksandr Tymoshenko static const struct mii_phydesc smscphys[] = {
77b011f8c4SOleksandr Tymoshenko MII_PHY_DESC(SMC, LAN8710A),
78fe56b741SBaptiste Daroussin MII_PHY_DESC(SMC, LAN8700),
79b011f8c4SOleksandr Tymoshenko MII_PHY_END
80b011f8c4SOleksandr Tymoshenko };
81b011f8c4SOleksandr Tymoshenko
82b011f8c4SOleksandr Tymoshenko static const struct mii_phy_funcs smscphy_funcs = {
83b011f8c4SOleksandr Tymoshenko smscphy_service,
84b011f8c4SOleksandr Tymoshenko smscphy_status,
85b011f8c4SOleksandr Tymoshenko mii_phy_reset
86b011f8c4SOleksandr Tymoshenko };
87b011f8c4SOleksandr Tymoshenko
88b011f8c4SOleksandr Tymoshenko static int
smscphy_probe(device_t dev)89b011f8c4SOleksandr Tymoshenko smscphy_probe(device_t dev)
90b011f8c4SOleksandr Tymoshenko {
91b011f8c4SOleksandr Tymoshenko
92b011f8c4SOleksandr Tymoshenko return (mii_phy_dev_probe(dev, smscphys, BUS_PROBE_DEFAULT));
93b011f8c4SOleksandr Tymoshenko }
94b011f8c4SOleksandr Tymoshenko
95b011f8c4SOleksandr Tymoshenko static int
smscphy_attach(device_t dev)96b011f8c4SOleksandr Tymoshenko smscphy_attach(device_t dev)
97b011f8c4SOleksandr Tymoshenko {
98b011f8c4SOleksandr Tymoshenko struct mii_softc *sc;
99b011f8c4SOleksandr Tymoshenko const struct mii_phy_funcs *mpf;
100b011f8c4SOleksandr Tymoshenko
101b011f8c4SOleksandr Tymoshenko sc = device_get_softc(dev);
102b011f8c4SOleksandr Tymoshenko mpf = &smscphy_funcs;
103b011f8c4SOleksandr Tymoshenko mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, mpf, 1);
104b011f8c4SOleksandr Tymoshenko mii_phy_setmedia(sc);
105b011f8c4SOleksandr Tymoshenko
106b011f8c4SOleksandr Tymoshenko return (0);
107b011f8c4SOleksandr Tymoshenko }
108b011f8c4SOleksandr Tymoshenko
109b011f8c4SOleksandr Tymoshenko static int
smscphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)110b011f8c4SOleksandr Tymoshenko smscphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
111b011f8c4SOleksandr Tymoshenko {
112b011f8c4SOleksandr Tymoshenko struct ifmedia_entry *ife;
113b011f8c4SOleksandr Tymoshenko int reg;
114b011f8c4SOleksandr Tymoshenko
115b011f8c4SOleksandr Tymoshenko ife = mii->mii_media.ifm_cur;
116b011f8c4SOleksandr Tymoshenko
117b011f8c4SOleksandr Tymoshenko switch (cmd) {
118b011f8c4SOleksandr Tymoshenko case MII_POLLSTAT:
119b011f8c4SOleksandr Tymoshenko break;
120b011f8c4SOleksandr Tymoshenko
121b011f8c4SOleksandr Tymoshenko case MII_MEDIACHG:
122b011f8c4SOleksandr Tymoshenko switch (IFM_SUBTYPE(ife->ifm_media)) {
123b011f8c4SOleksandr Tymoshenko case IFM_AUTO:
124b011f8c4SOleksandr Tymoshenko smscphy_auto(sc, ife->ifm_media);
125b011f8c4SOleksandr Tymoshenko break;
126b011f8c4SOleksandr Tymoshenko
127b011f8c4SOleksandr Tymoshenko default:
128b011f8c4SOleksandr Tymoshenko mii_phy_setmedia(sc);
129b011f8c4SOleksandr Tymoshenko break;
130b011f8c4SOleksandr Tymoshenko }
131b011f8c4SOleksandr Tymoshenko
132b011f8c4SOleksandr Tymoshenko break;
133b011f8c4SOleksandr Tymoshenko
134b011f8c4SOleksandr Tymoshenko case MII_TICK:
135b011f8c4SOleksandr Tymoshenko if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
136b011f8c4SOleksandr Tymoshenko break;
137b011f8c4SOleksandr Tymoshenko }
138b011f8c4SOleksandr Tymoshenko
139b011f8c4SOleksandr Tymoshenko /* I have no idea why BMCR_ISO gets set. */
140b011f8c4SOleksandr Tymoshenko reg = PHY_READ(sc, MII_BMCR);
141b011f8c4SOleksandr Tymoshenko if (reg & BMCR_ISO) {
142b011f8c4SOleksandr Tymoshenko PHY_WRITE(sc, MII_BMCR, reg & ~BMCR_ISO);
143b011f8c4SOleksandr Tymoshenko }
144b011f8c4SOleksandr Tymoshenko
145b011f8c4SOleksandr Tymoshenko reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
146b011f8c4SOleksandr Tymoshenko if (reg & BMSR_LINK) {
147b011f8c4SOleksandr Tymoshenko sc->mii_ticks = 0;
148b011f8c4SOleksandr Tymoshenko break;
149b011f8c4SOleksandr Tymoshenko }
150b011f8c4SOleksandr Tymoshenko
151b011f8c4SOleksandr Tymoshenko if (++sc->mii_ticks <= MII_ANEGTICKS) {
152b011f8c4SOleksandr Tymoshenko break;
153b011f8c4SOleksandr Tymoshenko }
154b011f8c4SOleksandr Tymoshenko
155b011f8c4SOleksandr Tymoshenko sc->mii_ticks = 0;
156b011f8c4SOleksandr Tymoshenko PHY_RESET(sc);
157b011f8c4SOleksandr Tymoshenko smscphy_auto(sc, ife->ifm_media);
158b011f8c4SOleksandr Tymoshenko break;
159b011f8c4SOleksandr Tymoshenko }
160b011f8c4SOleksandr Tymoshenko
161b011f8c4SOleksandr Tymoshenko /* Update the media status. */
162b011f8c4SOleksandr Tymoshenko PHY_STATUS(sc);
163b011f8c4SOleksandr Tymoshenko
164b011f8c4SOleksandr Tymoshenko /* Callback if something changed. */
165b011f8c4SOleksandr Tymoshenko mii_phy_update(sc, cmd);
166b011f8c4SOleksandr Tymoshenko return (0);
167b011f8c4SOleksandr Tymoshenko }
168b011f8c4SOleksandr Tymoshenko
169b011f8c4SOleksandr Tymoshenko static void
smscphy_auto(struct mii_softc * sc,int media)170b011f8c4SOleksandr Tymoshenko smscphy_auto(struct mii_softc *sc, int media)
171b011f8c4SOleksandr Tymoshenko {
172b011f8c4SOleksandr Tymoshenko uint16_t anar;
173b011f8c4SOleksandr Tymoshenko
174b011f8c4SOleksandr Tymoshenko anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
175b011f8c4SOleksandr Tymoshenko if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0)
176b011f8c4SOleksandr Tymoshenko anar |= ANAR_FC;
177b011f8c4SOleksandr Tymoshenko PHY_WRITE(sc, MII_ANAR, anar);
178b011f8c4SOleksandr Tymoshenko /* Apparently this helps. */
179b011f8c4SOleksandr Tymoshenko anar = PHY_READ(sc, MII_ANAR);
180b011f8c4SOleksandr Tymoshenko PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
181b011f8c4SOleksandr Tymoshenko }
182b011f8c4SOleksandr Tymoshenko
183b011f8c4SOleksandr Tymoshenko static void
smscphy_status(struct mii_softc * sc)184b011f8c4SOleksandr Tymoshenko smscphy_status(struct mii_softc *sc)
185b011f8c4SOleksandr Tymoshenko {
186b011f8c4SOleksandr Tymoshenko struct mii_data *mii;
187b011f8c4SOleksandr Tymoshenko uint32_t bmcr, bmsr, status;
188b011f8c4SOleksandr Tymoshenko
189b011f8c4SOleksandr Tymoshenko mii = sc->mii_pdata;
190b011f8c4SOleksandr Tymoshenko mii->mii_media_status = IFM_AVALID;
191b011f8c4SOleksandr Tymoshenko mii->mii_media_active = IFM_ETHER;
192b011f8c4SOleksandr Tymoshenko
193b011f8c4SOleksandr Tymoshenko bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
194b011f8c4SOleksandr Tymoshenko if ((bmsr & BMSR_LINK) != 0)
195b011f8c4SOleksandr Tymoshenko mii->mii_media_status |= IFM_ACTIVE;
196b011f8c4SOleksandr Tymoshenko
197b011f8c4SOleksandr Tymoshenko bmcr = PHY_READ(sc, MII_BMCR);
198b011f8c4SOleksandr Tymoshenko if ((bmcr & BMCR_ISO) != 0) {
199b011f8c4SOleksandr Tymoshenko mii->mii_media_active |= IFM_NONE;
200b011f8c4SOleksandr Tymoshenko mii->mii_media_status = 0;
201b011f8c4SOleksandr Tymoshenko return;
202b011f8c4SOleksandr Tymoshenko }
203b011f8c4SOleksandr Tymoshenko
204b011f8c4SOleksandr Tymoshenko if ((bmcr & BMCR_LOOP) != 0)
205b011f8c4SOleksandr Tymoshenko mii->mii_media_active |= IFM_LOOP;
206b011f8c4SOleksandr Tymoshenko
207b011f8c4SOleksandr Tymoshenko if ((bmcr & BMCR_AUTOEN) != 0) {
208b011f8c4SOleksandr Tymoshenko if ((bmsr & BMSR_ACOMP) == 0) {
209b011f8c4SOleksandr Tymoshenko /* Erg, still trying, I guess... */
210b011f8c4SOleksandr Tymoshenko mii->mii_media_active |= IFM_NONE;
211b011f8c4SOleksandr Tymoshenko return;
212b011f8c4SOleksandr Tymoshenko }
213b011f8c4SOleksandr Tymoshenko }
214b011f8c4SOleksandr Tymoshenko
215b011f8c4SOleksandr Tymoshenko status = PHY_READ(sc, 0x1F);
216b011f8c4SOleksandr Tymoshenko if (status & 0x0008)
217b011f8c4SOleksandr Tymoshenko mii->mii_media_active |= IFM_100_TX;
218b011f8c4SOleksandr Tymoshenko else
219b011f8c4SOleksandr Tymoshenko mii->mii_media_active |= IFM_10_T;
220b011f8c4SOleksandr Tymoshenko if (status & 0x0010)
221b011f8c4SOleksandr Tymoshenko mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc);
222b011f8c4SOleksandr Tymoshenko else
223b011f8c4SOleksandr Tymoshenko mii->mii_media_active |= IFM_HDX;
224b011f8c4SOleksandr Tymoshenko }
225