/* * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Copyright (c) 2003 Stuart Walsh * and Duncan Barclay */ /* * 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 AUTHOR 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 AUTHOR 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. */ #include #include #include #include "if_bfereg.h" #define DEBUG_LOG(fmt, args...) IOLog(fmt, ## args) #ifndef DELAY(x) #define DELAY(x) IODelay(x) #endif static void bfe_pci_setup( struct bfe_softc * sc, u_int32_t cores ); static void bfe_clear_stats( struct bfe_softc * sc ); static void bfe_core_disable( struct bfe_softc * sc ); static void bfe_core_reset( struct bfe_softc * sc ); static int bfe_wait_bit( struct bfe_softc * sc, u_int32_t reg, u_int32_t bit, u_long timeout, const int clear ); static void bfe_pci_setup( struct bfe_softc * sc, u_int32_t cores ) { u_int32_t bar_orig, pci_rev, val; bar_orig = pci_read_config(sc->bfe_dev, BFE_BAR0_WIN, 4); pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, BFE_REG_PCI, 4); pci_rev = CSR_READ_4(sc, BFE_SBIDHIGH) & BFE_RC_MASK; val = CSR_READ_4(sc, BFE_SBINTVEC); val |= cores; CSR_WRITE_4(sc, BFE_SBINTVEC, val); val = CSR_READ_4(sc, BFE_SSB_PCI_TRANS_2); val |= BFE_SSB_PCI_PREF | BFE_SSB_PCI_BURST; CSR_WRITE_4(sc, BFE_SSB_PCI_TRANS_2, val); pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, bar_orig, 4); } static void bfe_clear_stats( struct bfe_softc * sc ) { u_long reg; BFE_LOCK(sc); CSR_WRITE_4(sc, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ); for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4) CSR_READ_4(sc, reg); for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4) CSR_READ_4(sc, reg); BFE_UNLOCK(sc); } __private_extern__ void bfe_chip_halt( struct bfe_softc * sc ) { BFE_LOCK(sc); /* disable interrupts - not that it actually does..*/ CSR_WRITE_4(sc, BFE_IMASK, 0); CSR_READ_4(sc, BFE_IMASK); CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE); bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 200, 1); CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0); CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0); DELAY(10); BFE_UNLOCK(sc); } __private_extern__ void bfe_chip_reset( struct bfe_softc * sc ) { u_int32_t val; BFE_LOCK(sc); /* Set the interrupt vector for the enet core */ bfe_pci_setup(sc, BFE_INTVEC_ENET0); /* is core up? */ val = CSR_READ_4(sc, BFE_SBTMSLOW) & (BFE_RESET | BFE_REJECT | BFE_CLOCK); if (val == BFE_CLOCK) { /* It is, so shut it down */ CSR_WRITE_4(sc, BFE_RCV_LAZY, 0); CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE); bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 100, 1); CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0); #ifndef __APPLE__ sc->bfe_tx_cnt = sc->bfe_tx_prod = sc->bfe_tx_cons = 0; #endif if (CSR_READ_4(sc, BFE_DMARX_STAT) & BFE_STAT_EMASK) bfe_wait_bit(sc, BFE_DMARX_STAT, BFE_STAT_SIDLE, 100, 0); CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0); #ifndef __APPLE__ sc->bfe_rx_prod = sc->bfe_rx_cons = 0; #endif } bfe_core_reset(sc); bfe_clear_stats(sc); /* * We want the phy registers to be accessible even when * the driver is "downed" so initialize MDC preamble, frequency, * and whether internal or external phy here. */ /* 4402 has 62.5Mhz SB clock and internal phy */ CSR_WRITE_4(sc, BFE_MDIO_CTRL, 0x8d); /* Internal or external PHY? */ val = CSR_READ_4(sc, BFE_DEVCTRL); if(!(val & BFE_IPP)) { /* external PHY */ CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_EPSEL); CSR_READ_4(sc, BFE_ENET_CTRL); } else if(CSR_READ_4(sc, BFE_DEVCTRL) & BFE_EPR) { /* internal PHY */ BFE_AND(sc, BFE_DEVCTRL, ~BFE_EPR); CSR_READ_4(sc, BFE_DEVCTRL); DELAY(100); } BFE_OR(sc, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB | BFE_CTRL_LED); #ifdef __APPLE__ CSR_WRITE_4(sc, BFE_RCV_LAZY, (3 << BFE_LAZY_FC_SHIFT) | 0x3000); #else CSR_WRITE_4(sc, BFE_RCV_LAZY, ((1 << BFE_LAZY_FC_SHIFT) & BFE_LAZY_FC_MASK)); /* * We don't want lazy interrupts, so just send them at the end of a frame, * please */ BFE_OR(sc, BFE_RCV_LAZY, 0); #endif /* Set max lengths, accounting for VLAN tags */ CSR_WRITE_4(sc, BFE_RXMAXLEN, BFE_BUFFER_SIZE); CSR_WRITE_4(sc, BFE_TXMAXLEN, BFE_BUFFER_SIZE); /* Set watermark XXX - magic */ CSR_WRITE_4(sc, BFE_TX_WMARK, 56); /* * Initialise DMA channels - not forgetting dma addresses need to be added * to BFE_PCI_DMA */ CSR_WRITE_4(sc, BFE_DMATX_CTRL, BFE_TX_CTRL_ENABLE); CSR_WRITE_4(sc, BFE_DMATX_ADDR, sc->bfe_tx_dma + BFE_PCI_DMA); CSR_WRITE_4(sc, BFE_DMARX_CTRL, (BFE_RX_OFFSET << BFE_RX_CTRL_ROSHIFT) | BFE_RX_CTRL_ENABLE); CSR_WRITE_4(sc, BFE_DMARX_ADDR, sc->bfe_rx_dma + BFE_PCI_DMA); CSR_WRITE_4(sc, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ); #ifndef __APPLE__ bfe_resetphy(sc); bfe_setupphy(sc); #endif BFE_UNLOCK(sc); } static void bfe_core_disable( struct bfe_softc * sc ) { if((CSR_READ_4(sc, BFE_SBTMSLOW)) & BFE_RESET) return; /* * Set reject, wait for it set, then wait for the core to stop being busy * Then set reset and reject and enable the clocks */ CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_CLOCK)); bfe_wait_bit(sc, BFE_SBTMSLOW, BFE_REJECT, 100000, 0); bfe_wait_bit(sc, BFE_SBTMSHIGH, BFE_BUSY, 100000, 1); CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_FGC | BFE_CLOCK | BFE_REJECT | BFE_RESET)); CSR_READ_4(sc, BFE_SBTMSLOW); DELAY(10); /* Leave reset and reject set */ CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_RESET)); CSR_READ_4(sc, BFE_SBTMSLOW); DELAY(10); } static void bfe_core_reset( struct bfe_softc * sc ) { u_int32_t val; /* Disable the core */ bfe_core_disable(sc); /* and bring it back up */ CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_RESET | BFE_CLOCK | BFE_FGC)); CSR_READ_4(sc, BFE_SBTMSLOW); DELAY(10); /* Chip bug, clear SERR, IB and TO if they are set. */ if (CSR_READ_4(sc, BFE_SBTMSHIGH) & BFE_SERR) CSR_WRITE_4(sc, BFE_SBTMSHIGH, 0); val = CSR_READ_4(sc, BFE_SBIMSTATE); if (val & (BFE_IBE | BFE_TO)) CSR_WRITE_4(sc, BFE_SBIMSTATE, val & ~(BFE_IBE | BFE_TO)); /* Clear reset and allow it to move through the core */ CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_CLOCK | BFE_FGC)); CSR_READ_4(sc, BFE_SBTMSLOW); DELAY(10); /* Leave the clock set */ CSR_WRITE_4(sc, BFE_SBTMSLOW, BFE_CLOCK); CSR_READ_4(sc, BFE_SBTMSLOW); DELAY(10); } __private_extern__ void bfe_cam_write( struct bfe_softc * sc, u_char * data, int index ) { u_int32_t val; val = ((u_int32_t) data[2]) << 24; val |= ((u_int32_t) data[3]) << 16; val |= ((u_int32_t) data[4]) << 8; val |= ((u_int32_t) data[5]); CSR_WRITE_4(sc, BFE_CAM_DATA_LO, val); val = (BFE_CAM_HI_VALID | (((u_int32_t) data[0]) << 8) | (((u_int32_t) data[1]))); CSR_WRITE_4(sc, BFE_CAM_DATA_HI, val); CSR_WRITE_4(sc, BFE_CAM_CTRL, (BFE_CAM_WRITE | (index << BFE_CAM_INDEX_SHIFT))); bfe_wait_bit(sc, BFE_CAM_CTRL, BFE_CAM_BUSY, 10000, 1); } static int bfe_wait_bit( struct bfe_softc * sc, u_int32_t reg, u_int32_t bit, u_long timeout, const int clear ) { u_long i; int use_sleep = 0; /* jliu@Apple: long timeouts polls are done using a blocking wait */ if (timeout >= 10000) { use_sleep = 1; timeout /= 1000; } for (i = 0; i < timeout; i++) { u_int32_t val = CSR_READ_4(sc, reg); if (clear && !(val & bit)) break; if (!clear && (val & bit)) break; if (use_sleep) IOSleep(10); else DELAY(10); } if (i == timeout) { DEBUG_LOG("bfe%d: BUG! Timeout waiting for bit %08x of register " "%x to %s.\n", sc->bfe_unit, bit, reg, (clear ? "clear" : "set")); return -1; } return 0; } __private_extern__ int bfe_readphy( struct bfe_softc * sc, u_int32_t reg, u_int32_t * val ) { int err; BFE_LOCK(sc); /* Clear MII ISR */ CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII); CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START | (BFE_MDIO_OP_READ << BFE_MDIO_OP_SHIFT) | (sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) | (reg << BFE_MDIO_RA_SHIFT) | (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT))); err = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0); *val = CSR_READ_4(sc, BFE_MDIO_DATA) & BFE_MDIO_DATA_DATA; BFE_UNLOCK(sc); return err; } __private_extern__ int bfe_writephy( struct bfe_softc * sc, u_int32_t reg, u_int32_t val ) { int status; BFE_LOCK(sc); CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII); CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START | (BFE_MDIO_OP_WRITE << BFE_MDIO_OP_SHIFT) | (sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) | (reg << BFE_MDIO_RA_SHIFT) | (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT) | (val & BFE_MDIO_DATA_DATA))); status = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0); BFE_UNLOCK(sc); return status; } /* * XXX - I think this is handled by the PHY driver, but it can't hurt to do it * twice */ __private_extern__ int bfe_setupphy( struct bfe_softc * sc ) { u_int32_t val; BFE_LOCK(sc); /* Enable activity LED */ bfe_readphy(sc, 26, &val); bfe_writephy(sc, 26, val & 0x7fff); bfe_readphy(sc, 26, &val); /* Enable traffic meter LED mode */ bfe_readphy(sc, 27, &val); bfe_writephy(sc, 27, val | (1 << 6)); BFE_UNLOCK(sc); return 0; } __private_extern__ void bfe_chip_enable( struct bfe_softc * sc ) { /* Enable the chip and core */ BFE_OR(sc, BFE_ENET_CTRL, BFE_ENET_ENABLE); } __private_extern__ void bfe_enable_interrupts( struct bfe_softc * sc ) { CSR_WRITE_4(sc, BFE_IMASK, BFE_IMASK_DEF); } __private_extern__ void bfe_disable_interrupts( struct bfe_softc * sc ) { CSR_WRITE_4(sc, BFE_IMASK, 0); CSR_READ_4(sc, BFE_IMASK); }