nsphyter.c revision 231914
168349Sobrien/*	$NetBSD: nsphyter.c,v 1.28 2008/01/20 07:58:19 msaitoh Exp $	*/
268349Sobrien
368349Sobrien/*-
468349Sobrien * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
568349Sobrien * All rights reserved.
668349Sobrien *
768349Sobrien * This code is derived from software contributed to The NetBSD Foundation
868349Sobrien * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9159764Sobrien * NASA Ames Research Center.
10159764Sobrien *
11159764Sobrien * Redistribution and use in source and binary forms, with or without
12159764Sobrien * modification, are permitted provided that the following conditions
13159764Sobrien * are met:
14159764Sobrien * 1. Redistributions of source code must retain the above copyright
15159764Sobrien *    notice, this list of conditions and the following disclaimer.
16159764Sobrien * 2. Redistributions in binary form must reproduce the above copyright
17159764Sobrien *    notice, this list of conditions and the following disclaimer in the
18159764Sobrien *    documentation and/or other materials provided with the distribution.
19159764Sobrien *
20159764Sobrien * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21159764Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22159764Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23159764Sobrien * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24159764Sobrien * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25159764Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26159764Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27159764Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28159764Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29159764Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30159764Sobrien * POSSIBILITY OF SUCH DAMAGE.
31159764Sobrien */
32159764Sobrien
33159764Sobrien/*-
34159764Sobrien * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
35159764Sobrien *
36159764Sobrien * Redistribution and use in source and binary forms, with or without
37159764Sobrien * modification, are permitted provided that the following conditions
38159764Sobrien * are met:
39159764Sobrien * 1. Redistributions of source code must retain the above copyright
40159764Sobrien *    notice, this list of conditions and the following disclaimer.
41159764Sobrien * 2. Redistributions in binary form must reproduce the above copyright
42159764Sobrien *    notice, this list of conditions and the following disclaimer in the
43139368Sobrien *    documentation and/or other materials provided with the distribution.
44139368Sobrien *
45159764Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46159764Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47159764Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48159764Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49159764Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50159764Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51139368Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52139368Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53139368Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
54139368Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55139368Sobrien */
56159764Sobrien
57159764Sobrien#include <sys/cdefs.h>
58159764Sobrien__FBSDID("$FreeBSD: head/sys/dev/mii/nsphyter.c 231914 2012-02-19 12:25:58Z marius $");
59159764Sobrien
60159764Sobrien/*
61139368Sobrien * Driver for the National Semiconductor's DP83843, DP83847 and DP83849
62139368Sobrien * `PHYTER' Ethernet 10/100 PHYs
63139368Sobrien * Data Sheets are available from http://www.national.com
64139368Sobrien *
65139368Sobrien * We also support the DP83815 `MacPHYTER' internal PHY since, for our
66139368Sobrien * purposes, they are compatible.
67139368Sobrien */
68159764Sobrien
69159764Sobrien#include <sys/param.h>
70159764Sobrien#include <sys/systm.h>
71159764Sobrien#include <sys/bus.h>
72139368Sobrien#include <sys/errno.h>
73139368Sobrien#include <sys/kernel.h>
74139368Sobrien#include <sys/module.h>
75139368Sobrien#include <sys/socket.h>
76139368Sobrien
77139368Sobrien#include <net/if.h>
78139368Sobrien#include <net/if_media.h>
79139368Sobrien
80139368Sobrien#include <dev/mii/mii.h>
81139368Sobrien#include <dev/mii/miivar.h>
82139368Sobrien#include "miidevs.h"
83139368Sobrien
84139368Sobrien#include <dev/mii/nsphyterreg.h>
85139368Sobrien
86139368Sobrien#include "miibus_if.h"
87139368Sobrien
88139368Sobrienstatic device_probe_t	nsphyter_probe;
89139368Sobrienstatic device_attach_t	nsphyter_attach;
90139368Sobrien
91139368Sobrienstatic device_method_t nsphyter_methods[] = {
92139368Sobrien	/* device interface */
93139368Sobrien	DEVMETHOD(device_probe,		nsphyter_probe),
94139368Sobrien	DEVMETHOD(device_attach,	nsphyter_attach),
95139368Sobrien	DEVMETHOD(device_detach,	mii_phy_detach),
96139368Sobrien	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
97139368Sobrien	DEVMETHOD_END
98139368Sobrien};
99139368Sobrien
100139368Sobrienstatic devclass_t nsphyter_devclass;
101139368Sobrien
102139368Sobrienstatic driver_t nsphyter_driver = {
103139368Sobrien	"nsphyter",
104139368Sobrien	nsphyter_methods,
105139368Sobrien	sizeof(struct mii_softc)
106139368Sobrien};
107139368Sobrien
108139368SobrienDRIVER_MODULE(nsphyter, miibus, nsphyter_driver, nsphyter_devclass, 0, 0);
109139368Sobrien
110139368Sobrienstatic int	nsphyter_service(struct mii_softc *, struct mii_data *, int);
111139368Sobrienstatic void	nsphyter_status(struct mii_softc *);
112139368Sobrienstatic void	nsphyter_reset(struct mii_softc *);
113139368Sobrien
114139368Sobrienstatic const struct mii_phydesc nsphyters[] = {
115139368Sobrien	MII_PHY_DESC(xxNATSEMI, DP83815),
116139368Sobrien	MII_PHY_DESC(xxNATSEMI, DP83843),
117139368Sobrien	MII_PHY_DESC(xxNATSEMI, DP83847),
118139368Sobrien	MII_PHY_DESC(xxNATSEMI, DP83849),
119139368Sobrien	MII_PHY_END
120139368Sobrien};
121139368Sobrien
122139368Sobrienstatic const struct mii_phy_funcs nsphyter_funcs = {
123139368Sobrien	nsphyter_service,
124139368Sobrien	nsphyter_status,
125139368Sobrien	nsphyter_reset
126139368Sobrien};
127139368Sobrien
128139368Sobrienstatic int
129139368Sobriennsphyter_probe(device_t dev)
130139368Sobrien{
131139368Sobrien
132139368Sobrien	return (mii_phy_dev_probe(dev, nsphyters, BUS_PROBE_DEFAULT));
133139368Sobrien}
134139368Sobrien
135139368Sobrienstatic int
136159764Sobriennsphyter_attach(device_t dev)
137159764Sobrien{
138159764Sobrien
139159764Sobrien	mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &nsphyter_funcs, 1);
140139368Sobrien	return (0);
141139368Sobrien}
142139368Sobrien
143139368Sobrienstatic int
144139368Sobriennsphyter_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
145139368Sobrien{
146139368Sobrien
147139368Sobrien	switch (cmd) {
148139368Sobrien	case MII_POLLSTAT:
149139368Sobrien		break;
150139368Sobrien
151139368Sobrien	case MII_MEDIACHG:
152139368Sobrien		/*
153139368Sobrien		 * If the interface is not up, don't do anything.
154139368Sobrien		 */
155139368Sobrien		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
156139368Sobrien			break;
157139368Sobrien
158139368Sobrien		mii_phy_setmedia(sc);
159139368Sobrien		break;
160139368Sobrien
161139368Sobrien	case MII_TICK:
162139368Sobrien		if (mii_phy_tick(sc) == EJUSTRETURN)
163139368Sobrien			return (0);
164139368Sobrien		break;
165139368Sobrien	}
166139368Sobrien
167139368Sobrien	/* Update the media status. */
168139368Sobrien	PHY_STATUS(sc);
169139368Sobrien
170139368Sobrien	/* Callback if something changed. */
171139368Sobrien	mii_phy_update(sc, cmd);
172139368Sobrien	return (0);
173139368Sobrien}
174139368Sobrien
175139368Sobrienstatic void
176139368Sobriennsphyter_status(struct mii_softc *sc)
177159764Sobrien{
178159764Sobrien	struct mii_data *mii = sc->mii_pdata;
179159764Sobrien	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
180159764Sobrien	int bmsr, bmcr, physts;
181159764Sobrien
182159764Sobrien	mii->mii_media_status = IFM_AVALID;
183159764Sobrien	mii->mii_media_active = IFM_ETHER;
184159764Sobrien
185159764Sobrien	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
186159764Sobrien	physts = PHY_READ(sc, MII_NSPHYTER_PHYSTS);
187159764Sobrien
188159764Sobrien	if ((physts & PHYSTS_LINK) != 0)
189159764Sobrien		mii->mii_media_status |= IFM_ACTIVE;
190159764Sobrien
191159764Sobrien	bmcr = PHY_READ(sc, MII_BMCR);
192159764Sobrien	if ((bmcr & BMCR_ISO) != 0) {
193159764Sobrien		mii->mii_media_active |= IFM_NONE;
194139368Sobrien		mii->mii_media_status = 0;
195139368Sobrien		return;
196139368Sobrien	}
197139368Sobrien
198139368Sobrien	if ((bmcr & BMCR_LOOP) != 0)
199139368Sobrien		mii->mii_media_active |= IFM_LOOP;
200139368Sobrien
201139368Sobrien	if ((bmcr & BMCR_AUTOEN) != 0) {
202139368Sobrien		/*
203139368Sobrien		 * The media status bits are only valid if autonegotiation
204139368Sobrien		 * has completed (or it's disabled).
205139368Sobrien		 */
206139368Sobrien		if ((bmsr & BMSR_ACOMP) == 0) {
207139368Sobrien			/* Erg, still trying, I guess... */
208139368Sobrien			mii->mii_media_active |= IFM_NONE;
209139368Sobrien			return;
210139368Sobrien		}
211139368Sobrien
212139368Sobrien		if ((physts & PHYSTS_SPEED10) != 0)
213139368Sobrien			mii->mii_media_active |= IFM_10_T;
214139368Sobrien		else
215139368Sobrien			mii->mii_media_active |= IFM_100_TX;
216139368Sobrien		if ((physts & PHYSTS_DUPLEX) != 0)
217139368Sobrien			mii->mii_media_active |=
218139368Sobrien			    IFM_FDX | mii_phy_flowstatus(sc);
219139368Sobrien		else
220139368Sobrien			mii->mii_media_active |= IFM_HDX;
221139368Sobrien	} else
222139368Sobrien		mii->mii_media_active = ife->ifm_media;
223139368Sobrien}
224139368Sobrien
225139368Sobrienstatic void
226139368Sobriennsphyter_reset(struct mii_softc *sc)
227139368Sobrien{
228139368Sobrien	struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
229139368Sobrien	int reg, i;
230139368Sobrien
231139368Sobrien	if ((sc->mii_flags & MIIF_NOISOLATE) != 0)
232139368Sobrien		reg = BMCR_RESET;
233139368Sobrien	else
234139368Sobrien		reg = BMCR_RESET | BMCR_ISO;
235139368Sobrien	PHY_WRITE(sc, MII_BMCR, reg);
236139368Sobrien
237139368Sobrien	/*
238139368Sobrien	 * It is best to allow a little time for the reset to settle
239139368Sobrien	 * in before we start polling the BMCR again.  Notably, the
240139368Sobrien	 * DP8384{3,7} manuals state that there should be a 500us delay
241139368Sobrien	 * between asserting software reset and attempting MII serial
242139368Sobrien	 * operations.  Be conservative.  Also, a DP83815 can get into
243139368Sobrien	 * a bad state on cable removal and reinsertion if we do not
244139368Sobrien	 * delay here.
245139368Sobrien	 */
246139368Sobrien	DELAY(1000);
247139368Sobrien
248139368Sobrien	/*
24968349Sobrien	 * Wait another 2s for it to complete.
250139368Sobrien	 * This is only a little overkill as under normal circumstances
25168349Sobrien	 * the PHY can take up to 1s to complete reset.
252139368Sobrien	 * This is also a bit odd because after a reset, the BMCR will
25368349Sobrien	 * clear the reset bit and simply reports 0 even though the reset
254139368Sobrien	 * is not yet complete.
255139368Sobrien	 */
256139368Sobrien	for (i = 0; i < 1000; i++) {
257139368Sobrien		reg = PHY_READ(sc, MII_BMCR);
258139368Sobrien		if (reg != 0 && (reg & BMCR_RESET) == 0)
259139368Sobrien			break;
260139368Sobrien		DELAY(2000);
261139368Sobrien	}
262139368Sobrien
263139368Sobrien	if ((sc->mii_flags & MIIF_NOISOLATE) == 0) {
264139368Sobrien		if ((ife == NULL && sc->mii_inst != 0) ||
265139368Sobrien		    (ife != NULL && IFM_INST(ife->ifm_media) != sc->mii_inst))
266139368Sobrien			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
267139368Sobrien	}
268139368Sobrien}
269139368Sobrien