196f2e892SBill Paul /*
2df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro F. Giffuni *
496f2e892SBill Paul * Copyright (c) 1997, 1998, 1999
596f2e892SBill Paul * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
696f2e892SBill Paul *
796f2e892SBill Paul * Redistribution and use in source and binary forms, with or without
896f2e892SBill Paul * modification, are permitted provided that the following conditions
996f2e892SBill Paul * are met:
1096f2e892SBill Paul * 1. Redistributions of source code must retain the above copyright
1196f2e892SBill Paul * notice, this list of conditions and the following disclaimer.
1296f2e892SBill Paul * 2. Redistributions in binary form must reproduce the above copyright
1396f2e892SBill Paul * notice, this list of conditions and the following disclaimer in the
1496f2e892SBill Paul * documentation and/or other materials provided with the distribution.
1596f2e892SBill Paul * 3. All advertising materials mentioning features or use of this software
1696f2e892SBill Paul * must display the following acknowledgement:
1796f2e892SBill Paul * This product includes software developed by Bill Paul.
1896f2e892SBill Paul * 4. Neither the name of the author nor the names of any co-contributors
1996f2e892SBill Paul * may be used to endorse or promote products derived from this software
2096f2e892SBill Paul * without specific prior written permission.
2196f2e892SBill Paul *
2296f2e892SBill Paul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2396f2e892SBill Paul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2496f2e892SBill Paul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2596f2e892SBill Paul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2696f2e892SBill Paul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2796f2e892SBill Paul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2896f2e892SBill Paul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2996f2e892SBill Paul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3096f2e892SBill Paul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3196f2e892SBill Paul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3296f2e892SBill Paul * THE POSSIBILITY OF SUCH DAMAGE.
3396f2e892SBill Paul */
3496f2e892SBill Paul
35aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
3696f2e892SBill Paul /*
3796f2e892SBill Paul * Pseudo-driver for media selection on the Lite-On PNIC 82c168
3896f2e892SBill Paul * chip. The NWAY support on this chip is horribly broken, so we
3996f2e892SBill Paul * only support manual mode selection. This is lame, but getting
4096f2e892SBill Paul * NWAY to work right is amazingly difficult.
4196f2e892SBill Paul */
4296f2e892SBill Paul
4396f2e892SBill Paul #include <sys/param.h>
4496f2e892SBill Paul #include <sys/systm.h>
4596f2e892SBill Paul #include <sys/kernel.h>
4696f2e892SBill Paul #include <sys/socket.h>
4796f2e892SBill Paul #include <sys/errno.h>
48f34fa851SJohn Baldwin #include <sys/lock.h>
4996f2e892SBill Paul #include <sys/module.h>
5035e0e5b3SJohn Baldwin #include <sys/mutex.h>
5196f2e892SBill Paul #include <sys/bus.h>
5296f2e892SBill Paul
5396f2e892SBill Paul #include <net/if.h>
5476039bc8SGleb Smirnoff #include <net/if_var.h>
5596f2e892SBill Paul #include <net/if_arp.h>
5696f2e892SBill Paul #include <net/if_media.h>
5796f2e892SBill Paul
5896f2e892SBill Paul #include <dev/mii/mii.h>
5996f2e892SBill Paul #include <dev/mii/miivar.h>
602d3ce713SDavid E. O'Brien #include "miidevs.h"
6196f2e892SBill Paul
6296f2e892SBill Paul #include <machine/bus.h>
6396f2e892SBill Paul #include <machine/resource.h>
6496f2e892SBill Paul
656a3033a8SWarner Losh #include <dev/dc/if_dcreg.h>
6696f2e892SBill Paul
6796f2e892SBill Paul #include "miibus_if.h"
6896f2e892SBill Paul
69e51a25f8SAlfred Perlstein static int pnphy_probe(device_t);
70e51a25f8SAlfred Perlstein static int pnphy_attach(device_t);
7196f2e892SBill Paul
7296f2e892SBill Paul static device_method_t pnphy_methods[] = {
7396f2e892SBill Paul /* device interface */
7496f2e892SBill Paul DEVMETHOD(device_probe, pnphy_probe),
7596f2e892SBill Paul DEVMETHOD(device_attach, pnphy_attach),
76279fe8d1SPoul-Henning Kamp DEVMETHOD(device_detach, mii_phy_detach),
7796f2e892SBill Paul DEVMETHOD(device_shutdown, bus_generic_shutdown),
78604f5f1fSMarius Strobl DEVMETHOD_END
7996f2e892SBill Paul };
8096f2e892SBill Paul
8196f2e892SBill Paul static driver_t pnphy_driver = {
8296f2e892SBill Paul "pnphy",
8396f2e892SBill Paul pnphy_methods,
8496f2e892SBill Paul sizeof(struct mii_softc)
8596f2e892SBill Paul };
8696f2e892SBill Paul
87*64450e3aSJohn Baldwin DRIVER_MODULE(pnphy, miibus, pnphy_driver, 0, 0);
8896f2e892SBill Paul
89e51a25f8SAlfred Perlstein static int pnphy_service(struct mii_softc *, struct mii_data *, int);
90e51a25f8SAlfred Perlstein static void pnphy_status(struct mii_softc *);
913fcb7a53SMarius Strobl static void pnphy_reset(struct mii_softc *);
923fcb7a53SMarius Strobl
933fcb7a53SMarius Strobl static const struct mii_phy_funcs pnphy_funcs = {
943fcb7a53SMarius Strobl pnphy_service,
953fcb7a53SMarius Strobl pnphy_status,
963fcb7a53SMarius Strobl pnphy_reset
973fcb7a53SMarius Strobl };
9896f2e892SBill Paul
999c1c2e99SAlfred Perlstein static int
pnphy_probe(device_t dev)1007d830ac9SWarner Losh pnphy_probe(device_t dev)
10196f2e892SBill Paul {
10296f2e892SBill Paul struct mii_attach_args *ma;
10396f2e892SBill Paul
10496f2e892SBill Paul ma = device_get_ivars(dev);
10596f2e892SBill Paul
10696f2e892SBill Paul /*
10796f2e892SBill Paul * The dc driver will report the 82c168 vendor and device
10896f2e892SBill Paul * ID to let us know that it wants us to attach.
10996f2e892SBill Paul */
11096f2e892SBill Paul if (ma->mii_id1 != DC_VENDORID_LO ||
11196f2e892SBill Paul ma->mii_id2 != DC_DEVICEID_82C168)
11296f2e892SBill Paul return (ENXIO);
11396f2e892SBill Paul
11496f2e892SBill Paul device_set_desc(dev, "PNIC 82c168 media interface");
11596f2e892SBill Paul
11607c4a8dfSPyun YongHyeon return (BUS_PROBE_DEFAULT);
11796f2e892SBill Paul }
11896f2e892SBill Paul
1199c1c2e99SAlfred Perlstein static int
pnphy_attach(device_t dev)1207d830ac9SWarner Losh pnphy_attach(device_t dev)
12196f2e892SBill Paul {
12296f2e892SBill Paul struct mii_softc *sc;
12396f2e892SBill Paul
12496f2e892SBill Paul sc = device_get_softc(dev);
12596f2e892SBill Paul
1263fcb7a53SMarius Strobl mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE,
1273fcb7a53SMarius Strobl &pnphy_funcs, 0);
12896f2e892SBill Paul
12996f2e892SBill Paul sc->mii_capabilities =
13096f2e892SBill Paul BMSR_100TXFDX | BMSR_100TXHDX | BMSR_10TFDX | BMSR_10THDX;
1313fcb7a53SMarius Strobl sc->mii_capabilities &= sc->mii_capmask;
13296f2e892SBill Paul device_printf(dev, " ");
133b54282f6SMarius Strobl mii_phy_add_media(sc);
13496f2e892SBill Paul printf("\n");
13596f2e892SBill Paul
13696f2e892SBill Paul MIIBUS_MEDIAINIT(sc->mii_dev);
13796f2e892SBill Paul return (0);
13896f2e892SBill Paul }
13996f2e892SBill Paul
140d9730b8bSJonathan Lemon static int
pnphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)1417d830ac9SWarner Losh pnphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
14296f2e892SBill Paul {
14396f2e892SBill Paul struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
14496f2e892SBill Paul
14596f2e892SBill Paul switch (cmd) {
14696f2e892SBill Paul case MII_POLLSTAT:
14796f2e892SBill Paul break;
14896f2e892SBill Paul
14996f2e892SBill Paul case MII_MEDIACHG:
15096f2e892SBill Paul /*
15196f2e892SBill Paul * If the interface is not up, don't do anything.
15296f2e892SBill Paul */
15362d76917SMarcel Moolenaar if ((if_getflags(mii->mii_ifp) & IFF_UP) == 0)
15496f2e892SBill Paul break;
15596f2e892SBill Paul
15696f2e892SBill Paul /*
157c6397d3fSMarius Strobl * Note that auto-negotiation is broken on this chip.
15896f2e892SBill Paul */
159c6397d3fSMarius Strobl switch (IFM_SUBTYPE(ife->ifm_media)) {
16096f2e892SBill Paul case IFM_100_TX:
16196f2e892SBill Paul mii->mii_media_active = IFM_ETHER | IFM_100_TX;
162c6397d3fSMarius Strobl if ((ife->ifm_media & IFM_FDX) != 0)
16396f2e892SBill Paul mii->mii_media_active |= IFM_FDX;
16496f2e892SBill Paul MIIBUS_STATCHG(sc->mii_dev);
16596f2e892SBill Paul return (0);
16696f2e892SBill Paul case IFM_10_T:
16796f2e892SBill Paul mii->mii_media_active = IFM_ETHER | IFM_10_T;
168c6397d3fSMarius Strobl if ((ife->ifm_media & IFM_FDX) != 0)
16996f2e892SBill Paul mii->mii_media_active |= IFM_FDX;
17096f2e892SBill Paul MIIBUS_STATCHG(sc->mii_dev);
17196f2e892SBill Paul return (0);
17296f2e892SBill Paul default:
17396f2e892SBill Paul return (EINVAL);
17496f2e892SBill Paul }
17596f2e892SBill Paul break;
17696f2e892SBill Paul
17796f2e892SBill Paul case MII_TICK:
17896f2e892SBill Paul /*
17996f2e892SBill Paul * Is the interface even up?
18096f2e892SBill Paul */
18162d76917SMarcel Moolenaar if ((if_getflags(mii->mii_ifp) & IFF_UP) == 0)
18296f2e892SBill Paul return (0);
18396f2e892SBill Paul
184d9730b8bSJonathan Lemon break;
18596f2e892SBill Paul }
18696f2e892SBill Paul
18796f2e892SBill Paul /* Update the media status. */
1883fcb7a53SMarius Strobl PHY_STATUS(sc);
18996f2e892SBill Paul
19096f2e892SBill Paul /* Callback if something changed. */
191d9730b8bSJonathan Lemon mii_phy_update(sc, cmd);
19296f2e892SBill Paul return (0);
19396f2e892SBill Paul }
19496f2e892SBill Paul
195d9730b8bSJonathan Lemon static void
pnphy_status(struct mii_softc * sc)1967d830ac9SWarner Losh pnphy_status(struct mii_softc *sc)
19796f2e892SBill Paul {
19896f2e892SBill Paul struct mii_data *mii = sc->mii_pdata;
19996f2e892SBill Paul int reg;
20096f2e892SBill Paul struct dc_softc *dc_sc;
20196f2e892SBill Paul
20262d76917SMarcel Moolenaar dc_sc = if_getsoftc(mii->mii_ifp);
20396f2e892SBill Paul
20496f2e892SBill Paul mii->mii_media_status = IFM_AVALID;
20596f2e892SBill Paul mii->mii_media_active = IFM_ETHER;
20696f2e892SBill Paul
20796f2e892SBill Paul reg = CSR_READ_4(dc_sc, DC_ISR);
20896f2e892SBill Paul if (!(reg & DC_ISR_LINKFAIL))
20996f2e892SBill Paul mii->mii_media_status |= IFM_ACTIVE;
210c6397d3fSMarius Strobl reg = CSR_READ_4(dc_sc, DC_NETCFG);
211c6397d3fSMarius Strobl if (reg & DC_NETCFG_SPEEDSEL)
21296f2e892SBill Paul mii->mii_media_active |= IFM_10_T;
21396f2e892SBill Paul else
21496f2e892SBill Paul mii->mii_media_active |= IFM_100_TX;
215c6397d3fSMarius Strobl if (reg & DC_NETCFG_FULLDUPLEX)
21696f2e892SBill Paul mii->mii_media_active |= IFM_FDX;
217d7a9ad56SMarius Strobl else
218d7a9ad56SMarius Strobl mii->mii_media_active |= IFM_HDX;
21996f2e892SBill Paul }
2203fcb7a53SMarius Strobl
2213fcb7a53SMarius Strobl static void
pnphy_reset(struct mii_softc * sc __unused)2223fcb7a53SMarius Strobl pnphy_reset(struct mii_softc *sc __unused)
2233fcb7a53SMarius Strobl {
2243fcb7a53SMarius Strobl
2253fcb7a53SMarius Strobl }
226