/*-
* Copyright (c) 1999, 2000 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.
*
* 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.
*/
/*
* CardBus 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 */
/*
* Get revision info, and set some chip-specific variables.
*/
sc->sc_rev = PCI_REVISION(ca->ca_class);
switch (sc->sc_chip) {
case TULIP_CHIP_21142:
if (sc->sc_rev >= 0x20)
sc->sc_chip = TULIP_CHIP_21143;
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 = Cardbus_conf_read(ct, csc->sc_tag, 0x80);
switch (reg) {
case 0x09811317:
sc->sc_chip = TULIP_CHIP_AN985;
break;
case 0x09851317:
sc->sc_chip = TULIP_CHIP_AN983;
break;
}
break;
default:
/* Nothing. -- to make gcc happy */
break;
}
/*
* Bring the chip out of powersave mode and initialize the
* configuration registers.
*/
tlp_cardbus_setup(csc);
/*
* Read the contents of the Ethernet Address ROM/SROM.
*/
switch (sc->sc_chip) {
case TULIP_CHIP_X3201_3:
/*
* No SROM on this chip.
*/
break;
default:
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_21142:
case TULIP_CHIP_21143:
/* Check for new format SROM. */
if (tlp_isv_srom_enaddr(sc, enaddr) != 0) {
/*
* 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;
} else if (tlp_parse_old_srom(sc, enaddr) == 0) {
/*
* Not an ISV SROM, and not in old DEC Address
* ROM format. Try to snarf it out of the CIS.
*/
if (ca->ca_cis.funce.network.netid_present == 0)
goto cant_cope;
/* Grab the MAC address from the CIS. */
memcpy(enaddr, ca->ca_cis.funce.network.netid,
sizeof(enaddr));
}
/*
* Deal with any quirks this board might have.
*/
tlp_cardbus_get_quirks(csc, enaddr, tlp_cardbus_21142_quirks);
/*
* If we don't already have a media switch, default to
* MII-over-SIO, with no special reset routine.
*/
if (sc->sc_mediasw == NULL) {
aprint_normal("%s: defaulting to MII-over-SIO; "
"no bets...\n", device_xname(self));
sc->sc_mediasw = &tlp_sio_mii_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 access 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_X3201_3:
/*
* The X3201 doesn't have an SROM. Lift the MAC address
* from the CIS. Also, we have a special media switch:
* MII-on-SIO, plus some special GPIO setup.
*/
memcpy(enaddr, ca->ca_cis.funce.network.netid, sizeof(enaddr));
sc->sc_reset = tlp_cardbus_x3201_reset;
sc->sc_mediasw = &tlp_sio_mii_mediasw;
break;
default:
cant_cope:
aprint_error_dev(self, "sorry, unable to handle your board\n");
return;
}
/*
* Finish off the attach.
*/
tlp_attach(sc, enaddr);
/*
* Power down the socket.
*/
Cardbus_function_disable(csc->sc_ct);
}
int
tlp_cardbus_detach(device_t self, int flags)
{
struct tulip_cardbus_softc *csc = device_private(self);
struct tulip_softc *sc = &csc->sc_tulip;
struct cardbus_devfunc *ct = csc->sc_ct;
int rv;
#if defined(DIAGNOSTIC)
if (ct == NULL)
panic("%s: data structure lacks", device_xname(self));
#endif
rv = tlp_detach(sc);
if (rv)
return (rv);
/*
* Unhook the interrupt handler.
*/
if (csc->sc_ih != NULL)
Cardbus_intr_disestablish(ct, csc->sc_ih);
/*
* Release bus space and close window.
*/
if (csc->sc_bar_reg != 0)
Cardbus_mapreg_unmap(ct, csc->sc_bar_reg,
sc->sc_st, sc->sc_sh, csc->sc_mapsize);
/*
* Check to see if the device is in power-save mode, and
* bring it out if necessary.
*/
switch (sc->sc_chip) {
case TULIP_CHIP_21142:
case TULIP_CHIP_21143:
case TULIP_CHIP_X3201_3:
/*
* Clear the "sleep mode" bit in the CFDA register.
*/
reg = Cardbus_conf_read(ct, csc->sc_tag, TULIP_PCI_CFDA);
if (reg & (CFDA_SLEEP|CFDA_SNOOZE))
Cardbus_conf_write(ct, csc->sc_tag, TULIP_PCI_CFDA,
reg & ~(CFDA_SLEEP|CFDA_SNOOZE));
break;
default:
/* Nothing. -- to make gcc happy */
break;
}