⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lan91c111.c

📁 Analog公司的ADSP_BF532上面实现以太网接口的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
//##############################################################
//#
//# LAN91C111.H
//#
//# ADSP-21535 Embedded Web Server Project
//#
//# (c) ANALOG DEVICES 2002
//#     eDSP Division
//#     Stefan Hacker
//#     23-DEC-2002
//#
//# History
//#     16-APR-2003 HS  release 1.0
//#

#include <stdio.h>
#include "lan91c111.h"
#include "io_sprt.h"
#include "globals.h"
#include "tcp_ip.h"
#include "string.h"


/******************************************************************************
 * Initializes SMSC91C111
 *****************************************************************************/
void smc_init_91c111()
{
    int i;
    WORD wtmp, wstat, tmp, ioaddr,rev_reg;

    /* First, see if the high byte is 0x33 */
    tmp = _inpw(BSR_REG);
    if ( (tmp & 0xFF00) != 0x3300 )
    {
       return;
    }

    /* The above MIGHT indicate a device, but I need to write to further test this.  */
    _outpw(BSR_REG, 0x0);
    tmp = _inpw(BSR_REG);
    if ( (tmp & 0xFF00 ) != 0x3300 )
    {
       return;
    }

    _outpw(BSR_REG, 1);                             // select bank 1
    tmp = _inpw(BASE_REG );
    ioaddr = ( tmp >> 3 & 0x3E0 );

    _outpw(BSR_REG, 3);                             // select bank 1
    tmp = _inpw(REV_REG );
    rev_reg = ( tmp >> 4 & 0xF );


    //init SMSC
    _outpw(BSR_REG, 0);                             // select bank 0
    _outpw(RCR_REG, RCR_SOFTRST);                   // issue soft reset
    smc_write_phy_register(PHY_CNTL_REG, 0x8000);   // get phy from reset
    _outpw(RCR_REG, 0);                             // clear reset

    Timeout_LAN = 2;                                // wait 250ms
    while(Timeout_LAN);

    // disable TX and RX functionality
    _outpw(RCR_REG, 0);                             // clear RX
    _outpw(TCR_REG, 0);                             // clear TX

    // init MAC address
    _outpw(BSR_REG, 1);                             // select bank 1

    _outpw(CFG_REG, CFG_EPH_POWER_EN);              // get out of low power mode
    _outpw(CFG_REG, _inpw(CFG_REG)|CFG_NOWAIT);     // set NO_WAIT
    _outpw(ADDR0_REG, MAC_IA_2<<8|MAC_IA_1);        // set MAC addr
    _outpw(ADDR1_REG, MAC_IA_4<<8|MAC_IA_3);        // set MAC addr
    _outpw(ADDR2_REG, MAC_IA_6<<8|MAC_IA_5);        // set MAC addr

    // release all pending packets
    _outpw(CTL_REG, _inpw(CTL_REG)|CTL_AUTO_RELEASE);

    // reset MMU
    _outpw(BSR_REG, 2);
    _outpw(MMU_CMD_REG, MC_RESET);

    // disable all IRQs
    _outp(IM_REG, 0);

    // autonego + LEDs
    _outpw(BSR_REG, 0);
    _outpw(RPC_REG, RPC_ANEG | 0x80);

    // turn off isolation mode
    smc_write_phy_register(PHY_CNTL_REG, 0x3000);

    // wait 1.5sec
    Timeout_LAN = 16;
    while(Timeout_LAN);

    // read PHY_STAT once due to update latency
    smc_read_phy_register(PHY_STAT_REG);

#if 0//L_DP
    printf("\n");
    wtmp = smc_read_phy_register(PHY_CNTL_REG);
    printf("PHY_CNTL_REG: 0x%x\n", wtmp);

    wtmp = smc_read_phy_register(PHY_STAT_REG);
    printf("PHY_STAT_REG: 0x%x\n", wtmp);

    wtmp = smc_read_phy_register(PHY_ID1_REG);
    printf("PHY_ID1_REG:  0x%x\n", wtmp);

    wtmp = smc_read_phy_register(PHY_ID2_REG);
    printf("PHY_ID2_REG:  0x%x\n", wtmp);

    wtmp = smc_read_phy_register(PHY_AD_REG);
    printf("PHY_AD_REG:   0x%x\n", wtmp);

    wtmp = smc_read_phy_register(PHY_RMT_REG);
    printf("PHY_RMT_REG:  0x%x\n", wtmp);

    wtmp = smc_read_phy_register(PHY_CFG1_REG);
    printf("PHY_CFG1_REG: 0x%x\n", wtmp);

    wtmp = smc_read_phy_register(PHY_CFG2_REG);
    printf("PHY_CFG2_REG: 0x%x\n", wtmp);

    wtmp = smc_read_phy_register(PHY_INT_REG);
    printf("PHY_INT_REG:  0x%x\n", wtmp);

    wtmp = smc_read_phy_register(PHY_STAT_REG);
    printf("PHY_STAT_REG: 0x%x\n", wtmp);
#endif //D_LP

    // check anego bits
    wtmp = smc_read_phy_register(PHY_STAT_REG);
    if ((wtmp & (PHY_STAT_LINK|PHY_STAT_ANEG_ACK)) == (PHY_STAT_LINK|PHY_STAT_ANEG_ACK))
    {   // success
        wstat = smc_read_phy_register(PHY_INT_REG);
#if 1//D_LP==2
        printf("\nANEG success, Status = 0x%x", wstat);
#endif

        // read transmit register
        wtmp = _inpw(TCR_REG);

        // check for full duplex FDX
        if ((wstat & PHY_INT_DPLXDET) == PHY_INT_DPLXDET)
            wtmp |= TCR_SWFDUP;
        else
            wtmp &= ~TCR_SWFDUP;

        // write FDX result
        _outpw(TCR_REG, wtmp);
    }
    else
    {   // fail
        wstat = smc_read_phy_register(PHY_INT_REG);
#if D_LP==2
        printf("\nANEG failed, Status = 0x%x", wstat);
#endif
    }

    // enable RX and TX
    _outpw(BSR_REG, 0);
    _outpw(TCR_REG, _inpw(TCR_REG)|TCR_DEFAULT);  // enable TX
    _outpw(RCR_REG, _inpw(RCR_REG)|RCR_DEFAULT);  // enable RX

    // enable IRQs
    _outpw(BSR_REG, 2);
    _outp(IM_REG, SMC_INTERRUPT_MASK);                 // standard IRQ mask
    _outpw(BSR_REG, 0);
}


