lxtphy.c revision 213229
11556Srgrimes/*	OpenBSD: lxtphy.c,v 1.5 2000/08/26 20:04:17 nate Exp 	*/
21556Srgrimes/*	NetBSD: lxtphy.c,v 1.19 2000/02/02 23:34:57 thorpej Exp 	*/
31556Srgrimes
41556Srgrimes/*-
51556Srgrimes * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
61556Srgrimes * All rights reserved.
71556Srgrimes *
81556Srgrimes * This code is derived from software contributed to The NetBSD Foundation
91556Srgrimes * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
101556Srgrimes * NASA Ames Research Center.
111556Srgrimes *
121556Srgrimes * Redistribution and use in source and binary forms, with or without
131556Srgrimes * modification, are permitted provided that the following conditions
141556Srgrimes * are met:
151556Srgrimes * 1. Redistributions of source code must retain the above copyright
161556Srgrimes *    notice, this list of conditions and the following disclaimer.
171556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
181556Srgrimes *    notice, this list of conditions and the following disclaimer in the
191556Srgrimes *    documentation and/or other materials provided with the distribution.
201556Srgrimes *
211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
221556Srgrimes * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
231556Srgrimes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
241556Srgrimes * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
251556Srgrimes * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
261556Srgrimes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
271556Srgrimes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
281556Srgrimes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
291556Srgrimes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30110390Scharnier * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
311556Srgrimes * POSSIBILITY OF SUCH DAMAGE.
3236006Scharnier */
33110390Scharnier
3435773Scharnier/*-
35110390Scharnier * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
3699109Sobrien *
3799109Sobrien * Redistribution and use in source and binary forms, with or without
381556Srgrimes * modification, are permitted provided that the following conditions
391556Srgrimes * are met:
401556Srgrimes * 1. Redistributions of source code must retain the above copyright
411556Srgrimes *    notice, this list of conditions and the following disclaimer.
421556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
431556Srgrimes *    notice, this list of conditions and the following disclaimer in the
441556Srgrimes *    documentation and/or other materials provided with the distribution.
451556Srgrimes *
461556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
471556Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
481556Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
491556Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
501556Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
511556Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
521556Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
531556Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
541556Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
551556Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
561556Srgrimes */
571556Srgrimes
581556Srgrimes#include <sys/cdefs.h>
591556Srgrimes__FBSDID("$FreeBSD: head/sys/dev/mii/lxtphy.c 213229 2010-09-27 20:31:03Z marius $");
601556Srgrimes
611556Srgrimes/*
621556Srgrimes * driver for Level One's LXT-970 ethernet 10/100 PHY
631556Srgrimes * datasheet from www.level1.com
641556Srgrimes */
651556Srgrimes
6690108Simp#include <sys/param.h>
671556Srgrimes#include <sys/systm.h>
681556Srgrimes#include <sys/kernel.h>
691556Srgrimes#include <sys/socket.h>
701556Srgrimes#include <sys/errno.h>
7191079Smarkm#include <sys/module.h>
721556Srgrimes#include <sys/bus.h>
731556Srgrimes
7498062Skeramida#include <net/if.h>
7598062Skeramida#include <net/if_media.h>
761556Srgrimes
771556Srgrimes#include <dev/mii/mii.h>
781556Srgrimes#include <dev/mii/miivar.h>
79110390Scharnier#include "miidevs.h"
801556Srgrimes
811556Srgrimes#include <dev/mii/lxtphyreg.h>
821556Srgrimes
831556Srgrimes#include "miibus_if.h"
841556Srgrimes
851556Srgrimesstatic int lxtphy_probe(device_t);
861556Srgrimesstatic int lxtphy_attach(device_t);
871556Srgrimes
88244538Skevlostatic device_method_t lxtphy_methods[] = {
891556Srgrimes	/* device interface */
901556Srgrimes	DEVMETHOD(device_probe,		lxtphy_probe),
911556Srgrimes	DEVMETHOD(device_attach,	lxtphy_attach),
921556Srgrimes	DEVMETHOD(device_detach,	mii_phy_detach),
9391079Smarkm	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
9491079Smarkm	{ 0, 0 }
951556Srgrimes};
9691079Smarkm
9791079Smarkmstatic devclass_t lxtphy_devclass;
981556Srgrimes
991556Srgrimesstatic driver_t lxtphy_driver = {
1001556Srgrimes	"lxtphy",
1011556Srgrimes	lxtphy_methods,
1021556Srgrimes	sizeof(struct mii_softc)
1031556Srgrimes};
1041556Srgrimes
1051556SrgrimesDRIVER_MODULE(lxtphy, miibus, lxtphy_driver, lxtphy_devclass, 0, 0);
1061556Srgrimes
1071556Srgrimesstatic int	lxtphy_service(struct mii_softc *, struct mii_data *, int);
1081556Srgrimesstatic void	lxtphy_status(struct mii_softc *);
109161469Simpstatic void	lxtphy_set_tp(struct mii_softc *);
1101556Srgrimesstatic void	lxtphy_set_fx(struct mii_softc *);
1111556Srgrimes
1121556Srgrimesstatic const struct mii_phydesc lxtphys[] = {
1131556Srgrimes	MII_PHY_DESC(xxLEVEL1, LXT970),
1141556Srgrimes	MII_PHY_END
1151556Srgrimes};
116161469Simp
1171556Srgrimesstatic int
1181556Srgrimeslxtphy_probe(device_t dev)
1191556Srgrimes{
1201556Srgrimes
1211556Srgrimes	return (mii_phy_dev_probe(dev, lxtphys, BUS_PROBE_DEFAULT));
1221556Srgrimes}
1231556Srgrimes
1241556Srgrimesstatic int
1251556Srgrimeslxtphy_attach(device_t dev)
1261556Srgrimes{
1271556Srgrimes	struct mii_softc *sc;
1281556Srgrimes	struct mii_attach_args *ma;
1291556Srgrimes	struct mii_data *mii;
1301556Srgrimes	const char *nic;
1311556Srgrimes
1321556Srgrimes	sc = device_get_softc(dev);
1331556Srgrimes	ma = device_get_ivars(dev);
1341556Srgrimes	sc->mii_dev = device_get_parent(dev);
1351556Srgrimes	mii = ma->mii_data;
1361556Srgrimes	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
1371556Srgrimes
1381556Srgrimes	sc->mii_inst = mii->mii_instance;
1391556Srgrimes	sc->mii_phy = ma->mii_phyno;
1401556Srgrimes	sc->mii_service = lxtphy_service;
14191079Smarkm	sc->mii_pdata = mii;
1421556Srgrimes
14391079Smarkm	mii->mii_instance++;
14491079Smarkm
14591079Smarkm	mii_phy_reset(sc);
1461556Srgrimes
1471556Srgrimes	sc->mii_capabilities =
1481556Srgrimes	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
1491556Srgrimes	device_printf(dev, " ");
1501556Srgrimes
1511556Srgrimes	/*
1521556Srgrimes	 * On Apple BMAC controllers, we end up in a weird state
1531556Srgrimes	 * of partially-completed autonegotiation on boot. So
1541556Srgrimes	 * force autonegotation to try again.
1551556Srgrimes	 */
1561556Srgrimes	nic = device_get_name(device_get_parent(sc->mii_dev));
1571556Srgrimes	if (strcmp(nic, "bm") == 0)
1581556Srgrimes		sc->mii_flags |= MIIF_FORCEANEG | MIIF_NOISOLATE;
1591556Srgrimes
1601556Srgrimes#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
1611556Srgrimes	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst),
1621556Srgrimes	    MII_MEDIA_100_TX);
1631556Srgrimes	printf("100baseFX, ");
1641556Srgrimes	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst),
1651556Srgrimes	    MII_MEDIA_100_TX_FDX);
1661556Srgrimes	printf("100baseFX-FDX, ");
1671556Srgrimes#undef ADD
1681556Srgrimes
1698855Srgrimes	mii_phy_add_media(sc);
1701556Srgrimes	printf("\n");
1711556Srgrimes
1721556Srgrimes	MIIBUS_MEDIAINIT(sc->mii_dev);
1731556Srgrimes	return (0);
1741556Srgrimes}
1751556Srgrimes
1761556Srgrimesstatic int
1771556Srgrimeslxtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
1781556Srgrimes{
1791556Srgrimes	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
1801556Srgrimes	int reg;
1811556Srgrimes
182	switch (cmd) {
183	case MII_POLLSTAT:
184		/*
185		 * If we're not polling our PHY instance, just return.
186		 */
187		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
188			return (0);
189		break;
190
191	case MII_MEDIACHG:
192		/*
193		 * If the media indicates a different PHY instance,
194		 * isolate ourselves.
195		 */
196		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
197			reg = PHY_READ(sc, MII_BMCR);
198			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
199			return (0);
200		}
201
202		/*
203		 * If the interface is not up, don't do anything.
204		 */
205		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
206			break;
207
208		if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_FX)
209			lxtphy_set_fx(sc);
210		else
211			lxtphy_set_tp(sc);
212
213		mii_phy_setmedia(sc);
214		break;
215
216	case MII_TICK:
217		/*
218		 * If we're not currently selected, just return.
219		 */
220		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
221			return (0);
222		if (mii_phy_tick(sc) == EJUSTRETURN)
223			return (0);
224		break;
225	}
226
227	/* Update the media status. */
228	lxtphy_status(sc);
229
230	/* Callback if something changed. */
231	mii_phy_update(sc, cmd);
232	return (0);
233}
234
235static void
236lxtphy_status(struct mii_softc *sc)
237{
238	struct mii_data *mii = sc->mii_pdata;
239	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
240	int bmcr, bmsr, csr;
241
242	mii->mii_media_status = IFM_AVALID;
243	mii->mii_media_active = IFM_ETHER;
244
245	/*
246	 * Get link status from the CSR; we need to read the CSR
247	 * for media type anyhow, and the link status in the CSR
248	 * doens't latch, so fewer register reads are required.
249	 */
250	csr = PHY_READ(sc, MII_LXTPHY_CSR);
251	if (csr & CSR_LINK)
252		mii->mii_media_status |= IFM_ACTIVE;
253
254	bmcr = PHY_READ(sc, MII_BMCR);
255	if (bmcr & BMCR_ISO) {
256		mii->mii_media_active |= IFM_NONE;
257		mii->mii_media_status = 0;
258		return;
259	}
260
261	if (bmcr & BMCR_LOOP)
262		mii->mii_media_active |= IFM_LOOP;
263
264	if (bmcr & BMCR_AUTOEN) {
265		bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
266		if ((bmsr & BMSR_ACOMP) == 0) {
267			/* Erg, still trying, I guess... */
268			mii->mii_media_active |= IFM_NONE;
269			return;
270		}
271		if (csr & CSR_SPEED)
272			mii->mii_media_active |= IFM_100_TX;
273		else
274			mii->mii_media_active |= IFM_10_T;
275		if (csr & CSR_DUPLEX)
276			mii->mii_media_active |= IFM_FDX;
277	} else
278		mii->mii_media_active = ife->ifm_media;
279}
280
281static void
282lxtphy_set_tp(struct mii_softc *sc)
283{
284	int cfg;
285
286	cfg = PHY_READ(sc, MII_LXTPHY_CONFIG);
287	cfg &= ~CONFIG_100BASEFX;
288	PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg);
289}
290
291static void
292lxtphy_set_fx(struct mii_softc *sc)
293{
294	int cfg;
295
296	cfg = PHY_READ(sc, MII_LXTPHY_CONFIG);
297	cfg |= CONFIG_100BASEFX;
298	PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg);
299}
300