if_upd985xx.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,622 行 · 第 1/4 页

C
1,622
字号

    cyg_drv_interrupt_unmask(p_eth_upd985xx->vector);
}

// ------------------------------------------------------------------------
// Device table entry to operate the chip in a polled mode.
// Only diddle the interface we were asked to!

STATIC void
eth_upd985xx_poll(struct eth_drv_sc *sc)
{
    struct eth_upd985xx *p_eth_upd985xx;

    p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;

    // As it happens, this driver always requests the DSR to be called:
    (void)eth_isr( p_eth_upd985xx->vector, (cyg_addrword_t)sc );
    eth_upd985xx_deliver( sc );
}

// ------------------------------------------------------------------------
// Determine interrupt vector used by a device - for attaching GDB stubs
// packet handler.
STATIC int
eth_upd985xx_int_vector(struct eth_drv_sc *sc)
{
    struct eth_upd985xx *p_eth_upd985xx;
    p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
    return (p_eth_upd985xx->vector);
}

// ------------------------------------------------------------------------

STATIC int
eth_set_mac_address( struct eth_upd985xx *p_eth_upd985xx, void *data )
{
    cyg_uint8 *p = (cyg_uint8 *)data;
    cyg_uint8 *mac_address;

    mac_address = &p_eth_upd985xx->mac_address[0];

    mac_address[5] = p[5];
    mac_address[4] = p[4];
    mac_address[3] = p[3];
    mac_address[2] = p[2];
    mac_address[1] = p[1];
    mac_address[0] = p[0];

    p_eth_upd985xx->mac_addr_ok = 1;

    // Set the ESA in the device regs
    OUTL( ETH_LSA2,
          (p_eth_upd985xx->mac_address[1]) |
          (p_eth_upd985xx->mac_address[0] << 8 ) );
    OUTL( ETH_LSA1,
          (p_eth_upd985xx->mac_address[5]) |
          (p_eth_upd985xx->mac_address[4] << 8 ) |
          (p_eth_upd985xx->mac_address[3] << 16 ) |
          (p_eth_upd985xx->mac_address[2] << 24) );

    return 0; // OK
}

// ------------------------------------------------------------------------

