#include <libkern/OSByteOrder.h>
#include <libkern/OSAtomic.h>
#include <IOKit/IOLib.h>
#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);
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);
bfe_pci_setup(sc, BFE_INTVEC_ENET0);
val = CSR_READ_4(sc, BFE_SBTMSLOW) & (BFE_RESET | BFE_REJECT | BFE_CLOCK);
if (val == BFE_CLOCK) {
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);
CSR_WRITE_4(sc, BFE_MDIO_CTRL, 0x8d);
val = CSR_READ_4(sc, BFE_DEVCTRL);
if(!(val & BFE_IPP)) {
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) {
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));
BFE_OR(sc, BFE_RCV_LAZY, 0);
#endif
CSR_WRITE_4(sc, BFE_RXMAXLEN, BFE_BUFFER_SIZE);
CSR_WRITE_4(sc, BFE_TXMAXLEN, BFE_BUFFER_SIZE);
CSR_WRITE_4(sc, BFE_TX_WMARK, 56);
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;
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);
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;
bfe_core_disable(sc);
CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_RESET | BFE_CLOCK | BFE_FGC));
CSR_READ_4(sc, BFE_SBTMSLOW);
DELAY(10);
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));
CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_CLOCK | BFE_FGC));
CSR_READ_4(sc, BFE_SBTMSLOW);
DELAY(10);
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;
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);
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;
}
__private_extern__ int
bfe_setupphy( struct bfe_softc * sc )
{
u_int32_t val;
BFE_LOCK(sc);
bfe_readphy(sc, 26, &val);
bfe_writephy(sc, 26, val & 0x7fff);
bfe_readphy(sc, 26, &val);
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 )
{
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);
}