1*7a9a30c5Sthorpej /* $NetBSD: icsphy.c,v 1.56 2020/03/15 23:04:50 thorpej Exp $ */
23f98e69bSthorpej
33f98e69bSthorpej /*-
449014bf5Sthorpej * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
53f98e69bSthorpej * All rights reserved.
63f98e69bSthorpej *
73f98e69bSthorpej * This code is derived from software contributed to The NetBSD Foundation
83f98e69bSthorpej * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
93f98e69bSthorpej * NASA Ames Research Center.
103f98e69bSthorpej *
113f98e69bSthorpej * Redistribution and use in source and binary forms, with or without
123f98e69bSthorpej * modification, are permitted provided that the following conditions
133f98e69bSthorpej * are met:
143f98e69bSthorpej * 1. Redistributions of source code must retain the above copyright
153f98e69bSthorpej * notice, this list of conditions and the following disclaimer.
163f98e69bSthorpej * 2. Redistributions in binary form must reproduce the above copyright
173f98e69bSthorpej * notice, this list of conditions and the following disclaimer in the
183f98e69bSthorpej * documentation and/or other materials provided with the distribution.
193f98e69bSthorpej *
203f98e69bSthorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
213f98e69bSthorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
223f98e69bSthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
233f98e69bSthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
243f98e69bSthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
253f98e69bSthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
263f98e69bSthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
273f98e69bSthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
283f98e69bSthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
293f98e69bSthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
303f98e69bSthorpej * POSSIBILITY OF SUCH DAMAGE.
313f98e69bSthorpej */
323f98e69bSthorpej
333f98e69bSthorpej /*
343f98e69bSthorpej * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
353f98e69bSthorpej *
363f98e69bSthorpej * Redistribution and use in source and binary forms, with or without
373f98e69bSthorpej * modification, are permitted provided that the following conditions
383f98e69bSthorpej * are met:
393f98e69bSthorpej * 1. Redistributions of source code must retain the above copyright
403f98e69bSthorpej * notice, this list of conditions and the following disclaimer.
413f98e69bSthorpej * 2. Redistributions in binary form must reproduce the above copyright
423f98e69bSthorpej * notice, this list of conditions and the following disclaimer in the
433f98e69bSthorpej * documentation and/or other materials provided with the distribution.
443f98e69bSthorpej *
453f98e69bSthorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
463f98e69bSthorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
473f98e69bSthorpej * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
483f98e69bSthorpej * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
493f98e69bSthorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
503f98e69bSthorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
513f98e69bSthorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
523f98e69bSthorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
533f98e69bSthorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
543f98e69bSthorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
553f98e69bSthorpej */
563f98e69bSthorpej
573f98e69bSthorpej /*
585af1b693Smsaitoh * driver for Integrated Circuit Systems' ICS1889-1893 ethernet 10/100 PHY
593f98e69bSthorpej * datasheet from www.icst.com
603f98e69bSthorpej */
613f98e69bSthorpej
628b7bb912Slukem #include <sys/cdefs.h>
63*7a9a30c5Sthorpej __KERNEL_RCSID(0, "$NetBSD: icsphy.c,v 1.56 2020/03/15 23:04:50 thorpej Exp $");
648b7bb912Slukem
653f98e69bSthorpej #include <sys/param.h>
663f98e69bSthorpej #include <sys/systm.h>
673f98e69bSthorpej #include <sys/kernel.h>
683f98e69bSthorpej #include <sys/device.h>
693f98e69bSthorpej #include <sys/socket.h>
703f98e69bSthorpej
713f98e69bSthorpej #include <net/if.h>
723f98e69bSthorpej #include <net/if_media.h>
733f98e69bSthorpej
743f98e69bSthorpej #include <dev/mii/mii.h>
753f98e69bSthorpej #include <dev/mii/miivar.h>
763f98e69bSthorpej #include <dev/mii/miidevs.h>
773f98e69bSthorpej
783f98e69bSthorpej #include <dev/mii/icsphyreg.h>
793f98e69bSthorpej
807db0e577Sxtraeme static int icsphymatch(device_t, cfdata_t, void *);
817db0e577Sxtraeme static void icsphyattach(device_t, device_t, void *);
823f98e69bSthorpej
837db0e577Sxtraeme CFATTACH_DECL_NEW(icsphy, sizeof(struct mii_softc),
84c9b3657cSthorpej icsphymatch, icsphyattach, mii_phy_detach, mii_phy_activate);
853f98e69bSthorpej
861efb3da0Sthorpej static int icsphy_service(struct mii_softc *, struct mii_data *, int);
871efb3da0Sthorpej static void icsphy_status(struct mii_softc *);
881efb3da0Sthorpej static void icsphy_reset(struct mii_softc *);
8949014bf5Sthorpej
901efb3da0Sthorpej static const struct mii_phy_funcs icsphy_funcs = {
9149014bf5Sthorpej icsphy_service, icsphy_status, icsphy_reset,
9249014bf5Sthorpej };
933f98e69bSthorpej
941efb3da0Sthorpej static const struct mii_phydesc icsphys[] = {
957b43da1bSchristos MII_PHY_DESC(ICS, 1889),
967b43da1bSchristos MII_PHY_DESC(ICS, 1890),
977b43da1bSchristos MII_PHY_DESC(ICS, 1892),
987b43da1bSchristos MII_PHY_DESC(ICS, 1893),
997b43da1bSchristos MII_PHY_DESC(ICS, 1893C),
1007b43da1bSchristos MII_PHY_END,
101424f7a1eSthorpej };
102424f7a1eSthorpej
1031efb3da0Sthorpej static int
icsphymatch(device_t parent,cfdata_t match,void * aux)1047db0e577Sxtraeme icsphymatch(device_t parent, cfdata_t match, void *aux)
1053f98e69bSthorpej {
1063f98e69bSthorpej struct mii_attach_args *ma = aux;
1073f98e69bSthorpej
108424f7a1eSthorpej if (mii_phy_match(ma, icsphys) != NULL)
1098e65e831Smsaitoh return 10;
1103f98e69bSthorpej
1118e65e831Smsaitoh return 0;
1123f98e69bSthorpej }
1133f98e69bSthorpej
1141efb3da0Sthorpej static void
icsphyattach(device_t parent,device_t self,void * aux)1157db0e577Sxtraeme icsphyattach(device_t parent, device_t self, void *aux)
1163f98e69bSthorpej {
117838ee1e0Sthorpej struct mii_softc *sc = device_private(self);
1183f98e69bSthorpej struct mii_attach_args *ma = aux;
1193f98e69bSthorpej struct mii_data *mii = ma->mii_data;
120424f7a1eSthorpej const struct mii_phydesc *mpd;
1213f98e69bSthorpej
122424f7a1eSthorpej mpd = mii_phy_match(ma, icsphys);
123c31f87a5Sthorpej aprint_naive(": Media interface\n");
124c31f87a5Sthorpej aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
1253f98e69bSthorpej
1267db0e577Sxtraeme sc->mii_dev = self;
1275af1b693Smsaitoh sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
1282a17544cSthorpej sc->mii_inst = mii->mii_instance;
1292a17544cSthorpej sc->mii_phy = ma->mii_phyno;
13049014bf5Sthorpej sc->mii_funcs = &icsphy_funcs;
1312a17544cSthorpej sc->mii_pdata = mii;
132b0178985Sthorpej sc->mii_flags = ma->mii_flags;
1333f98e69bSthorpej
134*7a9a30c5Sthorpej mii_lock(mii);
135*7a9a30c5Sthorpej
13649014bf5Sthorpej PHY_RESET(sc);
1373f98e69bSthorpej
138a5cdd4b4Smsaitoh PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
139a5cdd4b4Smsaitoh sc->mii_capabilities &= ma->mii_capmask;
140509697f3Smsaitoh
141*7a9a30c5Sthorpej mii_unlock(mii);
142*7a9a30c5Sthorpej
14384dc99fdSthorpej mii_phy_add_media(sc);
1443f98e69bSthorpej }
1453f98e69bSthorpej
1461efb3da0Sthorpej static int
icsphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)14789893e42Sthorpej icsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
1483f98e69bSthorpej {
1493f98e69bSthorpej struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
150a5cdd4b4Smsaitoh uint16_t reg;
1513f98e69bSthorpej
152*7a9a30c5Sthorpej KASSERT(mii_locked(mii));
153*7a9a30c5Sthorpej
1543f98e69bSthorpej switch (cmd) {
1553f98e69bSthorpej case MII_POLLSTAT:
1568e65e831Smsaitoh /* If we're not polling our PHY instance, just return. */
1572a17544cSthorpej if (IFM_INST(ife->ifm_media) != sc->mii_inst)
1588e65e831Smsaitoh return 0;
1593f98e69bSthorpej break;
1603f98e69bSthorpej
1613f98e69bSthorpej case MII_MEDIACHG:
1623f98e69bSthorpej /*
1633f98e69bSthorpej * If the media indicates a different PHY instance,
1643f98e69bSthorpej * isolate ourselves.
1653f98e69bSthorpej */
1662a17544cSthorpej if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
167a5cdd4b4Smsaitoh PHY_READ(sc, MII_BMCR, ®);
1682a17544cSthorpej PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
1698e65e831Smsaitoh return 0;
1703f98e69bSthorpej }
1713f98e69bSthorpej
1728e65e831Smsaitoh /* If the interface is not up, don't do anything. */
1733f98e69bSthorpej if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
1743f98e69bSthorpej break;
1753f98e69bSthorpej
1768fc600c3Sthorpej mii_phy_setmedia(sc);
1773f98e69bSthorpej break;
1783f98e69bSthorpej
1793f98e69bSthorpej case MII_TICK:
1808e65e831Smsaitoh /* If we're not currently selected, just return. */
1812a17544cSthorpej if (IFM_INST(ife->ifm_media) != sc->mii_inst)
1828e65e831Smsaitoh return 0;
1833f98e69bSthorpej
184ad61d101Sthorpej if (mii_phy_tick(sc) == EJUSTRETURN)
1858e65e831Smsaitoh return 0;
1863f98e69bSthorpej break;
187bca88a28Sthorpej
188bca88a28Sthorpej case MII_DOWN:
189bca88a28Sthorpej mii_phy_down(sc);
1908e65e831Smsaitoh return 0;
1913f98e69bSthorpej }
1923f98e69bSthorpej
1933f98e69bSthorpej /* Update the media status. */
1948923ca0bSthorpej mii_phy_status(sc);
1953f98e69bSthorpej
1963f98e69bSthorpej /* Callback if something changed. */
197ad61d101Sthorpej mii_phy_update(sc, cmd);
1988e65e831Smsaitoh return 0;
1993f98e69bSthorpej }
2003f98e69bSthorpej
2011efb3da0Sthorpej static void
icsphy_status(struct mii_softc * sc)20289893e42Sthorpej icsphy_status(struct mii_softc *sc)
2033f98e69bSthorpej {
2042a17544cSthorpej struct mii_data *mii = sc->mii_pdata;
2058fc600c3Sthorpej struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
206a5cdd4b4Smsaitoh uint16_t bmcr, qpr;
2073f98e69bSthorpej
208*7a9a30c5Sthorpej KASSERT(mii_locked(mii));
209*7a9a30c5Sthorpej
2103f98e69bSthorpej mii->mii_media_status = IFM_AVALID;
2113f98e69bSthorpej mii->mii_media_active = IFM_ETHER;
2123f98e69bSthorpej
2133f98e69bSthorpej /*
2143f98e69bSthorpej * Don't get link from the BMSR. It's available in the QPR,
2153f98e69bSthorpej * and we have to read it twice to unlatch it anyhow. This
2163f98e69bSthorpej * gives us fewer register reads.
2173f98e69bSthorpej */
218a5cdd4b4Smsaitoh PHY_READ(sc, MII_ICSPHY_QPR, &qpr); /* unlatch */
219a5cdd4b4Smsaitoh PHY_READ(sc, MII_ICSPHY_QPR, &qpr); /* real value */
2203f98e69bSthorpej
2213f98e69bSthorpej if (qpr & QPR_LINK)
2223f98e69bSthorpej mii->mii_media_status |= IFM_ACTIVE;
2233f98e69bSthorpej
224a5cdd4b4Smsaitoh PHY_READ(sc, MII_BMCR, &bmcr);
2253f98e69bSthorpej if (bmcr & BMCR_ISO) {
2263f98e69bSthorpej mii->mii_media_active |= IFM_NONE;
2273f98e69bSthorpej mii->mii_media_status = 0;
2283f98e69bSthorpej return;
2293f98e69bSthorpej }
2303f98e69bSthorpej
2313f98e69bSthorpej if (bmcr & BMCR_LOOP)
2323f98e69bSthorpej mii->mii_media_active |= IFM_LOOP;
2333f98e69bSthorpej
234aabf2a08Sthorpej if (bmcr & BMCR_AUTOEN) {
235aabf2a08Sthorpej if ((qpr & QPR_ACOMP) == 0) {
2363f98e69bSthorpej /* Erg, still trying, I guess... */
2373f98e69bSthorpej mii->mii_media_active |= IFM_NONE;
2383f98e69bSthorpej return;
2393f98e69bSthorpej }
2403f98e69bSthorpej if (qpr & QPR_SPEED)
2413f98e69bSthorpej mii->mii_media_active |= IFM_100_TX;
2423f98e69bSthorpej else
2433f98e69bSthorpej mii->mii_media_active |= IFM_10_T;
244b211437bSmsaitoh
2453f98e69bSthorpej if (qpr & QPR_FDX)
2463f98e69bSthorpej mii->mii_media_active |= IFM_FDX;
247b211437bSmsaitoh else
248b211437bSmsaitoh mii->mii_media_active |= IFM_HDX;
2492b695df1Sthorpej } else
2508fc600c3Sthorpej mii->mii_media_active = ife->ifm_media;
2513f98e69bSthorpej }
2523f98e69bSthorpej
2531efb3da0Sthorpej static void
icsphy_reset(struct mii_softc * sc)2541efb3da0Sthorpej icsphy_reset(struct mii_softc *sc)
2553f98e69bSthorpej {
2563f98e69bSthorpej
257*7a9a30c5Sthorpej KASSERT(mii_locked(sc->mii_pdata));
258*7a9a30c5Sthorpej
2592a17544cSthorpej mii_phy_reset(sc);
2608e65e831Smsaitoh /* Set powerdown feature */
2615af1b693Smsaitoh switch (sc->mii_mpd_model) {
2625af1b693Smsaitoh case MII_MODEL_ICS_1890:
2635af1b693Smsaitoh case MII_MODEL_ICS_1893:
2645af1b693Smsaitoh PHY_WRITE(sc, MII_ICSPHY_ECR2, ECR2_100AUTOPWRDN);
2655af1b693Smsaitoh break;
2665af1b693Smsaitoh case MII_MODEL_ICS_1892:
2675af1b693Smsaitoh PHY_WRITE(sc, MII_ICSPHY_ECR2,
2685af1b693Smsaitoh ECR2_10AUTOPWRDN | ECR2_100AUTOPWRDN);
2695af1b693Smsaitoh break;
2705af1b693Smsaitoh default:
2715af1b693Smsaitoh /* 1889 have no ECR2 */
2725af1b693Smsaitoh break;
2735af1b693Smsaitoh }
2745af1b693Smsaitoh /*
2755af1b693Smsaitoh * There is no description that the reset do auto-negotiation in the
2765af1b693Smsaitoh * data sheet.
2775af1b693Smsaitoh */
2785af1b693Smsaitoh PHY_WRITE(sc, MII_BMCR, BMCR_S100 | BMCR_STARTNEG | BMCR_FDX);
2793f98e69bSthorpej }
280