STATIC void
eth_upd985xx_reset( struct eth_upd985xx *p_eth_upd985xx )
{
    int i;

    // Reset whole device: Software Reset (clears automatically)
    OUTL( ETH_CCR, ETH_CCR_SRT );
    for ( i = 0; i < 10000; i++ ) /* nothing */;
    // Reset internal units
    OUTL( ETH_MACC2, ETH_MACC2_MCRST | ETH_MACC2_RFRST | ETH_MACC2_TFRST );
    for ( i = 0; i < 10000; i++ ) /* nothing */;
    FLUSH_WRITES();
    OUTL( ETH_MACC2, 0 ); // (and release reset)
    // Enable CRC adding, padding
    FLUSH_WRITES();
    OUTL( ETH_MACC1,
          ETH_MACC1_CRCEN | ETH_MACC1_PADEN |
          ETH_MACC1_TXFC | ETH_MACC1_RXFC | ETH_MACC1_PARF );
    FLUSH_WRITES();
    OUTL( ETH_MACC2, ETH_MACC2_APD ); // Auto VLAN pad
    FLUSH_WRITES();
    OUTL( ETH_HT1, 0 );
    FLUSH_WRITES();
    OUTL( ETH_HT2, 0 );

    // Enable rx of broadcasts, multicasts, but not promiscuous...
    FLUSH_WRITES();
#if defined( CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2 ) && \
    !defined( CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2_E2ONLY )
    // Unless we are faking it.
    OUTL( ETH_AFR, ETH_AFR_ABC | ETH_AFR_PRM | ETH_AFR_PRO );
#else
    OUTL( ETH_AFR, ETH_AFR_ABC | ETH_AFR_PRM );
#endif

    FLUSH_WRITES();
    OUTL( ETH_IPGT, 0x00000013 );
    FLUSH_WRITES();
    OUTL( ETH_IPGR, 0x00000e13 );
    FLUSH_WRITES();
    OUTL( ETH_CLRT, 0x0000380f );
    FLUSH_WRITES();
    OUTL( ETH_LMAX, MAX_ETHERNET_PACKET_SIZE );

    // Select a clock for the MII
    FLUSH_WRITES();
    OUTL( ETH_MIIC, ETH_MIIC_66 ); // Example code sets to 66.
    // Set VLAN type reg
    FLUSH_WRITES();
    OUTL( ETH_VLTP, ETH_VLTP_VLTP );

    // Set the ESA in the device regs
    if ( p_eth_upd985xx->mac_addr_ok ) {
        FLUSH_WRITES();
        OUTL( ETH_LSA2,
              (p_eth_upd985xx->mac_address[1]) |
              (p_eth_upd985xx->mac_address[0] << 8 ) );
        FLUSH_WRITES();
        OUTL( ETH_LSA1,
              (p_eth_upd985xx->mac_address[5]) |
              (p_eth_upd985xx->mac_address[4] << 8 ) |
              (p_eth_upd985xx->mac_address[3] << 16 ) |
              (p_eth_upd985xx->mac_address[2] << 24) );
    }

    FLUSH_WRITES();
    OUTL( ETH_RXFCR, ETH_RXFCR_UWM_DEFAULT |
                     ETH_RXFCR_LWM_DEFAULT | ETH_RXFCR_DRTH16W ); 

    FLUSH_WRITES();
    // Fault E4 - use only 32 for FLTH, not the previously recommended 48 (words)
    // Tag: CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E4
    // but no config opt is provided.
    OUTL( ETH_TXFCR, ETH_TXFCR_TPTV_DEFAULT |
                     ETH_TXFCR_TX_DRTH_DEFAULT | (32 << ETH_TXFCR_TX_FLTH_SHIFT) );

    // Transmit and receive config regs we hit when enabling those
    // functions separately, and the wet string end of the receiver
    // which is controlled by   MACC1 |= ETH_MACC1_SRXEN;

    // Tx and Rx interrupts enabled internally; 
    // Tx done/aborted, and rx OK.
    FLUSH_WRITES();
    OUTL( ETH_MSR, ETH_ISR_XMTDN | ETH_ISR_TABR | 
                   ETH_ISR_RCVDN | ETH_ISR_RBDRS | ETH_ISR_RBDRU );
    FLUSH_WRITES();
}