/******************************************************************************
 * Writes a word through the MII interface to the PHY
 *****************************************************************************/
void smc_write_phy_register(BYTE phyreg, WORD phydata)
{
    int i;
    WORD oldBank, wmask, mii_reg;
    BYTE bits[65], bmask;
    int  clk_idx = 0;

    // Prepare bit stream for PHY
    // 32 consecutive ones on MDO to establish sync
    for (i = 0; i < 32; ++i)
        bits[clk_idx++] = MII_MDOE | MII_MDO;

    // Start code <01>
    bits[clk_idx++] = MII_MDOE;
    bits[clk_idx++] = MII_MDOE | MII_MDO;
    // Write command <01>
    bits[clk_idx++] = MII_MDOE;
    bits[clk_idx++] = MII_MDOE | MII_MDO;

    // Output the PHY address, msb first, internal PHY = 0
    bits[clk_idx++] = MII_MDOE;
    bits[clk_idx++] = MII_MDOE;
    bits[clk_idx++] = MII_MDOE;
    bits[clk_idx++] = MII_MDOE;
    bits[clk_idx++] = MII_MDOE;

    // Output the phy register number, msb first
    bmask = 0x10;
    for (i = 0; i < 5; ++i)
    {
        if (phyreg & bmask)
            bits[clk_idx++] = MII_MDOE | MII_MDO;
        else
            bits[clk_idx++] = MII_MDOE;
        // Shift to next lowest bit
        bmask >>= 1;
    }

    // Tristate and turnaround (2 bit times) <10>
    bits[clk_idx++] = MII_MDOE | MII_MDO;;
    bits[clk_idx++] = 0;

    // Write out 16 bits of data, msb first
    wmask = 0x8000;
    for (i = 0; i < 16; ++i)
    {
        if (phydata & wmask)
            bits[clk_idx++] = MII_MDOE | MII_MDO;
        else
            bits[clk_idx++] = MII_MDOE;
        // Shift to next lowest bit
        wmask >>= 1;
    }

    // Final clock bit (tristate)
    bits[clk_idx++] = 0;

    // Save the current bank
    oldBank = _inpw(BSR_REG);
    // Select bank 3
    _outpw(BSR_REG, 3);

    // Get the current MII register value
    mii_reg = _inpw(MII_REG);

    // Turn off all MII Interface bits
    mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);

    // Clock all cycles
    for (i = 0; i < sizeof bits; ++i)
    {
        // Clock Low - output data
        _outpw(MII_REG, mii_reg | bits[i] );
        // Clock Hi - input data
        _outpw(MII_REG, mii_reg | bits[i] | MII_MCLK);
    }

    // Return to idle state
    // Set clock to low, data to low, and output tristated
    _outpw(MII_REG, mii_reg);

    // Restore original bank select
    _outpw(BSR_REG, oldBank );
}

