bmtphy.c revision 213364
1115013Smarcel/*-
2160157Smarcel * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
3121642Smarcel * All rights reserved.
4121642Smarcel *
5121642Smarcel * This code is derived from software contributed to The NetBSD Foundation
6121642Smarcel * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
7121642Smarcel * NASA Ames Research Center.
8121642Smarcel *
9121642Smarcel * Redistribution and use in source and binary forms, with or without
10121642Smarcel * modification, are permitted provided that the following conditions
11115013Smarcel * are met:
12121642Smarcel * 1. Redistributions of source code must retain the above copyright
13121642Smarcel *    notice, this list of conditions and the following disclaimer.
14121642Smarcel * 2. Redistributions in binary form must reproduce the above copyright
15121642Smarcel *    notice, this list of conditions and the following disclaimer in the
16121642Smarcel *    documentation and/or other materials provided with the distribution.
17121642Smarcel *
18121642Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19121642Smarcel * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20121642Smarcel * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21121642Smarcel * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22121642Smarcel * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23121642Smarcel * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24121642Smarcel * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25115013Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26115013Smarcel * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27115013Smarcel * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28115013Smarcel * POSSIBILITY OF SUCH DAMAGE.
29115013Smarcel */
30115013Smarcel
31115013Smarcel/*
32115013Smarcel * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
33115013Smarcel *
34115013Smarcel * Redistribution and use in source and binary forms, with or without
35115013Smarcel * modification, are permitted provided that the following conditions
36115013Smarcel * are met:
37115013Smarcel * 1. Redistributions of source code must retain the above copyright
38115013Smarcel *    notice, this list of conditions and the following disclaimer.
39115013Smarcel * 2. Redistributions in binary form must reproduce the above copyright
40115013Smarcel *    notice, this list of conditions and the following disclaimer in the
41115013Smarcel *    documentation and/or other materials provided with the distribution.
42115013Smarcel *
43115013Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
44115013Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
45129059Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
46115013Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
47115013Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
48115013Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49115013Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50115013Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51115013Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
52115013Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53129059Smarcel *
54115013Smarcel *	from: NetBSD: bmtphy.c,v 1.8 2002/07/03 06:25:50 simonb Exp
55115013Smarcel *
56115013Smarcel */
57115013Smarcel
58115013Smarcel#include <sys/cdefs.h>
59115013Smarcel__FBSDID("$FreeBSD: head/sys/dev/mii/bmtphy.c 213364 2010-10-02 18:53:12Z marius $");
60115013Smarcel
61115013Smarcel/*
62115013Smarcel * Driver for the Broadcom BCM5201/BCM5202 "Mini-Theta" PHYs.  This also
63115013Smarcel * drives the PHY on the 3Com 3c905C.  The 3c905C's PHY is described in
64129059Smarcel * the 3c905C data sheet.
65115013Smarcel */
66115013Smarcel
67115013Smarcel#include <sys/param.h>
68129059Smarcel#include <sys/systm.h>
69115013Smarcel#include <sys/kernel.h>
70129059Smarcel#include <sys/module.h>
71129059Smarcel#include <sys/socket.h>
72115013Smarcel#include <sys/bus.h>
73115013Smarcel
74115013Smarcel#include <net/if.h>
75115013Smarcel#include <net/if_media.h>
76115013Smarcel
77115013Smarcel#include <dev/mii/mii.h>
78115013Smarcel#include <dev/mii/miivar.h>
79115013Smarcel#include "miidevs.h"
80115013Smarcel
81115013Smarcel#include <dev/mii/bmtphyreg.h>
82115013Smarcel
83115013Smarcel#include "miibus_if.h"
84160157Smarcel
85115013Smarcelstatic int	bmtphy_probe(device_t);
86115013Smarcelstatic int	bmtphy_attach(device_t);
87115013Smarcel
88115013Smarcelstatic device_method_t bmtphy_methods[] = {
89115013Smarcel	/* Device interface */
90115013Smarcel	DEVMETHOD(device_probe,		bmtphy_probe),
91115013Smarcel	DEVMETHOD(device_attach,	bmtphy_attach),
92115013Smarcel	DEVMETHOD(device_detach,	mii_phy_detach),
93115013Smarcel	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
94115013Smarcel
95115013Smarcel	{ 0, 0 }
96115013Smarcel};
97160157Smarcel
98160157Smarcelstatic devclass_t	bmtphy_devclass;
99160157Smarcel
100115013Smarcelstatic driver_t	bmtphy_driver = {
101115013Smarcel	"bmtphy",
102115013Smarcel	bmtphy_methods,
103115013Smarcel	sizeof(struct mii_softc)
104115013Smarcel};
105115013Smarcel
106115013SmarcelDRIVER_MODULE(bmtphy, miibus, bmtphy_driver, bmtphy_devclass, 0, 0);
107115013Smarcel
108115013Smarcelstatic int	bmtphy_service(struct mii_softc *, struct mii_data *, int);
109115013Smarcelstatic void	bmtphy_status(struct mii_softc *);
110115013Smarcel
111115013Smarcelstatic const struct mii_phydesc bmtphys_dp[] = {
112115013Smarcel	MII_PHY_DESC(BROADCOM, BCM4401),
113115013Smarcel	MII_PHY_DESC(BROADCOM, BCM5201),
114115013Smarcel	MII_PHY_DESC(BROADCOM, BCM5221),
115115013Smarcel	MII_PHY_END
116129059Smarcel};
117115013Smarcel
118115013Smarcelstatic const struct mii_phydesc bmtphys_lp[] = {
119115013Smarcel	MII_PHY_DESC(BROADCOM, 3C905B),
120115013Smarcel	MII_PHY_DESC(BROADCOM, 3C905C),
121115013Smarcel	MII_PHY_END
122115013Smarcel};
123129059Smarcel
124115013Smarcelstatic int
125115013Smarcelbmtphy_probe(device_t dev)
126115013Smarcel{
127115013Smarcel	int	rval;
128115013Smarcel
129115013Smarcel	/* Let exphy(4) take precedence for these. */
130115013Smarcel	rval = mii_phy_dev_probe(dev, bmtphys_lp, BUS_PROBE_LOW_PRIORITY);
131115013Smarcel	if (rval <= 0)
132115013Smarcel		return (rval);
133115013Smarcel
134115013Smarcel	return (mii_phy_dev_probe(dev, bmtphys_dp, BUS_PROBE_DEFAULT));
135115013Smarcel}
136115013Smarcel
137160157Smarcelstatic int
138160157Smarcelbmtphy_attach(device_t dev)
139115013Smarcel{
140115013Smarcel	struct	mii_softc *sc;
141129059Smarcel	struct	mii_attach_args *ma;
142115013Smarcel	struct	mii_data *mii;
143115013Smarcel
144115013Smarcel	sc = device_get_softc(dev);
145115013Smarcel	ma = device_get_ivars(dev);
146115013Smarcel	sc->mii_dev = device_get_parent(dev);
147160157Smarcel	mii = ma->mii_data;
148115013Smarcel	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
149115013Smarcel
150129059Smarcel	sc->mii_inst = mii->mii_instance++;
151115013Smarcel	sc->mii_phy = ma->mii_phyno;
152115013Smarcel	sc->mii_service = bmtphy_service;
153115013Smarcel	sc->mii_pdata = mii;
154115013Smarcel
155115013Smarcel	mii_phy_reset(sc);
156115013Smarcel
157115013Smarcel	sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
158115013Smarcel	device_printf(dev, " ");
159129059Smarcel	mii_phy_add_media(sc);
160115013Smarcel	printf("\n");
161115013Smarcel
162115013Smarcel	MIIBUS_MEDIAINIT(sc->mii_dev);
163115013Smarcel
164115013Smarcel	return (0);
165115013Smarcel}
166115013Smarcel
167115013Smarcelstatic int
168115013Smarcelbmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
169115013Smarcel{
170160157Smarcel
171115013Smarcel	switch (cmd) {
172160157Smarcel	case MII_POLLSTAT:
173115013Smarcel		break;
174115013Smarcel
175115013Smarcel	case MII_MEDIACHG:
176115013Smarcel		/*
177115013Smarcel		 * If the interface is not up, don't do anything.
178115013Smarcel		 */
179115013Smarcel		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
180115013Smarcel			break;
181115013Smarcel
182115013Smarcel		mii_phy_setmedia(sc);
183115013Smarcel		break;
184115013Smarcel
185115013Smarcel	case MII_TICK:
186115013Smarcel		if (mii_phy_tick(sc) == EJUSTRETURN)
187115013Smarcel			return (0);
188115013Smarcel		break;
189115013Smarcel	}
190160157Smarcel
191115013Smarcel	/* Update the media status. */
192115013Smarcel	bmtphy_status(sc);
193115013Smarcel
194115013Smarcel	/* Callback if something changed. */
195160157Smarcel	mii_phy_update(sc, cmd);
196160157Smarcel
197160157Smarcel	return (0);
198160157Smarcel}
199115013Smarcel
200115013Smarcelstatic void
201115013Smarcelbmtphy_status(struct mii_softc *sc)
202115013Smarcel{
203115013Smarcel	struct	mii_data *mii;
204115013Smarcel	struct	ifmedia_entry *ife;
205115013Smarcel	int	bmsr, bmcr, aux_csr;
206115013Smarcel
207160157Smarcel	mii = sc->mii_pdata;
208115013Smarcel	ife = mii->mii_media.ifm_cur;
209160157Smarcel
210115013Smarcel	mii->mii_media_status = IFM_AVALID;
211115013Smarcel	mii->mii_media_active = IFM_ETHER;
212115013Smarcel
213129059Smarcel	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
214115013Smarcel	aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR);
215115013Smarcel
216115013Smarcel	if (bmsr & BMSR_LINK)
217115013Smarcel		mii->mii_media_status |= IFM_ACTIVE;
218115013Smarcel
219160157Smarcel	bmcr = PHY_READ(sc, MII_BMCR);
220115013Smarcel	if (bmcr & BMCR_ISO) {
221115013Smarcel		mii->mii_media_active |= IFM_NONE;
222129059Smarcel		mii->mii_media_status = 0;
223115013Smarcel		return;
224115013Smarcel	}
225115013Smarcel
226115013Smarcel	if (bmcr & BMCR_LOOP)
227115013Smarcel		mii->mii_media_active |= IFM_LOOP;
228115013Smarcel
229115013Smarcel	if (bmcr & BMCR_AUTOEN) {
230115013Smarcel		/*
231129059Smarcel		 * The media status bits are only valid if autonegotiation
232115013Smarcel		 * has completed (or it's disabled).
233115013Smarcel		 */
234115013Smarcel		if ((bmsr & BMSR_ACOMP) == 0) {
235115013Smarcel			/* Erg, still trying, I guess... */
236115013Smarcel			mii->mii_media_active |= IFM_NONE;
237115013Smarcel			return;
238115013Smarcel		}
239115013Smarcel
240115013Smarcel		if (aux_csr & AUX_CSR_SPEED)
241115013Smarcel			mii->mii_media_active |= IFM_100_TX;
242115013Smarcel		else
243115013Smarcel			mii->mii_media_active |= IFM_10_T;
244115013Smarcel		if (aux_csr & AUX_CSR_FDX)
245115013Smarcel			mii->mii_media_active |= IFM_FDX;
246115013Smarcel	} else
247115013Smarcel		mii->mii_media_active = ife->ifm_media;
248115013Smarcel}
249115013Smarcel