Sync with Intel's original em driver:

- Add dspcode for igp3 and use it when the EEPROM isn't available.
- Add some delays.
- Stop the PHY transmitter before patching the DSP code and restart it after wrote.
- Save and restore register 0x2f5b.
This commit is contained in:
msaitoh 2009-12-16 14:37:26 +00:00
parent 7a92e8e89d
commit 05b467b58c
3 changed files with 158 additions and 65 deletions

@ -1,4 +1,4 @@
/* $NetBSD: igphy.c,v 1.19 2009/12/16 04:50:35 msaitoh Exp $ */
/* $NetBSD: igphy.c,v 1.20 2009/12/16 14:37:26 msaitoh Exp $ */
/*
* The Intel copyright applies to the analog register setup, and the
@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.19 2009/12/16 04:50:35 msaitoh Exp $");
__KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.20 2009/12/16 14:37:26 msaitoh Exp $");
#include "opt_mii.h"
@ -94,10 +94,12 @@ struct igphy_softc {
struct mii_softc sc_mii;
int sc_smartspeed;
uint32_t sc_mactype;
uint32_t sc_macflags;
};
static void igphy_reset(struct mii_softc *);
static void igphy_load_dspcode(struct mii_softc *);
static void igphy_load_dspcode_igp3(struct mii_softc *);
static void igphy_smartspeed_workaround(struct mii_softc *sc);
static int igphymatch(device_t, cfdata_t, void *);
@ -152,6 +154,8 @@ igphyattach(device_t parent, device_t self, void *aux)
dict = device_properties(parent);
if (!prop_dictionary_get_uint32(dict, "mactype", &igsc->sc_mactype))
aprint_error("WARNING! Failed to get mactype\n");
if (!prop_dictionary_get_uint32(dict, "macflags", &igsc->sc_macflags))
aprint_error("WARNING! Failed to get macflags\n");
sc->mii_dev = self;
sc->mii_inst = mii->mii_instance;
@ -176,62 +180,127 @@ igphyattach(device_t parent, device_t self, void *aux)
aprint_normal("\n");
}
typedef struct {
int reg;
uint16_t val;
} dspcode;
static const dspcode igp1code[] = {
{ 0x1f95, 0x0001 },
{ 0x1f71, 0xbd21 },
{ 0x1f79, 0x0018 },
{ 0x1f30, 0x1600 },
{ 0x1f31, 0x0014 },
{ 0x1f32, 0x161c },
{ 0x1f94, 0x0003 },
{ 0x1f96, 0x003f },
{ 0x2010, 0x0008 },
{ 0, 0 },
};
static const dspcode igp1code_r2[] = {
{ 0x1f73, 0x0099 },
{ 0, 0 },
};
static const dspcode igp3code[] = {
{ 0x2f5b, 0x9018},
{ 0x2f52, 0x0000},
{ 0x2fb1, 0x8b24},
{ 0x2fb2, 0xf8f0},
{ 0x2010, 0x10b0},
{ 0x2011, 0x0000},
{ 0x20dd, 0x249a},
{ 0x20de, 0x00d3},
{ 0x28b4, 0x04ce},
{ 0x2f70, 0x29e4},
{ 0x0000, 0x0140},
{ 0x1f30, 0x1606},
{ 0x1f31, 0xb814},
{ 0x1f35, 0x002a},
{ 0x1f3e, 0x0067},
{ 0x1f54, 0x0065},
{ 0x1f55, 0x002a},
{ 0x1f56, 0x002a},
{ 0x1f72, 0x3fb0},
{ 0x1f76, 0xc0ff},
{ 0x1f77, 0x1dec},
{ 0x1f78, 0xf9ef},
{ 0x1f79, 0x0210},
{ 0x1895, 0x0003},
{ 0x1796, 0x0008},
{ 0x1798, 0xd008},
{ 0x1898, 0xd918},
{ 0x187a, 0x0800},
{ 0x0019, 0x008d},
{ 0x001b, 0x2080},
{ 0x0014, 0x0045},
{ 0x0000, 0x1340},
{ 0, 0 },
};
/* DSP patch for igp1 and igp2 */
static void
igphy_load_dspcode(struct mii_softc *sc)
{
struct igphy_softc *igsc = (struct igphy_softc *) sc;
static const struct {
int reg;
uint16_t val;
} dspcode[] = {
{ 0x1f95, 0x0001 },
{ 0x1f71, 0xbd21 },
{ 0x1f79, 0x0018 },
{ 0x1f30, 0x1600 },
{ 0x1f31, 0x0014 },
{ 0x1f32, 0x161c },
{ 0x1f94, 0x0003 },
{ 0x1f96, 0x003f },
{ 0x2010, 0x0008 },
{ 0, 0 },
};
const dspcode *code;
uint16_t reg;
int i;
/* This workaround is only for 82541 and 82547 */
switch (igsc->sc_mactype) {
case WM_T_82541:
case WM_T_82547:
code = igp1code;
break;
case WM_T_82541_2:
case WM_T_82547_2:
code = igp1code_r2;
break;
default:
/* byebye */
return;
return; /* byebye */
}
delay(10);
/* Delay after phy reset to enable NVM configuration to load */
delay(20000);
/*
* Save off the current value of register 0x2F5B to be restored at
* the end of this routine.
*/
reg = IGPHY_READ(sc, 0x2f5b);
/* Disabled the PHY transmitter */
IGPHY_WRITE(sc, 0x2f5b, 0x0003);
delay(20000);
PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
PHY_WRITE(sc, 0x0000, 0x0140);
delay(5);
delay(5000);
switch (igsc->sc_mactype) {
case WM_T_82541:
case WM_T_82547:
for (i = 0; dspcode[i].reg != 0; i++)
IGPHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
break;
case WM_T_82541_2:
case WM_T_82547_2:
IGPHY_WRITE(sc, 0x1f73, 0x0099);
break;
default:
break;
}
for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
IGPHY_WRITE(sc, code[i].reg, code[i].val);
PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
PHY_WRITE(sc, 0x0000, 0x3300);
delay(20000);
/* Now enable the transmitter */
IGPHY_WRITE(sc, 0x2f5b, reg);
}
static void
igphy_load_dspcode_igp3(struct mii_softc *sc)
{
const dspcode *code = igp3code;
int i;
for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
IGPHY_WRITE(sc, code[i].reg, code[i].val);
}
static void
@ -241,7 +310,23 @@ igphy_reset(struct mii_softc *sc)
uint16_t fused, fine, coarse;
mii_phy_reset(sc);
igphy_load_dspcode(sc);
delay(150);
switch (igsc->sc_mactype) {
case WM_T_82541:
case WM_T_82547:
case WM_T_82541_2:
case WM_T_82547_2:
igphy_load_dspcode(sc);
break;
case WM_T_ICH8:
case WM_T_ICH9:
if ((igsc->sc_macflags & WM_F_EEPROM_INVALID) != 0)
igphy_load_dspcode_igp3(sc);
break;
default: /* Not for ICH10, PCH and 8257[12] */
break;
}
if (igsc->sc_mactype == WM_T_82547) {
fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS);
@ -266,7 +351,7 @@ igphy_reset(struct mii_softc *sc)
ANALOG_FUSE_ENABLE_SW_CONTROL);
}
}
PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
}