/******************************************************************************
 * Reads a word through the MII interface off the PHY
 *****************************************************************************/
WORD    smc_read_phy_register(BYTE phyreg)
{
    BYTE bits[64];
    BYTE bmask;
    WORD oldBank, mii_reg, phydata, wmask;
    int i, clk_idx = 0;
    int input_idx;

    // Prepare bit stream for PHY
    // 32 consecutive ones on MDO to establish sync
    for (i = 0; i < 32; ++i)
        bits[clk_idx++] = MII_MDOE | MII_MDO;

    // Start code <01>
    bits[clk_idx++] = MII_MDOE;
    bits[clk_idx++] = MII_MDOE | MII_MDO;
    // Read command <10>
    bits[clk_idx++] = MII_MDOE | MII_MDO;
    bits[clk_idx++] = MII_MDOE;
    // internal PHY address = <00000>
    bits[clk_idx++] = MII_MDOE;
    bits[clk_idx++] = MII_MDOE;
    bits[clk_idx++] = MII_MDOE;
    bits[clk_idx++] = MII_MDOE;
    bits[clk_idx++] = MII_MDOE;

    // Output the phy register number, msb first
    bmask = 0x10;
    for (i = 0; i < 5; ++i)
    {
        if (phyreg & bmask)
            bits[clk_idx++] = MII_MDOE | MII_MDO;
        else
            bits[clk_idx++] = MII_MDOE;
        // Shift to next lowest bit
        bmask >>= 1;
    }

    // Tristate and turnaround (2 bit times)
    bits[clk_idx++] = 0;

    // Input starts at this bit time
    input_idx = clk_idx;

    // Will input 16 bits
    for (i = 0; i < 16; ++i)
        bits[clk_idx++] = 0;

    // Final clock bit
    bits[clk_idx++] = 0;

    // Save the current bank
    oldBank = _inpw(BSR_REG);
    // Select bank 3
    _outpw(BSR_REG, 3);

    // Get the current MII register value
    mii_reg = _inpw(MII_REG);

    // Turn off all MII Interface bits
    mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);

    // Clock all 64 cycles
    for (i = 0; i < clk_idx /*sizeof bits*/; ++i)
    {
        // Clock Low - output data
        _outpw(MII_REG, mii_reg | bits[i]);
        // Clock Hi - input data
        _outpw(MII_REG, mii_reg | bits[i] | MII_MCLK);
        bits[i] |= _inpw(MII_REG) & MII_MDI;
    }

    // Return to idle state
    // Set clock to low, data to low, and output tristated
    _outpw(MII_REG, mii_reg);

    // Restore original bank select
    _outpw(BSR_REG, oldBank);

    // Recover input data
    phydata = 0;
    for (i = 0; i < 16; ++i)
    {
        phydata <<= 1;
        if (bits[input_idx++] & MII_MDI)
            phydata |= 0x0001;
    }
    return(phydata);
}

/******************************************************************************
 * Main IRQ Handler Function for SMSC91C111
 *****************************************************************************/
