/*-
* Copyright (c) 1998, 1999, 2000, 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center; and Charles M. Hannum.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* PCI bus front-end for the Digital Semiconductor ``Tulip'' (21x4x)
* Ethernet controller family driver.
*/
/*
* PCI configuration space registers used by the Tulip.
*/
#define TULIP_PCI_IOBA PCI_BAR(0) /* i/o mapped base */
#define TULIP_PCI_MMBA PCI_BAR(1) /* memory mapped base */
#define TULIP_PCI_CFDA 0x40 /* configuration driver area */
/*
* Note: This is like a MX98725 with Wake-On-LAN and a
* 128-bit multicast hash table.
*/
{ .id = PCI_ID_CODE(PCI_VENDOR_LITEON, PCI_PRODUCT_LITEON_82C115),
.value = TULIP_CHIP_82C115 },
static void
tlp_pci_check_slaved(struct tulip_pci_softc *psc, int shared, int slaved)
{
extern struct cfdriver tlp_cd;
struct tulip_pci_softc *cur, *best = NULL;
struct tulip_softc *sc = &psc->sc_tulip;
int i;
/*
* First of all, find the lowest pcidev numbered device on our
* bus marked as shared. That should be our master.
*/
for (i = 0; i < tlp_cd.cd_ndevs; i++) {
if ((cur = device_lookup_private(&tlp_cd, i)) == NULL)
continue;
if (device_parent(cur->sc_tulip.sc_dev) !=
device_parent(sc->sc_dev))
continue;
if ((cur->sc_flags & shared) == 0)
continue;
if (cur == psc)
continue;
if (best == NULL ||
best->sc_tulip.sc_devno > cur->sc_tulip.sc_devno)
best = cur;
}
/*
* By default, Tulip registers are 8 bytes long (4 bytes
* followed by a 4 byte pad).
*/
sc->sc_regshift = 3;
/*
* No power management hooks.
* XXX Maybe we should add some!
*/
sc->sc_flags |= TULIPF_ENABLED;
/*
* Get revision info, and set some chip-specific variables.
*/
sc->sc_rev = PCI_REVISION(pa->pa_class);
switch (sc->sc_chip) {
case TULIP_CHIP_21140:
if (sc->sc_rev >= 0x20)
sc->sc_chip = TULIP_CHIP_21140A;
break;
case TULIP_CHIP_21142:
if (sc->sc_rev >= 0x20)
sc->sc_chip = TULIP_CHIP_21143;
break;
case TULIP_CHIP_82C168:
if (sc->sc_rev >= 0x20)
sc->sc_chip = TULIP_CHIP_82C169;
break;
case TULIP_CHIP_MX98713:
if (sc->sc_rev >= 0x10)
sc->sc_chip = TULIP_CHIP_MX98713A;
break;
case TULIP_CHIP_MX98715:
if (sc->sc_rev >= 0x20)
sc->sc_chip = TULIP_CHIP_MX98715A;
if (sc->sc_rev >= 0x25)
sc->sc_chip = TULIP_CHIP_MX98715AEC_X;
if (sc->sc_rev >= 0x30)
sc->sc_chip = TULIP_CHIP_MX98725;
break;
case TULIP_CHIP_WB89C840F:
sc->sc_regshift = 2;
break;
case TULIP_CHIP_AN985:
/*
* The AN983 and AN985 are very similar, and are
* differentiated by a "signature" register that
* is like, but not identical, to a PCI ID register.
*/
reg = pci_conf_read(pc, pa->pa_tag, 0x80);
switch (reg) {
case 0x09811317:
sc->sc_chip = TULIP_CHIP_AN985;
break;
case 0x09851317:
sc->sc_chip = TULIP_CHIP_AN983;
break;
default:
/* Unknown -- use default. */
break;
}
break;
case TULIP_CHIP_AX88140:
if (sc->sc_rev >= 0x10)
sc->sc_chip = TULIP_CHIP_AX88141;
break;
case TULIP_CHIP_DM9102:
if (sc->sc_rev >= 0x30)
sc->sc_chip = TULIP_CHIP_DM9102A;
break;
switch (sc->sc_chip) {
case TULIP_CHIP_21040:
if (sc->sc_rev < 0x20) {
aprint_normal_dev(self,
"21040 must be at least pass 2.0\n");
return;
}
break;
case TULIP_CHIP_21140:
if (sc->sc_rev < 0x11) {
aprint_normal_dev(self,
"21140 must be at least pass 1.1\n");
return;
}
break;
default:
/* Nothing. */
break;
}
/*
* Check to see if the device is in power-save mode, and
* being it out if necessary.
*/
switch (sc->sc_chip) {
case TULIP_CHIP_21140:
case TULIP_CHIP_21140A:
case TULIP_CHIP_21142:
case TULIP_CHIP_21143:
case TULIP_CHIP_MX98713A:
case TULIP_CHIP_MX98715:
case TULIP_CHIP_MX98715A:
case TULIP_CHIP_MX98715AEC_X:
case TULIP_CHIP_MX98725:
case TULIP_CHIP_DM9102:
case TULIP_CHIP_DM9102A:
case TULIP_CHIP_AX88140:
case TULIP_CHIP_AX88141:
case TULIP_CHIP_RS7112:
/*
* Clear the "sleep mode" bit in the CFDA register.
*/
reg = pci_conf_read(pc, pa->pa_tag, TULIP_PCI_CFDA);
if (reg & (CFDA_SLEEP | CFDA_SNOOZE))
pci_conf_write(pc, pa->pa_tag, TULIP_PCI_CFDA,
reg & ~(CFDA_SLEEP | CFDA_SNOOZE));
break;
default:
/* Nothing. */
break;
}
/* power up chip */
if ((error = pci_activate(pa->pa_pc, pa->pa_tag, self,
NULL)) && error != EOPNOTSUPP) {
aprint_error_dev(self, "cannot activate %d\n", error);
return;
}
/*
* Make sure bus mastering is enabled.
*/
pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
PCI_COMMAND_MASTER_ENABLE);
/*
* Get the cacheline size.
*/
sc->sc_cacheline = PCI_CACHELINE(pci_conf_read(pc, pa->pa_tag,
PCI_BHLC_REG));
/*
* Get PCI data moving command info.
*/
if (pa->pa_flags & PCI_FLAGS_MRL_OKAY)
sc->sc_flags |= TULIPF_MRL;
if (pa->pa_flags & PCI_FLAGS_MRM_OKAY)
sc->sc_flags |= TULIPF_MRM;
if (pa->pa_flags & PCI_FLAGS_MWI_OKAY)
sc->sc_flags |= TULIPF_MWI;
/*
* Read the contents of the Ethernet Address ROM/SROM.
*/
switch (sc->sc_chip) {
case TULIP_CHIP_21040:
sc->sc_srom_addrbits = 6;
sc->sc_srom = kmem_alloc(TULIP_ROM_SIZE(6), KM_SLEEP);
TULIP_WRITE(sc, CSR_MIIROM, MIIROM_SROMCS);
for (i = 0; i < TULIP_ROM_SIZE(6); i++) {
for (j = 0; j < 10000; j++) {
val = TULIP_READ(sc, CSR_MIIROM);
if ((val & MIIROM_DN) == 0)
break;
}
sc->sc_srom[i] = val & MIIROM_DATA;
}
break;
case TULIP_CHIP_82C168:
case TULIP_CHIP_82C169:
{
sc->sc_srom_addrbits = 2;
sc->sc_srom = kmem_zalloc(TULIP_ROM_SIZE(2), KM_SLEEP);
/*
* The Lite-On PNIC stores the Ethernet address in
* the first 3 words of the EEPROM. EEPROM access
* is not like the other Tulip chips.
*/
for (i = 0; i < 6; i += 2) {
TULIP_WRITE(sc, CSR_PNIC_SROMCTL,
PNIC_SROMCTL_READ | (i >> 1));
for (j = 0; j < 500; j++) {
delay(2);
val = TULIP_READ(sc, CSR_MIIROM);
if ((val & PNIC_MIIROM_BUSY) == 0)
break;
}
if (val & PNIC_MIIROM_BUSY) {
aprint_error_dev(self, "EEPROM timed out\n");
goto fail;
}
val &= PNIC_MIIROM_DATA;
sc->sc_srom[i] = val >> 8;
sc->sc_srom[i + 1] = val & 0xff;
}
break;
}
default:
/*
* XXX This isn't quite the right way to do this; we should
* XXX be attempting to fetch the mac-addr property in the
* XXX bus-agnostic part of the driver independently. But
* XXX that requires a larger change in the SROM handling
* XXX logic, and for now we can at least remove a machine-
* XXX dependent wart from the PCI front-end.
*/
ea = prop_dictionary_get(device_properties(self),
"mac-address");
if (ea != NULL) {
extern int tlp_srom_debug;
KASSERT(prop_object_type(ea) == PROP_TYPE_DATA);
KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN);
sc->sc_srom_addrbits = 6;
sc->sc_srom = kmem_zalloc(TULIP_ROM_SIZE(6), KM_SLEEP);
memcpy(sc->sc_srom, enaddr, sizeof(enaddr));
if (tlp_srom_debug) {
aprint_normal("SROM CONTENTS:");
for (i = 0; i < TULIP_ROM_SIZE(6); i++) {
if ((i % 8) == 0)
aprint_normal("\n\t");
aprint_normal("0x%02x ",
sc->sc_srom[i]);
}
aprint_normal("\n");
}
break;
}
/* Check for a slaved ROM on a multi-port board. */
tlp_pci_check_slaved(psc, TULIP_PCI_SHAREDROM,
TULIP_PCI_SLAVEROM);
if (psc->sc_flags & TULIP_PCI_SLAVEROM) {
sc->sc_srom_addrbits =
psc->sc_master->sc_tulip.sc_srom_addrbits;
sc->sc_srom = psc->sc_master->sc_tulip.sc_srom;
enaddr[5] +=
sc->sc_devno - psc->sc_master->sc_tulip.sc_devno;
}
else if (tlp_read_srom(sc) == 0)
goto cant_cope;
break;
}
/*
* Deal with chip/board quirks. This includes setting up
* the mediasw, and extracting the Ethernet address from
* the rombuf.
*/
switch (sc->sc_chip) {
case TULIP_CHIP_21040:
/*
* Parse the Ethernet Address ROM.
*/
if (tlp_parse_old_srom(sc, enaddr) == 0)
goto cant_cope;
/*
* All 21040 boards start out with the same
* media switch.
*/
sc->sc_mediasw = &tlp_21040_mediasw;
/*
* Deal with any quirks this board might have.
*/
tlp_pci_get_quirks(psc, enaddr, tlp_pci_21040_quirks);
break;
case TULIP_CHIP_21041:
/* Check for new format SROM. */
if (tlp_isv_srom_enaddr(sc, enaddr) == 0) {
/*
* Not an ISV SROM; try the old DEC Ethernet Address
* ROM format.
*/
if (tlp_parse_old_srom(sc, enaddr) == 0)
goto cant_cope;
}
/*
* All 21041 boards use the same media switch; they all
* work basically the same! Yippee!
*/
sc->sc_mediasw = &tlp_21041_mediasw;
/*
* Deal with any quirks this board might have.
*/
tlp_pci_get_quirks(psc, enaddr, tlp_pci_21041_quirks);
break;
case TULIP_CHIP_21140:
case TULIP_CHIP_21140A:
/* Check for new format SROM. */
if (tlp_isv_srom_enaddr(sc, enaddr) == 0) {
/*
* Not an ISV SROM; try the old DEC Ethernet Address
* ROM format.
*/
if (tlp_parse_old_srom(sc, enaddr) == 0)
goto cant_cope;
} else {
/*
* We start out with the 2114x ISV media switch.
* When we search for quirks, we may change to
* a different switch.
*/
sc->sc_mediasw = &tlp_2114x_isv_mediasw;
}
/*
* Deal with any quirks this board might have.
*/
tlp_pci_get_quirks(psc, enaddr, tlp_pci_21140_quirks);
/*
* Bail out now if we can't deal with this board.
*/
if (sc->sc_mediasw == NULL)
goto cant_cope;
break;
case TULIP_CHIP_21142:
case TULIP_CHIP_21143:
/* Check for new format SROM. */
if (tlp_isv_srom_enaddr(sc, enaddr) == 0) {
/*
* Not an ISV SROM; try the old DEC Ethernet Address
* ROM format.
*/
if (tlp_parse_old_srom(sc, enaddr) == 0) {
/*
* One last try: just copy the address
* from offset 20 and try to look
* up quirks.
*/
memcpy(enaddr, &sc->sc_srom[20],
ETHER_ADDR_LEN);
}
} else {
/*
* We start out with the 2114x ISV media switch.
* When we search for quirks, we may change to
* a different switch.
*/
sc->sc_mediasw = &tlp_2114x_isv_mediasw;
}
/*
* Deal with any quirks this board might have.
*/
tlp_pci_get_quirks(psc, enaddr, tlp_pci_21142_quirks);
/*
* Bail out now if we can't deal with this board.
*/
if (sc->sc_mediasw == NULL)
goto cant_cope;
break;
case TULIP_CHIP_82C168:
case TULIP_CHIP_82C169:
/*
* Lite-On PNIC's Ethernet address is the first 6
* bytes of its EEPROM.
*/
memcpy(enaddr, sc->sc_srom, ETHER_ADDR_LEN);
/*
* Lite-On PNICs always use the same mediasw; we
* select MII vs. internal NWAY automatically.
*/
sc->sc_mediasw = &tlp_pnic_mediasw;
break;
case TULIP_CHIP_MX98713:
/*
* The Macronix MX98713 has an MII and GPIO, but no
* internal Nway block. This chip is basically a
* perfect 21140A clone, with the exception of the
* a magic register frobbing in order to make the
* interface function.
*/
if (tlp_isv_srom_enaddr(sc, enaddr)) {
sc->sc_mediasw = &tlp_2114x_isv_mediasw;
break;
}
/* FALLTHROUGH */
case TULIP_CHIP_82C115:
/*
* Yippee! The Lite-On 82C115 is a clone of
* the MX98725 (the data sheet even says `MXIC'
* on it)! Imagine that, a clone of a clone.
*
* The differences are really minimal:
*
* - Wake-On-LAN support
* - 128-bit multicast hash table, rather than
* the standard 512-bit hash table
*/
/* FALLTHROUGH */
case TULIP_CHIP_MX98713A:
case TULIP_CHIP_MX98715A:
case TULIP_CHIP_MX98715AEC_X:
case TULIP_CHIP_MX98725:
/*
* The MX98713A has an MII as well as an internal Nway block,
* but no GPIO. The MX98715 and MX98725 have an internal
* Nway block only.
*
* The internal Nway block, unlike the Lite-On PNIC's, does
* just that - performs Nway. Once autonegotiation completes,
* we must program the GPR media information into the chip.
*
* The byte offset of the Ethernet address is stored at
* offset 0x70.
*/
memcpy(enaddr, &sc->sc_srom[sc->sc_srom[0x70]], ETHER_ADDR_LEN);
sc->sc_mediasw = &tlp_pmac_mediasw;
break;
case TULIP_CHIP_WB89C840F:
/*
* Winbond 89C840F's Ethernet address is the first
* 6 bytes of its EEPROM.
*/
memcpy(enaddr, sc->sc_srom, ETHER_ADDR_LEN);
/*
* Winbond 89C840F has an MII attached to the SIO.
*/
sc->sc_mediasw = &tlp_sio_mii_mediasw;
break;
case TULIP_CHIP_AL981:
/*
* The ADMtek AL981's Ethernet address is located
* at offset 8 of its EEPROM.
*/
memcpy(enaddr, &sc->sc_srom[8], ETHER_ADDR_LEN);
/*
* ADMtek AL981 has a built-in PHY accessed through
* special registers.
*/
sc->sc_mediasw = &tlp_al981_mediasw;
break;
case TULIP_CHIP_AN983:
case TULIP_CHIP_AN985:
/*
* The ADMtek AN985's Ethernet address is located
* at offset 8 of its EEPROM.
*/
memcpy(enaddr, &sc->sc_srom[8], ETHER_ADDR_LEN);
/*
* The ADMtek AN985 can be configured in Single-Chip
* mode or MAC-only mode. Single-Chip uses the built-in
* PHY, MAC-only has an external PHY (usually HomePNA).
* The selection is based on an EEPROM setting, and both
* PHYs are accessed via MII attached to SIO.
*
* The AN985 "ghosts" the internal PHY onto all
* MII addresses, so we have to use a media init
* routine that limits the search.
* XXX How does this work with MAC-only mode?
*/
sc->sc_mediasw = &tlp_an985_mediasw;
break;
case TULIP_CHIP_DM9102:
case TULIP_CHIP_DM9102A:
/*
* Some boards with the Davicom chip have an ISV
* SROM (mostly DM9102A boards -- trying to describe
* the HomePNA PHY, probably) although the data in
* them is generally wrong. Check for ISV format
* and grab the Ethernet address that way, and if
* that fails, fall back on grabbing it from an
* observed offset of 20 (which is where it would
* be in an ISV SROM anyhow, tho ISV can cope with
* multi-port boards).
*/
if (!tlp_isv_srom_enaddr(sc, enaddr)) {
/*
* Davicom chips all have an internal MII interface
* and a built-in PHY. DM9102A also has a an external
* MII interface, usually with a HomePNA PHY attached
* to it.
*/
sc->sc_mediasw = &tlp_dm9102_mediasw;
break;
case TULIP_CHIP_AX88140:
case TULIP_CHIP_AX88141:
/*
* ASIX AX88140/AX88141 Ethernet Address is located at offset
* 20 of the SROM.
*/
memcpy(enaddr, &sc->sc_srom[20], ETHER_ADDR_LEN);
/*
* ASIX AX88140A/AX88141 chip can have a built-in PHY or
* an external MII interface.
*/
sc->sc_mediasw = &tlp_asix_mediasw;
break;
case TULIP_CHIP_RS7112:
/*
* RS7112 Ethernet Address is located of offset 0x19a
* of the SROM
*/
memcpy(enaddr, &sc->sc_srom[0x19a], ETHER_ADDR_LEN);
/* RS7112 chip has a PHY at MII address 1 */
sc->sc_mediasw = &tlp_rs7112_mediasw;
break;
default:
cant_cope:
aprint_error_dev(self, "sorry, unable to handle your board\n");
goto fail;
}
/*
* This isn't really a quirk-gathering device, really. We
* just want to get the spiffy DEC board name from the SROM.
*/
strcpy(sc->sc_name, "DEC ");
/*
* If we have a slaved ROM, just copy the bits from the master.
* This is in case we fail the ROM ID check (older boards) and
* need to fall back on Ethernet address model checking; that
* will fail for slave chips.
*/
if (psc->sc_flags & TULIP_PCI_SLAVEROM) {
strcpy(sc->sc_name, psc->sc_master->sc_tulip.sc_name);
sc->sc_mediasw = psc->sc_master->sc_tulip.sc_mediasw;
psc->sc_flags |=
psc->sc_master->sc_flags & TULIP_PCI_SHAREDINTR;
return;
}
if (sc->sc_srom[32] == 0x4a && sc->sc_srom[33] == 0x52) {
id = sc->sc_srom[37] | (sc->sc_srom[36] << 8);
switch (id) {
zx312:
case 0x0602: /* ZX312 */
strcpy(sc->sc_name, "ZNYX ZX312");
return;
/*
* Some Asante boards don't use the ISV SROM format. For
* those that don't, we initialize the GPIO direction bits,
* and provide our own reset hook, which resets the MII.
*
* All of these boards use SIO-attached-MII media.
*/
if (sc->sc_mediasw == &tlp_2114x_isv_mediasw)
return;
/*
* Phobos boards just use MII-on-SIO.
*/
sc->sc_mediasw = &tlp_sio_mii_mediasw;
sc->sc_reset = tlp_pci_phobos_21140_reset;
/*
* These boards appear solely on sgimips machines behind a special
* GIO<->PCI ASIC and require the DBO and BLE bits to be set in CSR0.
*/
sc->sc_flags |= (TULIPF_BLE | TULIPF_DBO);
}
/*
* Cobalt Networks interfaces are just MII-on-SIO.
*/
sc->sc_reset = tlp_pci_cobalt_21142_reset;
sc->sc_mediasw = &tlp_sio_mii_mediasw;
/*
* The Cobalt systems tend to fall back to store-and-forward
* pretty quickly, so we select that from the beginning to
* avoid initial timeouts.
*/
sc->sc_txthresh = TXTH_SF;
}
/*
* Algorithmics boards just have MII-on-SIO.
*
* XXX They also have AUI on the serial interface.
* XXX Deal with this.
*/
sc->sc_mediasw = &tlp_sio_mii_mediasw;
}
/*
* Phobos boards just use MII-on-SIO.
*/
sc->sc_mediasw = &tlp_sio_mii_mediasw;
sc->sc_reset = tlp_pci_phobos_21142_reset;
/*
* These boards appear solely on sgimips machines behind a special
* GIO<->PCI ASIC and require the DBO and BLE bits to be set in CSR0.
*/
sc->sc_flags |= (TULIPF_BLE | TULIPF_DBO);
}