xref: /freebsd/sys/dev/mii/smscphy.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
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