void smc_interrupt()
{
    /*
     * This is the main routine of the driver, to handle the
     * net_device when it needs some attention.
     * So:
     *  first, save state of the chipset
     *  branch off into routines to handle each case,
     *  and acknowledge each to the interrupt register
     *  and finally restore state.
     */

    BYTE    status;
    WORD    card_status;
    BYTE    mask;
    WORD    saved_bank;
    WORD    saved_pointer;

    // reset IRQ occurred
    IRQ_LAN = 0;

    // save current bank
    saved_bank = _inpw(BSR_REG);

    // switch to bank 2 and save pointer
    _outpw(BSR_REG, 2);
    saved_pointer = _inpw(PTR_REG);

    // read IRQ status register
    mask = _inp(IM_REG);

    // disable all LAN IRQs
    _outp(IM_REG, 0x0);

    /////////////////////
    // set here a timeout, typically less than 1sec
    //
    Timeout_LAN = 4;

    do {
        // read the status flag and mask it
        status = _inp(INT_REG)& mask;
        if (!status )
            break;

        if (status & IM_RCV_INT) {
            // store debug
            LAN_state.last_IRQ_serviced = IM_RCV_INT;
            // Got a packet(s), receive them
            smc_rcv();

        } else if (status & IM_TX_INT ) {
            // store debug
            LAN_state.last_IRQ_serviced = IM_TX_INT;
            smc_tx();
            // Acknowledge the interrupt
            _outp(INT_REG, IM_TX_INT);

        } else if (status & IM_TX_EMPTY_INT ) {
            // store debug
            LAN_state.last_IRQ_serviced = IM_TX_EMPTY_INT;

            _outpw(BSR_REG, 0);
            card_status = _inpw(COUNTER_REG );

#ifdef log_net_errs
            // multiple collisions
            stats.collisions += card_stats & 0xF;
            card_stats >>= 4;
            // multiple collisions
            stats.collisions += card_stats & 0xF;
#endif

            _outpw(BSR_REG, 2);
            // Acknowledge the interrupt
            _outp(INT_REG, IM_TX_EMPTY_INT);
            mask &= ~IM_TX_EMPTY_INT;

#ifdef log_net_errs
            stats.tx_packets += packets_waiting;
#endif
            // clear state of waiting packets
            LAN_state.packets_waiting = 0;

        } else if (status & IM_ALLOC_INT ) {
            // store debug
            LAN_state.last_IRQ_serviced = IM_ALLOC_INT;

            // allocation IRQ
            LAN_state.alloc_success = 1;

            // clear this interrupt so it doesn't happen again
            mask &= ~IM_ALLOC_INT;

            /* enable xmit interrupts based on this */
            mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );

        } else if (status & IM_RX_OVRN_INT ) {
            // store debug
            LAN_state.last_IRQ_serviced = IM_RX_OVRN_INT;

#ifdef log_net_errs
            stats.rx_errors++;
            stats.rx_fifo_errors++;
#endif
            // Acknowledge the interrupt
            _outp(INT_REG, IM_RX_OVRN_INT);

        } else if (status & IM_EPH_INT ) {
            // currently unsupported IRQ
            // store debug
            LAN_state.last_IRQ_serviced = IM_EPH_INT;

        } else if (status & IM_MDINT ) {
            // store debug
            LAN_state.last_IRQ_serviced = IM_MDINT;
            smc_phy_interrupt();
            // Acknowledge the interrupt
            _outp(INT_REG, IM_MDINT);

        } else if (status & IM_ERCV_INT ) {
            // store debug
            // currently unsupported IRQ
            LAN_state.last_IRQ_serviced = IM_ERCV_INT;
            // Acknowledge the interrupt
            _outp(INT_REG, IM_ERCV_INT);
        }
    } while (Timeout_LAN--);


    //restore found register states
    _outpw(BSR_REG, 2);
    _outp(IM_REG, mask);

    _outpw(PTR_REG, saved_pointer);
    _outpw(BSR_REG, saved_bank);
}


/******************************************************************************
 * IRQ Sub Function: SMC_RCV for the LAN91C111
 *
 * Purpose:
 *  There is a packet waiting to be read from 91C111
 *
 * Actions:
 *  - Read the status
 *  - If an error, record it
 *  - otherwise, read in the packet
 *
 *****************************************************************************/
void smc_rcv()
{
    int     i, packet_number;
    WORD    status;
    WORD    packet_length;
#ifndef USE_16_BIT
    DWORD   *data;
#else
    WORD    *data;

⌨️ 快捷键说明

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