@ -1,4 +1,4 @@
/* $NetBSD: if_wm.c,v 1.182 2009/12/16 04:50:35 msaitoh Exp $ */
/* $NetBSD: if_wm.c,v 1.183 2009/12/16 14:37:26 msaitoh Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@ -76,7 +76,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.182 2009/12/16 04:50:35 msaitoh Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.183 2009/12/16 14:37:26 msaitoh Exp $");
#include "bpfilter.h"
#include "rnd.h"
@ -380,22 +380,6 @@ do { \
(sc)->sc_rxtailp = &(m)->m_next; \
} while (/*CONSTCOND*/0)
/* sc_flags */
#define WM_F_HAS_MII 0x0001 /* has MII */
#define WM_F_EEPROM_HANDSHAKE 0x0002 /* requires EEPROM handshake */
#define WM_F_EEPROM_SEMAPHORE 0x0004 /* EEPROM with semaphore */
#define WM_F_EEPROM_EERDEEWR 0x0008 /* EEPROM access via EERD/EEWR */
#define WM_F_EEPROM_SPI 0x0010 /* EEPROM is SPI */
#define WM_F_EEPROM_FLASH 0x0020 /* EEPROM is FLASH */
#define WM_F_EEPROM_INVALID 0x0040 /* EEPROM not present (bad checksum) */
#define WM_F_IOH_VALID 0x0080 /* I/O handle is valid */
#define WM_F_BUS64 0x0100 /* bus is 64-bit */
#define WM_F_PCIX 0x0200 /* bus is PCI-X */
#define WM_F_CSA 0x0400 /* bus is CSA */
#define WM_F_PCIE 0x0800 /* bus is PCI-Express */
#define WM_F_SWFW_SYNC 0x1000 /* Software-Firmware synchronisation */
#define WM_F_SWFWHW_SYNC 0x2000 /* Software-Firmware synchronisation */
#ifdef WM_EVENT_COUNTERS
#define WM_EVCNT_INCR(ev) (ev)->ev_count++
#define WM_EVCNT_ADD(ev, val) (ev)->ev_count += (val)
@ -981,7 +965,7 @@ wm_attach(device_t parent, device_t self, void *aux)
sc->sc_type = WM_T_82542_2_0;
}
/* Set device properties */
/* Set device properties (mactype)*/
dict = device_properties(sc->sc_dev);
prop_dictionary_set_uint32(dict, "mactype", sc->sc_type);
@ -1351,18 +1335,26 @@ wm_attach(device_t parent, device_t self, void *aux)
* that no EEPROM is attached.
*/
/*
* Validate the EEPROM checksum. If the checksum fails, flag this for
* later, so we can fail future reads from the EEPROM.
*/
if (wm_validate_eeprom_checksum(sc)) {
/* Check whether EEPROM is present or not */
if ((CSR_READ(sc, WMREG_EECD) & EECD_EE_PRES) == 0) {
/* Not found */
sc->sc_flags |= WM_F_EEPROM_INVALID;
} else {
/*
* Read twice again because some PCI-e parts fail the first
* check due to the link being in sleep state.
* Validate the EEPROM checksum. If the checksum fails, flag
* this for later, so we can fail future reads from the EEPROM.
*/
if (wm_validate_eeprom_checksum(sc))
sc->sc_flags |= WM_F_EEPROM_INVALID;
if (wm_validate_eeprom_checksum(sc)) {
/*
* Read twice again because some PCI-e parts fail the
* first check due to the link being in sleep state.
*/
if (wm_validate_eeprom_checksum(sc))
sc->sc_flags |= WM_F_EEPROM_INVALID;
}
}
/* Set device properties (macflags)*/
prop_dictionary_set_uint32(dict, "macflags", sc->sc_flags);
if (sc->sc_flags & WM_F_EEPROM_INVALID)
aprint_verbose_dev(sc->sc_dev, "No EEPROM\n");

@ -1,4 +1,4 @@
/* $NetBSD: if_wmvar.h,v 1.3 2009/12/16 04:50:36 msaitoh Exp $ */
/* $NetBSD: if_wmvar.h,v 1.4 2009/12/16 14:37:26 msaitoh Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@ -71,6 +71,22 @@
#ifndef _DEV_PCI_IF_WMVAR_H_
#define _DEV_PCI_IF_WMVAR_H_
/* sc_flags */
#define WM_F_HAS_MII 0x0001 /* has MII */
#define WM_F_EEPROM_HANDSHAKE 0x0002 /* requires EEPROM handshake */
#define WM_F_EEPROM_SEMAPHORE 0x0004 /* EEPROM with semaphore */
#define WM_F_EEPROM_EERDEEWR 0x0008 /* EEPROM access via EERD/EEWR */
#define WM_F_EEPROM_SPI 0x0010 /* EEPROM is SPI */
#define WM_F_EEPROM_FLASH 0x0020 /* EEPROM is FLASH */
#define WM_F_EEPROM_INVALID 0x0040 /* EEPROM not present (bad checksum) */
#define WM_F_IOH_VALID 0x0080 /* I/O handle is valid */
#define WM_F_BUS64 0x0100 /* bus is 64-bit */
#define WM_F_PCIX 0x0200 /* bus is PCI-X */
#define WM_F_CSA 0x0400 /* bus is CSA */
#define WM_F_PCIE 0x0800 /* bus is PCI-Express */
#define WM_F_SWFW_SYNC 0x1000 /* Software-Firmware synchronisation */
#define WM_F_SWFWHW_SYNC 0x2000 /* Software-Firmware synchronisation */
typedef enum {
WM_T_unknown = 0,
WM_T_82542_2_0, /* i82542 2.0 (really old) */