172132Ssemenu/*-
272132Ssemenu * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
372132Ssemenu * All rights reserved.
472132Ssemenu *
572132Ssemenu * This code is derived from software contributed to The NetBSD Foundation
672132Ssemenu * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
772132Ssemenu * NASA Ames Research Center.
872132Ssemenu *
972132Ssemenu * Redistribution and use in source and binary forms, with or without
1072132Ssemenu * modification, are permitted provided that the following conditions
1172132Ssemenu * are met:
1272132Ssemenu * 1. Redistributions of source code must retain the above copyright
1372132Ssemenu *    notice, this list of conditions and the following disclaimer.
1472132Ssemenu * 2. Redistributions in binary form must reproduce the above copyright
1572132Ssemenu *    notice, this list of conditions and the following disclaimer in the
1672132Ssemenu *    documentation and/or other materials provided with the distribution.
1772132Ssemenu *
1872132Ssemenu * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1972132Ssemenu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2072132Ssemenu * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2172132Ssemenu * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2272132Ssemenu * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2372132Ssemenu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2472132Ssemenu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2572132Ssemenu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2672132Ssemenu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2772132Ssemenu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2872132Ssemenu * POSSIBILITY OF SUCH DAMAGE.
2972132Ssemenu */
30119418Sobrien
31139749Simp/*-
3272132Ssemenu * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
3372132Ssemenu *
3472132Ssemenu * Redistribution and use in source and binary forms, with or without
3572132Ssemenu * modification, are permitted provided that the following conditions
3672132Ssemenu * are met:
3772132Ssemenu * 1. Redistributions of source code must retain the above copyright
3872132Ssemenu *    notice, this list of conditions and the following disclaimer.
3972132Ssemenu * 2. Redistributions in binary form must reproduce the above copyright
4072132Ssemenu *    notice, this list of conditions and the following disclaimer in the
4172132Ssemenu *    documentation and/or other materials provided with the distribution.
4272132Ssemenu *
4372132Ssemenu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
4472132Ssemenu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4572132Ssemenu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
4672132Ssemenu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
4772132Ssemenu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4872132Ssemenu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4972132Ssemenu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
5072132Ssemenu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5172132Ssemenu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
5272132Ssemenu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5372132Ssemenu */
5472132Ssemenu
55129844Smarius#include <sys/cdefs.h>
56129844Smarius__FBSDID("$FreeBSD$");
57129844Smarius
5872132Ssemenu/*
5972132Ssemenu * Driver for Altima AC101 10/100 PHY
6072132Ssemenu */
6172132Ssemenu
6272132Ssemenu#include <sys/param.h>
6372132Ssemenu#include <sys/systm.h>
6472132Ssemenu#include <sys/kernel.h>
6572132Ssemenu#include <sys/socket.h>
6672132Ssemenu#include <sys/errno.h>
6772132Ssemenu#include <sys/module.h>
6872132Ssemenu#include <sys/bus.h>
6972132Ssemenu
7072132Ssemenu#include <net/if.h>
7172132Ssemenu#include <net/if_media.h>
7272132Ssemenu
7372132Ssemenu#include <dev/mii/mii.h>
7472132Ssemenu#include <dev/mii/miivar.h>
75109514Sobrien#include "miidevs.h"
7672132Ssemenu
7772132Ssemenu#include <dev/mii/acphyreg.h>
7872132Ssemenu
7972132Ssemenu#include "miibus_if.h"
8072132Ssemenu
81105135Salfredstatic int acphy_probe(device_t);
82105135Salfredstatic int acphy_attach(device_t);
8372132Ssemenu
8472132Ssemenustatic device_method_t acphy_methods[] = {
8572132Ssemenu	/* device interface */
8672132Ssemenu	DEVMETHOD(device_probe,		acphy_probe),
8772132Ssemenu	DEVMETHOD(device_attach,	acphy_attach),
8895722Sphk	DEVMETHOD(device_detach,	mii_phy_detach),
8972132Ssemenu	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
90227908Smarius	DEVMETHOD_END
9172132Ssemenu};
9272132Ssemenu
9372132Ssemenustatic devclass_t acphy_devclass;
9472132Ssemenu
9572132Ssemenustatic driver_t acphy_driver = {
9672132Ssemenu	"acphy",
9772132Ssemenu	acphy_methods,
9872132Ssemenu	sizeof(struct mii_softc)
9972132Ssemenu};
10072132Ssemenu
10172132SsemenuDRIVER_MODULE(acphy, miibus, acphy_driver, acphy_devclass, 0, 0);
10272132Ssemenu
10392739Salfredstatic int	acphy_service(struct mii_softc *, struct mii_data *, int);
10492739Salfredstatic void	acphy_reset(struct mii_softc *);
10592739Salfredstatic void	acphy_status(struct mii_softc *);
10672132Ssemenu
107164827Smariusstatic const struct mii_phydesc acphys[] = {
108221407Smarius	MII_PHY_DESC(ALTIMA, AC101),
109221407Smarius	MII_PHY_DESC(ALTIMA, AC101L),
110164834Smarius	/* XXX This is reported to work, but it's not from any data sheet. */
111221407Smarius	MII_PHY_DESC(ALTIMA, ACXXX),
112164827Smarius	MII_PHY_END
113164827Smarius};
114164827Smarius
115221407Smariusstatic const struct mii_phy_funcs acphy_funcs = {
116221407Smarius	acphy_service,
117221407Smarius	acphy_status,
118221407Smarius	acphy_reset
119221407Smarius};
120221407Smarius
121105135Salfredstatic int
122150763Simpacphy_probe(device_t dev)
12372132Ssemenu{
12472132Ssemenu
125164827Smarius	return (mii_phy_dev_probe(dev, acphys, BUS_PROBE_DEFAULT));
12672132Ssemenu}
12772132Ssemenu
128105135Salfredstatic int
129150763Simpacphy_attach(device_t dev)
13072132Ssemenu{
13172132Ssemenu	struct mii_softc *sc;
13272132Ssemenu
13372132Ssemenu	sc = device_get_softc(dev);
13472132Ssemenu
135221407Smarius	mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &acphy_funcs, 0);
13672132Ssemenu
137221407Smarius	PHY_RESET(sc);
13872132Ssemenu
139221407Smarius	sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask;
14072132Ssemenu	device_printf(dev, " ");
141165987Smarius
142221407Smarius#define	ADD(m, c)	ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL)
143165987Smarius	if ((PHY_READ(sc, MII_ACPHY_MCTL) & AC_MCTL_FX_SEL) != 0) {
144165987Smarius		sc->mii_flags |= MIIF_HAVEFIBER;
145165987Smarius		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst),
146165987Smarius		    MII_MEDIA_100_TX);
147165987Smarius		printf("100baseFX, ");
148165987Smarius		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst),
149165987Smarius		    MII_MEDIA_100_TX_FDX);
150165987Smarius		printf("100baseFX-FDX, ");
151165987Smarius	}
152165987Smarius#undef ADD
153165987Smarius
154164834Smarius	mii_phy_add_media(sc);
15572132Ssemenu	printf("\n");
15672132Ssemenu
15772132Ssemenu	MIIBUS_MEDIAINIT(sc->mii_dev);
15872132Ssemenu	return (0);
15972132Ssemenu}
16072132Ssemenu
16184145Sjlemonstatic int
162150763Simpacphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
16372132Ssemenu{
16472132Ssemenu	int reg;
16572132Ssemenu
16672132Ssemenu	switch (cmd) {
16772132Ssemenu	case MII_POLLSTAT:
16872132Ssemenu		break;
16972132Ssemenu
17072132Ssemenu	case MII_MEDIACHG:
17172132Ssemenu		/*
17272132Ssemenu		 * If the interface is not up, don't do anything.
17372132Ssemenu		 */
17472132Ssemenu		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
17572132Ssemenu			break;
17672132Ssemenu
17795877Ssemenu		/* Wake & deisolate up if necessary */
17872132Ssemenu		reg = PHY_READ(sc, MII_BMCR);
179164834Smarius		if (reg & (BMCR_ISO | BMCR_PDOWN))
18072132Ssemenu			PHY_WRITE(sc, MII_BMCR, reg & ~(BMCR_ISO | BMCR_PDOWN));
18172132Ssemenu
182164834Smarius		mii_phy_setmedia(sc);
18372132Ssemenu		break;
18472132Ssemenu
18572132Ssemenu	case MII_TICK:
18672132Ssemenu		/*
18784145Sjlemon		 * Is the interface even up?
18872132Ssemenu		 */
18984145Sjlemon		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
19072132Ssemenu			return (0);
19172132Ssemenu
19272132Ssemenu		/*
19395877Ssemenu		 * This PHY's autonegotiation doesn't need to be kicked.
19472132Ssemenu		 */
19572132Ssemenu		break;
19672132Ssemenu	}
19772132Ssemenu
19872132Ssemenu	/* Update the media status. */
199221407Smarius	PHY_STATUS(sc);
20072132Ssemenu
20172132Ssemenu	/* Callback if something changed. */
20284145Sjlemon	mii_phy_update(sc, cmd);
20372132Ssemenu	return (0);
20472132Ssemenu}
20572132Ssemenu
20684145Sjlemonstatic void
207150763Simpacphy_status(struct mii_softc *sc)
20872132Ssemenu{
20972132Ssemenu	struct mii_data *mii = sc->mii_pdata;
21072132Ssemenu	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
21172132Ssemenu	int bmsr, bmcr, diag;
21272132Ssemenu
21372132Ssemenu	mii->mii_media_status = IFM_AVALID;
21472132Ssemenu	mii->mii_media_active = IFM_ETHER;
21572132Ssemenu
21672132Ssemenu	bmsr = PHY_READ(sc, MII_BMSR) |
21772132Ssemenu	    PHY_READ(sc, MII_BMSR);
21872132Ssemenu	if (bmsr & BMSR_LINK)
21972132Ssemenu		mii->mii_media_status |= IFM_ACTIVE;
22072132Ssemenu
22172132Ssemenu	bmcr = PHY_READ(sc, MII_BMCR);
22272132Ssemenu	if (bmcr & BMCR_ISO) {
22372132Ssemenu		mii->mii_media_active |= IFM_NONE;
22472132Ssemenu		mii->mii_media_status = 0;
22572132Ssemenu		return;
22672132Ssemenu	}
22772132Ssemenu
22872132Ssemenu	if (bmcr & BMCR_LOOP)
22972132Ssemenu		mii->mii_media_active |= IFM_LOOP;
23072132Ssemenu
23172132Ssemenu	if (bmcr & BMCR_AUTOEN) {
23272132Ssemenu		if ((bmsr & BMSR_ACOMP) == 0) {
23372132Ssemenu			/* Erg, still trying, I guess... */
23472132Ssemenu			mii->mii_media_active |= IFM_NONE;
23572132Ssemenu			return;
23672132Ssemenu		}
23795877Ssemenu		diag = PHY_READ(sc, MII_ACPHY_DIAG);
23872132Ssemenu		if (diag & AC_DIAG_SPEED)
23972132Ssemenu			mii->mii_media_active |= IFM_100_TX;
24072132Ssemenu		else
24172132Ssemenu			mii->mii_media_active |= IFM_10_T;
24272132Ssemenu
24372132Ssemenu		if (diag & AC_DIAG_DUPLEX)
244221407Smarius			mii->mii_media_active |=
245221407Smarius			    IFM_FDX | mii_phy_flowstatus(sc);
246213384Smarius		else
247213384Smarius			mii->mii_media_active |= IFM_HDX;
24872132Ssemenu	} else
24972132Ssemenu		mii->mii_media_active = ife->ifm_media;
25072132Ssemenu}
25172132Ssemenu
25284145Sjlemonstatic void
253150763Simpacphy_reset(struct mii_softc *sc)
25472132Ssemenu{
25572132Ssemenu
25672132Ssemenu	mii_phy_reset(sc);
25772132Ssemenu	PHY_WRITE(sc, MII_ACPHY_INT, 0);
25872132Ssemenu}
259