// ------------------------------------------------------------------------
//
//                NETWORK INTERFACE INITIALIZATION
//
// ------------------------------------------------------------------------
STATIC bool
upd985xx_eth_upd985xx_init(struct cyg_netdevtab_entry * ndp)
{
    struct eth_drv_sc *sc;
    cyg_uint8 *mac_address;
    struct eth_upd985xx *p_eth_upd985xx;

#ifdef DEBUG
    db_printf("upd985xx_eth_upd985xx_init\n");
#endif

    sc = (struct eth_drv_sc *)(ndp->device_instance);
    p_eth_upd985xx = (struct eth_upd985xx *)(sc->driver_private);

    CHECK_NDP_SC_LINK();

    p_eth_upd985xx->tx_busy = 0;

    // record the net dev pointer
    p_eth_upd985xx->ndp = (void *)ndp;

    mac_address = &p_eth_upd985xx->mac_address[0];

#ifdef CYGSEM_DEVS_ETH_UPD985XX_ETH0_GET_EEPROM_ESA
    if ( ! p_eth_upd985xx->hardwired_esa ) {
        cyg_uint8 *p;
        union macar {
            struct {
                cyg_uint32 macar1, macar2, macar3;
            } integers;
            cyg_uint8 bytes[12];
        } eeprom;

        eeprom.integers.macar1 = INL( MACAR1 );  // MAC Address Register 1
        eeprom.integers.macar2 = INL( MACAR2 );  // MAC Address Register 2
        eeprom.integers.macar3 = INL( MACAR3 );  // MAC Address Register 3

        if ( (0 != eeprom.integers.macar1 ||
              0 != eeprom.integers.macar2 ||
              0 != eeprom.integers.macar3 )
             && 
             (0xffffffff != eeprom.integers.macar1 ||
              0xffffffff != eeprom.integers.macar2 ||
              0xffffffff != eeprom.integers.macar3 ) ) {
            // Then we have good data in the EEPROM
#ifdef DEBUG
            os_printf( "EEPROM data %08x %08x %08x\n", 
                       eeprom.integers.macar1,
                       eeprom.integers.macar2,
                       eeprom.integers.macar3 );
#endif
            p = &eeprom.bytes[0]; // pick up either set of ESA info
            if ( 1 == p_eth_upd985xx->index )
                p += 6;

            mac_address[5] = p[5];
            mac_address[4] = p[4];
            mac_address[3] = p[3];
            mac_address[2] = p[2];
            mac_address[1] = p[1];
            mac_address[0] = p[0];
            p_eth_upd985xx->mac_addr_ok = 1;
        }
        else {
            // Fake it so we can get RedBoot going on a board with no EEPROM
            mac_address[0] = 0;
            mac_address[1] = 0xBA;
            mac_address[2] = 0xD0;
            mac_address[3] = 0xEE;
            mac_address[4] = 0x00;
            mac_address[5] = p_eth_upd985xx->index;
            p_eth_upd985xx->mac_addr_ok = 1;
        }
    }
#endif // CYGSEM_DEVS_ETH_UPD985XX_ETH0_GET_EEPROM_ESA
    
    // Init the underlying hardware and insert the ESA:
    eth_upd985xx_reset(p_eth_upd985xx);

#ifdef DEBUG
    os_printf("MAC Address %s, ESA = %02X %02X %02X %02X %02X %02X\n",
              p_eth_upd985xx->mac_addr_ok ? "OK" : "**BAD**", 
              mac_address[0], mac_address[1], mac_address[2], mac_address[3],
              mac_address[4], mac_address[5]);
#endif

    // Set up the pointers to data structures
    InitTxRing(p_eth_upd985xx);

    // Construct the interrupt handler
    p_eth_upd985xx->active = 0;
    cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
    cyg_drv_interrupt_mask(p_eth_upd985xx->vector);
    cyg_drv_interrupt_create(
        p_eth_upd985xx->vector,
        0,                              // Priority - unused
        (CYG_ADDRWORD)sc,               // Data item passed to ISR & DSR
        eth_isr,                        // ISR
        eth_drv_dsr,                    // DSR (generic)
        &p_eth_upd985xx->interrupt_handle, // handle to intr obj
        &p_eth_upd985xx->interrupt_object ); // space for int obj

    cyg_drv_interrupt_attach(p_eth_upd985xx->interrupt_handle);

    // Initialize upper level driver
    if ( p_eth_upd985xx->mac_addr_ok )
        (sc->funs->eth_drv->init)(sc, &(p_eth_upd985xx->mac_address[0]) );
    else
        (sc->funs->eth_drv->init)(sc, 0 );
    
    return (1);
}

