bmtphy.c revision 164703
1110130Sjake/*-
2110130Sjake * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
3144328Sjoerg * All rights reserved.
4110130Sjake *
5110130Sjake * This code is derived from software contributed to The NetBSD Foundation
6110130Sjake * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
7110130Sjake * NASA Ames Research Center.
8110130Sjake *
9110130Sjake * Redistribution and use in source and binary forms, with or without
10110130Sjake * modification, are permitted provided that the following conditions
11110130Sjake * are met:
12110130Sjake * 1. Redistributions of source code must retain the above copyright
13110130Sjake *    notice, this list of conditions and the following disclaimer.
14110130Sjake * 2. Redistributions in binary form must reproduce the above copyright
15110130Sjake *    notice, this list of conditions and the following disclaimer in the
16110130Sjake *    documentation and/or other materials provided with the distribution.
17110130Sjake * 3. All advertising materials mentioning features or use of this software
18110130Sjake *    must display the following acknowledgement:
19110130Sjake *      This product includes software developed by the NetBSD
20110130Sjake *      Foundation, Inc. and its contributors.
21110130Sjake * 4. Neither the name of The NetBSD Foundation nor the names of its
22110130Sjake *    contributors may be used to endorse or promote products derived
23110130Sjake *    from this software without specific prior written permission.
24110130Sjake *
25110130Sjake * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26110130Sjake * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27110130Sjake * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28110130Sjake * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29110130Sjake * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30110130Sjake * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31110130Sjake * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32110130Sjake * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33110130Sjake * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34110130Sjake * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35110130Sjake * POSSIBILITY OF SUCH DAMAGE.
36110130Sjake */
37110130Sjake
38110130Sjake/*
39110130Sjake * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
40110130Sjake *
41110130Sjake * Redistribution and use in source and binary forms, with or without
42110130Sjake * modification, are permitted provided that the following conditions
43110130Sjake * are met:
44110130Sjake * 1. Redistributions of source code must retain the above copyright
45110130Sjake *    notice, this list of conditions and the following disclaimer.
46110130Sjake * 2. Redistributions in binary form must reproduce the above copyright
47110130Sjake *    notice, this list of conditions and the following disclaimer in the
48110130Sjake *    documentation and/or other materials provided with the distribution.
49110130Sjake * 3. All advertising materials mentioning features or use of this software
50110130Sjake *    must display the following acknowledgement:
51110130Sjake *      This product includes software developed by Manuel Bouyer.
52110130Sjake * 4. The name of the author may not be used to endorse or promote products
53110130Sjake *    derived from this software without specific prior written permission.
54110130Sjake *
55110130Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
56110130Sjake * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
57110130Sjake * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
58110130Sjake * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
59110130Sjake * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
60110130Sjake * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
61110130Sjake * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
62110130Sjake * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
63110130Sjake * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
64110130Sjake * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65110130Sjake *
66110130Sjake *	from: NetBSD: bmtphy.c,v 1.8 2002/07/03 06:25:50 simonb Exp
67110130Sjake *
68110130Sjake */
69110130Sjake
70110130Sjake#include <sys/cdefs.h>
71110130Sjake__FBSDID("$FreeBSD: head/sys/dev/mii/bmtphy.c 164703 2006-11-27 23:50:19Z marius $");
72110130Sjake
73110130Sjake/*
74113538Sjake * Driver for the Broadcom BCM5201/BCM5202 "Mini-Theta" PHYs.  This also
75113538Sjake * drives the PHY on the 3Com 3c905C.  The 3c905C's PHY is described in
76110130Sjake * the 3c905C data sheet.
77110130Sjake */
78110130Sjake
79128916Sjoerg#include <sys/param.h>
80110130Sjake#include <sys/systm.h>
81110130Sjake#include <sys/kernel.h>
82110130Sjake#include <sys/module.h>
83113896Sphk#include <sys/socket.h>
84110130Sjake#include <sys/bus.h>
85110130Sjake
86110130Sjake#include <net/if.h>
87110130Sjake#include <net/if_media.h>
88110130Sjake
89110130Sjake#include <dev/mii/mii.h>
90110130Sjake#include <dev/mii/miivar.h>
91110130Sjake#include "miidevs.h"
92110130Sjake
93110130Sjake#include <dev/mii/bmtphyreg.h>
94110130Sjake
95129965Sjoerg#include "miibus_if.h"
96110130Sjake
97129965Sjoergstatic int	bmtphy_probe(device_t);
98110130Sjakestatic int	bmtphy_attach(device_t);
99110130Sjake
100110130Sjakestatic device_method_t bmtphy_methods[] = {
101110130Sjake	/* Device interface */
102129965Sjoerg	DEVMETHOD(device_probe,		bmtphy_probe),
103129965Sjoerg	DEVMETHOD(device_attach,	bmtphy_attach),
104129965Sjoerg	DEVMETHOD(device_detach,	mii_phy_detach),
105129965Sjoerg	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
106129965Sjoerg
107129965Sjoerg	{ 0, 0 }
108129965Sjoerg};
109129965Sjoerg
110110130Sjakestatic devclass_t	bmtphy_devclass;
111110130Sjake
112110130Sjakestatic driver_t	bmtphy_driver = {
113110130Sjake	"bmtphy",
114129965Sjoerg	bmtphy_methods,
115110130Sjake	sizeof(struct mii_softc)
116110130Sjake};
117110130Sjake
118110130SjakeDRIVER_MODULE(bmtphy, miibus, bmtphy_driver, bmtphy_devclass, 0, 0);
119110130Sjake
120110130Sjakestatic int	bmtphy_service(struct mii_softc *, struct mii_data *, int);
121110130Sjakestatic void	bmtphy_status(struct mii_softc *);
122129965Sjoerg
123129965Sjoergstatic int
124129965Sjoergbmtphy_probe(device_t dev)
125129965Sjoerg{
126129965Sjoerg	struct	mii_attach_args *ma;
127129965Sjoerg	int	rval;
128129965Sjoerg
129129965Sjoerg	ma = device_get_ivars(dev);
130110130Sjake	rval = BUS_PROBE_DEFAULT;
131110130Sjake
132110130Sjake	if (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_BROADCOM)
133110130Sjake		return (ENXIO);
134129965Sjoerg
135129965Sjoerg	switch (MII_MODEL(ma->mii_id2)) {
136129965Sjoerg	case MII_MODEL_BROADCOM_3C905B:
137129965Sjoerg		device_set_desc(dev, MII_STR_BROADCOM_3C905B);
138129965Sjoerg		rval = BUS_PROBE_LOW_PRIORITY;	/* Let exphy take precedence. */
139129965Sjoerg		break;
140129965Sjoerg	case MII_MODEL_BROADCOM_3C905C:
141129965Sjoerg		device_set_desc(dev, MII_STR_BROADCOM_3C905C);
142129965Sjoerg		rval = BUS_PROBE_LOW_PRIORITY;	/* Let exphy take precedence. */
143129965Sjoerg		break;
144129965Sjoerg	case MII_MODEL_BROADCOM_BCM5201:
145129965Sjoerg		device_set_desc(dev, MII_STR_BROADCOM_BCM5201);
146129965Sjoerg		break;
147129965Sjoerg	case MII_MODEL_BROADCOM_BCM5221:
148129965Sjoerg		device_set_desc(dev, MII_STR_BROADCOM_BCM5221);
149129965Sjoerg		break;
150129965Sjoerg	case MII_MODEL_BROADCOM_BCM4401:
151129965Sjoerg		device_set_desc(dev, MII_STR_BROADCOM_BCM4401);
152129965Sjoerg		break;
153129965Sjoerg	default:
154129965Sjoerg		return (ENXIO);
155129965Sjoerg	}
156129965Sjoerg
157110130Sjake	return (rval);
158110130Sjake}
159110130Sjake
160110130Sjakestatic int
161110130Sjakebmtphy_attach(device_t dev)
162110130Sjake{
163110130Sjake	struct	mii_softc *sc;
164110130Sjake	struct	mii_attach_args *ma;
165110130Sjake	struct	mii_data *mii;
166110130Sjake
167110130Sjake	sc = device_get_softc(dev);
168110130Sjake	ma = device_get_ivars(dev);
169110130Sjake	sc->mii_dev = device_get_parent(dev);
170129965Sjoerg	mii = device_get_softc(sc->mii_dev);
171110130Sjake	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
172110130Sjake
173110130Sjake	sc->mii_inst = mii->mii_instance;
174110130Sjake	sc->mii_phy = ma->mii_phyno;
175110130Sjake	sc->mii_service = bmtphy_service;
176110130Sjake	sc->mii_pdata = mii;
177110130Sjake
178110130Sjake	mii_phy_reset(sc);
179129965Sjoerg
180129965Sjoerg	mii->mii_instance++;
181129965Sjoerg
182110130Sjake	sc->mii_capabilities =
183110130Sjake	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
184110130Sjake	device_printf(dev, " ");
185129965Sjoerg	mii_phy_add_media(sc);
186129965Sjoerg	printf("\n");
187129965Sjoerg
188110130Sjake	MIIBUS_MEDIAINIT(sc->mii_dev);
189110130Sjake
190110130Sjake	return (0);
191110130Sjake}
192113896Sphk
193110130Sjakestatic int
194110130Sjakebmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
195110130Sjake{
196110130Sjake	struct	ifmedia_entry *ife;
197110130Sjake	int	reg;
198110130Sjake
199110130Sjake	ife = mii->mii_media.ifm_cur;
200110130Sjake
201110130Sjake	switch (cmd) {
202110130Sjake	case MII_POLLSTAT:
203110130Sjake		/*
204110130Sjake		 * If we're not polling our PHY instance, just return.
205110130Sjake		 */
206110130Sjake		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
207110130Sjake			return (0);
208110130Sjake		break;
209110130Sjake
210129965Sjoerg	case MII_MEDIACHG:
211129965Sjoerg		/*
212110130Sjake		 * If the media indicates a different PHY instance,
213110130Sjake		 * isolate ourselves.
214110130Sjake		 */
215110130Sjake		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
216110130Sjake			reg = PHY_READ(sc, MII_BMCR);
217110130Sjake			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
218110130Sjake			return (0);
219110130Sjake		}
220110130Sjake
221110130Sjake		/*
222110130Sjake		 * If the interface is not up, don't do anything.
223113824Sphk		 */
224113824Sphk		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
225110130Sjake			break;
226110130Sjake
227110130Sjake		mii_phy_setmedia(sc);
228110130Sjake		break;
229110130Sjake
230110130Sjake	case MII_TICK:
231110130Sjake		/*
232110130Sjake		 * If we're not currently selected, just return.
233129965Sjoerg		 */
234110130Sjake		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
235110130Sjake			return (0);
236110130Sjake		if (mii_phy_tick(sc) == EJUSTRETURN)
237110130Sjake			return (0);
238110130Sjake		break;
239113538Sjake	}
240113538Sjake
241110130Sjake	/* Update the media status. */
242110130Sjake	bmtphy_status(sc);
243110130Sjake
244110130Sjake	/* Callback if something changed. */
245110130Sjake	mii_phy_update(sc, cmd);
246110130Sjake
247110130Sjake	return (0);
248110130Sjake}
249110130Sjake
250110130Sjakestatic void
251110130Sjakebmtphy_status(struct mii_softc *sc)
252110130Sjake{
253110130Sjake	struct	mii_data *mii;
254110130Sjake	struct	ifmedia_entry *ife;
255110130Sjake	int	bmsr, bmcr, aux_csr;
256110130Sjake
257110130Sjake	mii = sc->mii_pdata;
258110130Sjake	ife = mii->mii_media.ifm_cur;
259110130Sjake
260110130Sjake	mii->mii_media_status = IFM_AVALID;
261110130Sjake	mii->mii_media_active = IFM_ETHER;
262110130Sjake
263110130Sjake	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
264129965Sjoerg	aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR);
265129965Sjoerg
266110130Sjake	if (bmsr & BMSR_LINK)
267110130Sjake		mii->mii_media_status |= IFM_ACTIVE;
268110130Sjake
269129965Sjoerg	bmcr = PHY_READ(sc, MII_BMCR);
270129965Sjoerg	if (bmcr & BMCR_ISO) {
271110130Sjake		mii->mii_media_active |= IFM_NONE;
272113824Sphk		mii->mii_media_status = 0;
273113824Sphk		return;
274113538Sjake	}
275113538Sjake
276113538Sjake	if (bmcr & BMCR_LOOP)
277113538Sjake		mii->mii_media_active |= IFM_LOOP;
278129965Sjoerg
279129965Sjoerg	if (bmcr & BMCR_AUTOEN) {
280129965Sjoerg		/*
281129965Sjoerg		 * The media status bits are only valid if autonegotiation
282113824Sphk		 * has completed (or it's disabled).
283110130Sjake		 */
284110130Sjake		if ((bmsr & BMSR_ACOMP) == 0) {
285110130Sjake			/* Erg, still trying, I guess... */
286110130Sjake			mii->mii_media_active |= IFM_NONE;
287110130Sjake			return;
288110130Sjake		}
289110130Sjake
290110130Sjake		if (aux_csr & AUX_CSR_SPEED)
291110130Sjake			mii->mii_media_active |= IFM_100_TX;
292110130Sjake		else
293129965Sjoerg			mii->mii_media_active |= IFM_10_T;
294129965Sjoerg		if (aux_csr & AUX_CSR_FDX)
295129965Sjoerg			mii->mii_media_active |= IFM_FDX;
296130692Sjoerg	} else
297129965Sjoerg		mii->mii_media_active = ife->ifm_media;
298129965Sjoerg}
299129965Sjoerg