1*4dff0d0bSmsaitoh /* $NetBSD: igphy.c,v 1.37 2020/11/04 09:15:10 msaitoh Exp $ */
244954feaSfvdl
344954feaSfvdl /*
444954feaSfvdl * The Intel copyright applies to the analog register setup, and the
5f3909175Smsaitoh * SmartSpeed workaround code.
644954feaSfvdl */
744954feaSfvdl
844954feaSfvdl /*******************************************************************************
944954feaSfvdl
1044954feaSfvdl Copyright (c) 2001-2003, Intel Corporation
1144954feaSfvdl All rights reserved.
1244954feaSfvdl
1344954feaSfvdl Redistribution and use in source and binary forms, with or without
1444954feaSfvdl modification, are permitted provided that the following conditions are met:
1544954feaSfvdl
1644954feaSfvdl 1. Redistributions of source code must retain the above copyright notice,
1744954feaSfvdl this list of conditions and the following disclaimer.
1844954feaSfvdl
1944954feaSfvdl 2. Redistributions in binary form must reproduce the above copyright
2044954feaSfvdl notice, this list of conditions and the following disclaimer in the
2144954feaSfvdl documentation and/or other materials provided with the distribution.
2244954feaSfvdl
2344954feaSfvdl 3. Neither the name of the Intel Corporation nor the names of its
2444954feaSfvdl contributors may be used to endorse or promote products derived from
2544954feaSfvdl this software without specific prior written permission.
2644954feaSfvdl
2744954feaSfvdl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2844954feaSfvdl AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2944954feaSfvdl IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3044954feaSfvdl ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
3144954feaSfvdl LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3244954feaSfvdl CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3344954feaSfvdl SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3444954feaSfvdl INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3544954feaSfvdl CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3644954feaSfvdl ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3744954feaSfvdl POSSIBILITY OF SUCH DAMAGE.
3844954feaSfvdl
3944954feaSfvdl *******************************************************************************/
4044954feaSfvdl
4144954feaSfvdl
4244954feaSfvdl /*-
4344954feaSfvdl * Copyright (c) 1998, 1999, 2000, 2003 The NetBSD Foundation, Inc.
4444954feaSfvdl * All rights reserved.
4544954feaSfvdl *
4644954feaSfvdl * This code is derived from software contributed to The NetBSD Foundation
4744954feaSfvdl * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
4844954feaSfvdl * NASA Ames Research Center, and by Frank van der Linden.
4944954feaSfvdl *
5044954feaSfvdl * Redistribution and use in source and binary forms, with or without
5144954feaSfvdl * modification, are permitted provided that the following conditions
5244954feaSfvdl * are met:
5344954feaSfvdl * 1. Redistributions of source code must retain the above copyright
5444954feaSfvdl * notice, this list of conditions and the following disclaimer.
5544954feaSfvdl * 2. Redistributions in binary form must reproduce the above copyright
5644954feaSfvdl * notice, this list of conditions and the following disclaimer in the
5744954feaSfvdl * documentation and/or other materials provided with the distribution.
5844954feaSfvdl *
5944954feaSfvdl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
6044954feaSfvdl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
6144954feaSfvdl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
6244954feaSfvdl * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
6344954feaSfvdl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
6444954feaSfvdl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
6544954feaSfvdl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
6644954feaSfvdl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
6744954feaSfvdl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
6844954feaSfvdl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
6944954feaSfvdl * POSSIBILITY OF SUCH DAMAGE.
7044954feaSfvdl */
7144954feaSfvdl
7244954feaSfvdl #include <sys/cdefs.h>
73*4dff0d0bSmsaitoh __KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.37 2020/11/04 09:15:10 msaitoh Exp $");
7444954feaSfvdl
75d304a501Spooka #ifdef _KERNEL_OPT
7644954feaSfvdl #include "opt_mii.h"
77d304a501Spooka #endif
7844954feaSfvdl
7944954feaSfvdl #include <sys/param.h>
8044954feaSfvdl #include <sys/systm.h>
8144954feaSfvdl #include <sys/kernel.h>
8244954feaSfvdl #include <sys/device.h>
8344954feaSfvdl #include <sys/socket.h>
8444954feaSfvdl #include <sys/errno.h>
8544954feaSfvdl
8644954feaSfvdl #include <net/if.h>
8744954feaSfvdl #include <net/if_media.h>
8844954feaSfvdl
8944954feaSfvdl #include <dev/mii/mii.h>
9044954feaSfvdl #include <dev/mii/miivar.h>
9144954feaSfvdl #include <dev/mii/miidevs.h>
9244954feaSfvdl #include <dev/mii/igphyreg.h>
93c70d45b7Smsaitoh #include <dev/mii/igphyvar.h>
94f03b8365Smsaitoh #include <dev/pci/if_wmvar.h>
9544954feaSfvdl
9644954feaSfvdl static void igphy_reset(struct mii_softc *);
9744954feaSfvdl static void igphy_load_dspcode(struct mii_softc *);
9805b467b5Smsaitoh static void igphy_load_dspcode_igp3(struct mii_softc *);
9944954feaSfvdl static void igphy_smartspeed_workaround(struct mii_softc *sc);
10044954feaSfvdl
1017db0e577Sxtraeme static int igphymatch(device_t, cfdata_t, void *);
1027db0e577Sxtraeme static void igphyattach(device_t, device_t, void *);
10344954feaSfvdl
1047db0e577Sxtraeme CFATTACH_DECL_NEW(igphy, sizeof(struct igphy_softc),
10544954feaSfvdl igphymatch, igphyattach, mii_phy_detach, mii_phy_activate);
10644954feaSfvdl
1071efb3da0Sthorpej static int igphy_service(struct mii_softc *, struct mii_data *, int);
1081efb3da0Sthorpej static void igphy_status(struct mii_softc *);
10944954feaSfvdl
1101efb3da0Sthorpej static const struct mii_phy_funcs igphy_funcs = {
11144954feaSfvdl igphy_service, igphy_status, igphy_reset,
11244954feaSfvdl };
11344954feaSfvdl
1141efb3da0Sthorpej static const struct mii_phydesc igphys[] = {
115d23de6ffSchristos MII_PHY_DESC(yyINTEL, IGP01E1000),
116d23de6ffSchristos MII_PHY_DESC(yyINTEL, I82566),
117d23de6ffSchristos MII_PHY_END,
11844954feaSfvdl };
11944954feaSfvdl
1201efb3da0Sthorpej static int
igphymatch(device_t parent,cfdata_t match,void * aux)1217db0e577Sxtraeme igphymatch(device_t parent, cfdata_t match, void *aux)
12244954feaSfvdl {
12344954feaSfvdl struct mii_attach_args *ma = aux;
12444954feaSfvdl
12544954feaSfvdl if (mii_phy_match(ma, igphys) != NULL)
12644954feaSfvdl return 10;
12744954feaSfvdl
12844954feaSfvdl return 0;
12944954feaSfvdl }
13044954feaSfvdl
1311efb3da0Sthorpej static void
igphyattach(device_t parent,device_t self,void * aux)1327db0e577Sxtraeme igphyattach(device_t parent, device_t self, void *aux)
13344954feaSfvdl {
134838ee1e0Sthorpej struct mii_softc *sc = device_private(self);
13544954feaSfvdl struct mii_attach_args *ma = aux;
13644954feaSfvdl struct mii_data *mii = ma->mii_data;
13744954feaSfvdl const struct mii_phydesc *mpd;
138f03b8365Smsaitoh struct igphy_softc *igsc = (struct igphy_softc *)sc;
139f03b8365Smsaitoh prop_dictionary_t dict;
14044954feaSfvdl
14144954feaSfvdl mpd = mii_phy_match(ma, igphys);
14244954feaSfvdl aprint_naive(": Media interface\n");
14344954feaSfvdl aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
14444954feaSfvdl
145f03b8365Smsaitoh dict = device_properties(parent);
146f03b8365Smsaitoh if (!prop_dictionary_get_uint32(dict, "mactype", &igsc->sc_mactype))
147f03b8365Smsaitoh aprint_error("WARNING! Failed to get mactype\n");
14805b467b5Smsaitoh if (!prop_dictionary_get_uint32(dict, "macflags", &igsc->sc_macflags))
14905b467b5Smsaitoh aprint_error("WARNING! Failed to get macflags\n");
150f03b8365Smsaitoh
1517db0e577Sxtraeme sc->mii_dev = self;
15244954feaSfvdl sc->mii_inst = mii->mii_instance;
15344954feaSfvdl sc->mii_phy = ma->mii_phyno;
15448297c12Smsaitoh sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
15548297c12Smsaitoh sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
15648297c12Smsaitoh sc->mii_mpd_rev = MII_REV(ma->mii_id2);
15744954feaSfvdl sc->mii_funcs = &igphy_funcs;
15844954feaSfvdl sc->mii_pdata = mii;
15944954feaSfvdl sc->mii_flags = ma->mii_flags;
16044954feaSfvdl
16161b37dcbSthorpej mii_lock(mii);
16261b37dcbSthorpej
16344954feaSfvdl PHY_RESET(sc);
16444954feaSfvdl
165e746222fSmsaitoh PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
166e746222fSmsaitoh sc->mii_capabilities &= ma->mii_capmask;
16744954feaSfvdl if (sc->mii_capabilities & BMSR_EXTSTAT)
168e746222fSmsaitoh PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities);
169b2a008adSmsaitoh
17061b37dcbSthorpej mii_unlock(mii);
17161b37dcbSthorpej
17244954feaSfvdl mii_phy_add_media(sc);
17344954feaSfvdl }
17444954feaSfvdl
17505b467b5Smsaitoh typedef struct {
17644954feaSfvdl int reg;
17744954feaSfvdl uint16_t val;
17805b467b5Smsaitoh } dspcode;
17905b467b5Smsaitoh
18005b467b5Smsaitoh static const dspcode igp1code[] = {
18144954feaSfvdl { 0x1f95, 0x0001 },
18244954feaSfvdl { 0x1f71, 0xbd21 },
18344954feaSfvdl { 0x1f79, 0x0018 },
18444954feaSfvdl { 0x1f30, 0x1600 },
18544954feaSfvdl { 0x1f31, 0x0014 },
18644954feaSfvdl { 0x1f32, 0x161c },
18744954feaSfvdl { 0x1f94, 0x0003 },
18844954feaSfvdl { 0x1f96, 0x003f },
18944954feaSfvdl { 0x2010, 0x0008 },
19044954feaSfvdl { 0, 0 },
19144954feaSfvdl };
19205b467b5Smsaitoh
19305b467b5Smsaitoh static const dspcode igp1code_r2[] = {
19405b467b5Smsaitoh { 0x1f73, 0x0099 },
19505b467b5Smsaitoh { 0, 0 },
19605b467b5Smsaitoh };
19705b467b5Smsaitoh
19805b467b5Smsaitoh static const dspcode igp3code[] = {
19905b467b5Smsaitoh { 0x2f5b, 0x9018},
20005b467b5Smsaitoh { 0x2f52, 0x0000},
20105b467b5Smsaitoh { 0x2fb1, 0x8b24},
20205b467b5Smsaitoh { 0x2fb2, 0xf8f0},
20305b467b5Smsaitoh { 0x2010, 0x10b0},
20405b467b5Smsaitoh { 0x2011, 0x0000},
20505b467b5Smsaitoh { 0x20dd, 0x249a},
20605b467b5Smsaitoh { 0x20de, 0x00d3},
20705b467b5Smsaitoh { 0x28b4, 0x04ce},
20805b467b5Smsaitoh { 0x2f70, 0x29e4},
20905b467b5Smsaitoh { 0x0000, 0x0140},
21005b467b5Smsaitoh { 0x1f30, 0x1606},
21105b467b5Smsaitoh { 0x1f31, 0xb814},
21205b467b5Smsaitoh { 0x1f35, 0x002a},
21305b467b5Smsaitoh { 0x1f3e, 0x0067},
21405b467b5Smsaitoh { 0x1f54, 0x0065},
21505b467b5Smsaitoh { 0x1f55, 0x002a},
21605b467b5Smsaitoh { 0x1f56, 0x002a},
21705b467b5Smsaitoh { 0x1f72, 0x3fb0},
21805b467b5Smsaitoh { 0x1f76, 0xc0ff},
21905b467b5Smsaitoh { 0x1f77, 0x1dec},
22005b467b5Smsaitoh { 0x1f78, 0xf9ef},
22105b467b5Smsaitoh { 0x1f79, 0x0210},
22205b467b5Smsaitoh { 0x1895, 0x0003},
22305b467b5Smsaitoh { 0x1796, 0x0008},
22405b467b5Smsaitoh { 0x1798, 0xd008},
22505b467b5Smsaitoh { 0x1898, 0xd918},
22605b467b5Smsaitoh { 0x187a, 0x0800},
22705b467b5Smsaitoh { 0x0019, 0x008d},
22805b467b5Smsaitoh { 0x001b, 0x2080},
22905b467b5Smsaitoh { 0x0014, 0x0045},
23005b467b5Smsaitoh { 0x0000, 0x1340},
23105b467b5Smsaitoh { 0, 0 },
23205b467b5Smsaitoh };
23305b467b5Smsaitoh
23405b467b5Smsaitoh /* DSP patch for igp1 and igp2 */
23505b467b5Smsaitoh static void
igphy_load_dspcode(struct mii_softc * sc)23605b467b5Smsaitoh igphy_load_dspcode(struct mii_softc *sc)
23705b467b5Smsaitoh {
23805b467b5Smsaitoh struct igphy_softc *igsc = (struct igphy_softc *)sc;
23905b467b5Smsaitoh const dspcode *code;
24005b467b5Smsaitoh uint16_t reg;
24144954feaSfvdl int i;
24244954feaSfvdl
243f03b8365Smsaitoh /* This workaround is only for 82541 and 82547 */
244f03b8365Smsaitoh switch (igsc->sc_mactype) {
245f03b8365Smsaitoh case WM_T_82541:
246f03b8365Smsaitoh case WM_T_82547:
24705b467b5Smsaitoh code = igp1code;
24805b467b5Smsaitoh break;
249f03b8365Smsaitoh case WM_T_82541_2:
250f03b8365Smsaitoh case WM_T_82547_2:
25105b467b5Smsaitoh code = igp1code_r2;
252f03b8365Smsaitoh break;
253f03b8365Smsaitoh default:
25405b467b5Smsaitoh return; /* byebye */
255f03b8365Smsaitoh }
256f03b8365Smsaitoh
25705b467b5Smsaitoh /* Delay after phy reset to enable NVM configuration to load */
25805b467b5Smsaitoh delay(20000);
25905b467b5Smsaitoh
26005b467b5Smsaitoh /*
26105b467b5Smsaitoh * Save off the current value of register 0x2F5B to be restored at
26205b467b5Smsaitoh * the end of this routine.
26305b467b5Smsaitoh */
264e746222fSmsaitoh IGPHY_READ(sc, 0x2f5b, ®);
26505b467b5Smsaitoh
26605b467b5Smsaitoh /* Disabled the PHY transmitter */
26705b467b5Smsaitoh IGPHY_WRITE(sc, 0x2f5b, 0x0003);
26805b467b5Smsaitoh
26905b467b5Smsaitoh delay(20000);
27044954feaSfvdl
27172951728Smsaitoh PHY_WRITE(sc, IGPHY_PAGE_SELECT, 0x0000);
27244954feaSfvdl PHY_WRITE(sc, 0x0000, 0x0140);
27344954feaSfvdl
27405b467b5Smsaitoh delay(5000);
27544954feaSfvdl
27605b467b5Smsaitoh for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
27705b467b5Smsaitoh IGPHY_WRITE(sc, code[i].reg, code[i].val);
27844954feaSfvdl
27972951728Smsaitoh PHY_WRITE(sc, IGPHY_PAGE_SELECT, 0x0000);
28044954feaSfvdl PHY_WRITE(sc, 0x0000, 0x3300);
28105b467b5Smsaitoh
28205b467b5Smsaitoh delay(20000);
28305b467b5Smsaitoh
28405b467b5Smsaitoh /* Now enable the transmitter */
28505b467b5Smsaitoh IGPHY_WRITE(sc, 0x2f5b, reg);
28605b467b5Smsaitoh }
28705b467b5Smsaitoh
28805b467b5Smsaitoh static void
igphy_load_dspcode_igp3(struct mii_softc * sc)28905b467b5Smsaitoh igphy_load_dspcode_igp3(struct mii_softc *sc)
29005b467b5Smsaitoh {
29105b467b5Smsaitoh const dspcode *code = igp3code;
29205b467b5Smsaitoh int i;
29305b467b5Smsaitoh
29405b467b5Smsaitoh for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
29505b467b5Smsaitoh IGPHY_WRITE(sc, code[i].reg, code[i].val);
29644954feaSfvdl }
29744954feaSfvdl
29844954feaSfvdl static void
igphy_reset(struct mii_softc * sc)29944954feaSfvdl igphy_reset(struct mii_softc *sc)
30044954feaSfvdl {
301f03b8365Smsaitoh struct igphy_softc *igsc = (struct igphy_softc *)sc;
30244954feaSfvdl uint16_t fused, fine, coarse;
30344954feaSfvdl
30461b37dcbSthorpej KASSERT(mii_locked(sc->mii_pdata));
30561b37dcbSthorpej
30644954feaSfvdl mii_phy_reset(sc);
30705b467b5Smsaitoh delay(150);
30805b467b5Smsaitoh
30905b467b5Smsaitoh switch (igsc->sc_mactype) {
31005b467b5Smsaitoh case WM_T_82541:
31105b467b5Smsaitoh case WM_T_82547:
31205b467b5Smsaitoh case WM_T_82541_2:
31305b467b5Smsaitoh case WM_T_82547_2:
31444954feaSfvdl igphy_load_dspcode(sc);
31505b467b5Smsaitoh break;
31605b467b5Smsaitoh case WM_T_ICH8:
31705b467b5Smsaitoh case WM_T_ICH9:
31805b467b5Smsaitoh if ((igsc->sc_macflags & WM_F_EEPROM_INVALID) != 0)
31905b467b5Smsaitoh igphy_load_dspcode_igp3(sc);
32005b467b5Smsaitoh break;
32105b467b5Smsaitoh default: /* Not for ICH10, PCH and 8257[12] */
32205b467b5Smsaitoh break;
32305b467b5Smsaitoh }
32444954feaSfvdl
325f03b8365Smsaitoh if (igsc->sc_mactype == WM_T_82547) {
32672951728Smsaitoh IGPHY_READ(sc, IGPHY_ANALOG_SPARE_FUSE_STATUS, &fused);
32744954feaSfvdl if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) {
32872951728Smsaitoh IGPHY_READ(sc, IGPHY_ANALOG_FUSE_STATUS, &fused);
32944954feaSfvdl
33044954feaSfvdl fine = fused & ANALOG_FUSE_FINE_MASK;
33144954feaSfvdl coarse = fused & ANALOG_FUSE_COARSE_MASK;
33244954feaSfvdl
33344954feaSfvdl if (coarse > ANALOG_FUSE_COARSE_THRESH) {
33444954feaSfvdl coarse -= ANALOG_FUSE_COARSE_10;
33544954feaSfvdl fine -= ANALOG_FUSE_FINE_1;
33644954feaSfvdl } else if (coarse == ANALOG_FUSE_COARSE_THRESH)
33744954feaSfvdl fine -= ANALOG_FUSE_FINE_10;
33844954feaSfvdl
33944954feaSfvdl fused = (fused & ANALOG_FUSE_POLY_MASK) |
34044954feaSfvdl (fine & ANALOG_FUSE_FINE_MASK) |
34144954feaSfvdl (coarse & ANALOG_FUSE_COARSE_MASK);
34244954feaSfvdl
34372951728Smsaitoh IGPHY_WRITE(sc, IGPHY_ANALOG_FUSE_CONTROL, fused);
34472951728Smsaitoh IGPHY_WRITE(sc, IGPHY_ANALOG_FUSE_BYPASS,
34544954feaSfvdl ANALOG_FUSE_ENABLE_SW_CONTROL);
34644954feaSfvdl }
347f03b8365Smsaitoh }
34872951728Smsaitoh PHY_WRITE(sc, IGPHY_PAGE_SELECT, 0x0000);
34944954feaSfvdl }
35044954feaSfvdl
35144954feaSfvdl
3521efb3da0Sthorpej static int
igphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)35344954feaSfvdl igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
35444954feaSfvdl {
35544954feaSfvdl struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
35644954feaSfvdl uint16_t reg;
35744954feaSfvdl
35861b37dcbSthorpej KASSERT(mii_locked(mii));
35961b37dcbSthorpej
36044954feaSfvdl switch (cmd) {
36144954feaSfvdl case MII_POLLSTAT:
3629846d3fdSmsaitoh /* If we're not polling our PHY instance, just return. */
36344954feaSfvdl if (IFM_INST(ife->ifm_media) != sc->mii_inst)
3649846d3fdSmsaitoh return 0;
36544954feaSfvdl break;
36644954feaSfvdl
36744954feaSfvdl case MII_MEDIACHG:
36844954feaSfvdl /*
36944954feaSfvdl * If the media indicates a different PHY instance,
37044954feaSfvdl * isolate ourselves.
37144954feaSfvdl */
37244954feaSfvdl if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
373e746222fSmsaitoh PHY_READ(sc, MII_BMCR, ®);
37444954feaSfvdl PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
3759846d3fdSmsaitoh return 0;
37644954feaSfvdl }
37744954feaSfvdl
3789846d3fdSmsaitoh /* If the interface is not up, don't do anything. */
37944954feaSfvdl if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
38044954feaSfvdl break;
38144954feaSfvdl
38272951728Smsaitoh PHY_READ(sc, IGPHY_PORT_CTRL, ®);
383f0a2eb28Smsaitoh if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
384f0a2eb28Smsaitoh reg |= PSCR_AUTO_MDIX;
385f0a2eb28Smsaitoh reg &= ~PSCR_FORCE_MDI_MDIX;
38672951728Smsaitoh PHY_WRITE(sc, IGPHY_PORT_CTRL, reg);
387f0a2eb28Smsaitoh } else {
388f0a2eb28Smsaitoh reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX);
38972951728Smsaitoh PHY_WRITE(sc, IGPHY_PORT_CTRL, reg);
390f0a2eb28Smsaitoh }
391f0a2eb28Smsaitoh
39244954feaSfvdl mii_phy_setmedia(sc);
39344954feaSfvdl break;
39444954feaSfvdl
39544954feaSfvdl case MII_TICK:
3969846d3fdSmsaitoh /* If we're not currently selected, just return. */
39744954feaSfvdl if (IFM_INST(ife->ifm_media) != sc->mii_inst)
3989846d3fdSmsaitoh return 0;
39944954feaSfvdl
40044954feaSfvdl igphy_smartspeed_workaround(sc);
40144954feaSfvdl
40244954feaSfvdl if (mii_phy_tick(sc) == EJUSTRETURN)
4039846d3fdSmsaitoh return 0;
40444954feaSfvdl break;
40544954feaSfvdl
40644954feaSfvdl case MII_DOWN:
40744954feaSfvdl mii_phy_down(sc);
4089846d3fdSmsaitoh return 0;
40944954feaSfvdl }
41044954feaSfvdl
41144954feaSfvdl /* Update the media status. */
41244954feaSfvdl mii_phy_status(sc);
41344954feaSfvdl
41444954feaSfvdl /* Callback if something changed. */
41544954feaSfvdl mii_phy_update(sc, cmd);
4169846d3fdSmsaitoh return 0;
41744954feaSfvdl }
41844954feaSfvdl
41944954feaSfvdl
4201efb3da0Sthorpej static void
igphy_status(struct mii_softc * sc)42144954feaSfvdl igphy_status(struct mii_softc *sc)
42244954feaSfvdl {
42344954feaSfvdl struct mii_data *mii = sc->mii_pdata;
42444954feaSfvdl struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
42544954feaSfvdl uint16_t bmcr, pssr, gtsr, bmsr;
42644954feaSfvdl
42761b37dcbSthorpej KASSERT(mii_locked(mii));
42861b37dcbSthorpej
42944954feaSfvdl mii->mii_media_status = IFM_AVALID;
43044954feaSfvdl mii->mii_media_active = IFM_ETHER;
43144954feaSfvdl
43272951728Smsaitoh PHY_READ(sc, IGPHY_PORT_STATUS, &pssr);
43344954feaSfvdl
4344bdc7ccdSmsaitoh if (pssr & IGPHY_PSSR_LINK_UP)
43544954feaSfvdl mii->mii_media_status |= IFM_ACTIVE;
43644954feaSfvdl
437e746222fSmsaitoh PHY_READ(sc, MII_BMCR, &bmcr);
43844954feaSfvdl if (bmcr & BMCR_ISO) {
43944954feaSfvdl mii->mii_media_active |= IFM_NONE;
44044954feaSfvdl return;
44144954feaSfvdl }
44244954feaSfvdl
44344954feaSfvdl if (bmcr & BMCR_LOOP)
44444954feaSfvdl mii->mii_media_active |= IFM_LOOP;
44544954feaSfvdl
446e746222fSmsaitoh PHY_READ(sc, MII_BMSR, &bmsr);
447e746222fSmsaitoh PHY_READ(sc, MII_BMSR, &bmsr);
44844954feaSfvdl
4499846d3fdSmsaitoh /* XXX can't check if the info is valid, no 'negotiation done' bit? */
45044954feaSfvdl if (bmcr & BMCR_AUTOEN) {
45144954feaSfvdl if ((bmsr & BMSR_ACOMP) == 0) {
45244954feaSfvdl mii->mii_media_active |= IFM_NONE;
45344954feaSfvdl return;
45444954feaSfvdl }
4554bdc7ccdSmsaitoh switch (pssr & IGPHY_PSSR_SPEED_MASK) {
4564bdc7ccdSmsaitoh case IGPHY_PSSR_SPEED_1000MBPS:
45744954feaSfvdl mii->mii_media_active |= IFM_1000_T;
458e746222fSmsaitoh PHY_READ(sc, MII_100T2SR, >sr);
45944954feaSfvdl if (gtsr & GTSR_MS_RES)
46044954feaSfvdl mii->mii_media_active |= IFM_ETH_MASTER;
46144954feaSfvdl break;
46244954feaSfvdl
4634bdc7ccdSmsaitoh case IGPHY_PSSR_SPEED_100MBPS:
46444954feaSfvdl mii->mii_media_active |= IFM_100_TX;
46544954feaSfvdl break;
46644954feaSfvdl
4674bdc7ccdSmsaitoh case IGPHY_PSSR_SPEED_10MBPS:
46844954feaSfvdl mii->mii_media_active |= IFM_10_T;
46944954feaSfvdl break;
47044954feaSfvdl
47144954feaSfvdl default:
47244954feaSfvdl mii->mii_media_active |= IFM_NONE;
47344954feaSfvdl mii->mii_media_status = 0;
47444954feaSfvdl return;
47544954feaSfvdl }
47644954feaSfvdl
4774bdc7ccdSmsaitoh if (pssr & IGPHY_PSSR_FULL_DUPLEX)
47884694bb5Sthorpej mii->mii_media_active |=
47908645d15Sthorpej IFM_FDX | mii_phy_flowstatus(sc);
480a7fbee7bSmsaitoh else
481a7fbee7bSmsaitoh mii->mii_media_active |= IFM_HDX;
48244954feaSfvdl } else
48344954feaSfvdl mii->mii_media_active = ife->ifm_media;
48444954feaSfvdl }
48544954feaSfvdl
48644954feaSfvdl static void
igphy_smartspeed_workaround(struct mii_softc * sc)48744954feaSfvdl igphy_smartspeed_workaround(struct mii_softc *sc)
48844954feaSfvdl {
48929a0a6f5Sthorpej struct igphy_softc *igsc = (struct igphy_softc *)sc;
49029a0a6f5Sthorpej uint16_t reg, gtsr, gtcr;
49129a0a6f5Sthorpej
492f03b8365Smsaitoh /* This workaround is only for 82541 and 82547 */
493f03b8365Smsaitoh switch (igsc->sc_mactype) {
494f03b8365Smsaitoh case WM_T_82541:
495f03b8365Smsaitoh case WM_T_82541_2:
496f03b8365Smsaitoh case WM_T_82547:
497f03b8365Smsaitoh case WM_T_82547_2:
498f03b8365Smsaitoh break;
499f03b8365Smsaitoh default:
500f03b8365Smsaitoh /* byebye */
501f03b8365Smsaitoh return;
502f03b8365Smsaitoh }
503f03b8365Smsaitoh
504e746222fSmsaitoh PHY_READ(sc, MII_BMCR, ®);
505e746222fSmsaitoh if ((reg & BMCR_AUTOEN) == 0)
50629a0a6f5Sthorpej return;
50729a0a6f5Sthorpej
50829a0a6f5Sthorpej /* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */
50944954feaSfvdl
510e746222fSmsaitoh PHY_READ(sc, MII_BMSR, ®);
511e746222fSmsaitoh PHY_READ(sc, MII_BMSR, ®);
51229a0a6f5Sthorpej if ((reg & BMSR_LINK) == 0) {
51329a0a6f5Sthorpej switch (igsc->sc_smartspeed) {
51444954feaSfvdl case 0:
515e746222fSmsaitoh PHY_READ(sc, MII_100T2SR, >sr);
51644954feaSfvdl if (!(gtsr & GTSR_MAN_MS_FLT))
51744954feaSfvdl break;
518e746222fSmsaitoh PHY_READ(sc, MII_100T2SR, >sr);
51944954feaSfvdl if (gtsr & GTSR_MAN_MS_FLT) {
520e746222fSmsaitoh PHY_READ(sc, MII_100T2CR, >cr);
52144954feaSfvdl if (gtcr & GTCR_MAN_MS) {
52244954feaSfvdl gtcr &= ~GTCR_MAN_MS;
523e746222fSmsaitoh PHY_WRITE(sc, MII_100T2CR, gtcr);
52444954feaSfvdl }
525e28eda5dSmsaitoh mii_phy_auto(sc);
52644954feaSfvdl }
52744954feaSfvdl break;
52844954feaSfvdl case IGPHY_TICK_DOWNSHIFT:
529e746222fSmsaitoh PHY_READ(sc, MII_100T2CR, >cr);
53044954feaSfvdl gtcr |= GTCR_MAN_MS;
53144954feaSfvdl PHY_WRITE(sc, MII_100T2CR, gtcr);
532e28eda5dSmsaitoh mii_phy_auto(sc);
53344954feaSfvdl break;
53444954feaSfvdl default:
53544954feaSfvdl break;
53644954feaSfvdl }
53729a0a6f5Sthorpej if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX)
53829a0a6f5Sthorpej igsc->sc_smartspeed = 0;
53929a0a6f5Sthorpej } else
54029a0a6f5Sthorpej igsc->sc_smartspeed = 0;
54144954feaSfvdl }
542