// ------------------------------------------------------------------------
//
//  Function : eth_upd985xx_start
//
// ------------------------------------------------------------------------
STATIC void
eth_upd985xx_start( struct eth_drv_sc *sc,
                    unsigned char *enaddr, int flags )
{
    struct eth_upd985xx *p_eth_upd985xx;
    cyg_uint32 ss; 
#ifdef CYGPKG_NET
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;
#endif

    p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;

#ifdef DEBUG
    os_printf("eth_upd985xx_start %d flg %x\n", p_eth_upd985xx->index, *(int *)p_eth_upd985xx );
#endif

    if ( p_eth_upd985xx->active )
        eth_upd985xx_stop( sc );

    p_eth_upd985xx->active = 1;
    
#ifdef CYGPKG_NET
    /* Enable promiscuous mode if requested, reception of oversized frames always.
     * The latter is needed for VLAN support and shouldn't hurt even if we're not
     * using VLANs.
     */
    eth_upd985xx_configure(p_eth_upd985xx, !!(ifp->if_flags & IFF_PROMISC), 1);
#endif

    // renegotiate link status
    p_eth_upd985xx->phy_status = eth_upd985xx_status( p_eth_upd985xx );

    if ( p_eth_upd985xx->phy_status & PHY_STATUS_FDX ) {
        cyg_uint32 ss;
        // then enable full duplex in the MAC
        ss = INL( ETH_MACC1 );
        ss |= ETH_MACC1_FDX;
        OUTL( ETH_MACC1, ss );
    }

#ifdef DEBUG
    {
        int status = p_eth_upd985xx->phy_status;
        os_printf("eth_upd985xx_start %d Link = %s, %s Mbps, %s Duplex\n",
                  p_eth_upd985xx->index,
                  status & PHY_STATUS_LINK ? "Up" : "Down",
                  status & PHY_STATUS_100MBPS ?  "100" : "10",
                  status & PHY_STATUS_FDX ? "Full" : "Half"
            );
    }
#endif


    // Start the receive engine
    p_eth_upd985xx->count_rx_restart++;
    // Initialize all but one buffer: [B0,B1,B2,...Bx,NULL,LINK]
    InitRxRing( p_eth_upd985xx );
    // Point the hardware at the list of buffers
    OUTL( ETH_RXDPR, (cyg_uint32)p_eth_upd985xx->rxring_active );
    // Tell it about the buffers via the rx descriptor count
    OUTL( ETH_RXPDR, ETH_RXPDR_AL | (NUM_RXBUFS-1) );
    // Ack any pending interrupts from the system
    p_eth_upd985xx->intrs = INL( ETH_ISR ); // Read-clear
    // Start the rx.
    OUTL( ETH_RXCR, ETH_RXCR_RXE | ETH_RXCR_DRBS_16 );

    // Enable the wet string end of the receiver
    ss = INL( ETH_MACC1 );
    ss |= ETH_MACC1_SRXEN;
    OUTL( ETH_MACC1, ss );

    // And unmask the interrupt
    cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
    cyg_drv_interrupt_unmask(p_eth_upd985xx->vector);
}

// ------------------------------------------------------------------------
//
//  Function : eth_upd985xx_status; 10/100 and Full/Half Duplex (FDX/HDX)
//
// ------------------------------------------------------------------------
STATIC int eth_upd985xx_status( struct eth_upd985xx *p_eth_upd985xx )
{
    int status;
    int i, j;
    // Some of these bits latch and only reflect "the truth" on a 2nd reading.
    // So read and discard.
    mii_read( PHY_CONTROL_REG, &i, p_eth_upd985xx );
    mii_read( PHY_STATUS_REG, &i, p_eth_upd985xx );
    // Use the "and" of the local and remote capabilities words to infer
    // what is selected:
    status = 0;
    if ( mii_read( PHY_STATUS_REG, &i, p_eth_upd985xx ) ) {
        if ( PHY_STATUS_LINK_OK & i )
            status |= PHY_STATUS_LINK;
    }
    if ( mii_read( PHY_AUTONEG_ADVERT, &j, p_eth_upd985xx ) && 
         mii_read( PHY_AUTONEG_REMOTE, &i, p_eth_upd985xx ) ) {
#if defined( DEBUG_TRAFFIC ) || defined( DEBUG_IOCTL )
        os_printf( "MII: capabilities are %04x, %04x; common %04x\n",
                   i, j, i & j );
#endif
        j &= i; // select only common capabilities

        if ( (PHY_AUTONEG_100BASET4 |
              PHY_AUTONEG_100BASETX_FDX |
              PHY_AUTONEG_100BASETX_HDX)  & j )
            status |= PHY_STATUS_100MBPS;
        if ( (PHY_AUTONEG_100BASETX_FDX | PHY_AUTONEG_10BASET_FDX) & j )
            status |= PHY_STATUS_FDX;
    }
    return status;
}

// ------------------------------------------------------------------------
//
//  Function : eth_upd985xx_stop
//
// ------------------------------------------------------------------------

STATIC void eth_upd985xx_stop( struct eth_drv_sc *sc )
{
    struct eth_upd985xx *p_eth_upd985xx;

    p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;

    // No more interrupts
    cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
    cyg_drv_interrupt_mask(p_eth_upd985xx->vector);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?