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

📄 if_ep93xx.c

📁 ecos实时嵌入式操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
//==========================================================================////      dev/if_ep93xx.c////      Ethernet device driver for Cirrus Logic EP93xx////==========================================================================//####COPYRIGHTBEGIN####//                                                                          // -------------------------------------------                              // The contents of this file are subject to the Red Hat eCos Public License // Version 1.1 (the "License"); you may not use this file except in         // compliance with the License.  You may obtain a copy of the License at    // http://www.redhat.com/                                                   //                                                                          // Software distributed under the License is distributed on an "AS IS"      // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the // License for the specific language governing rights and limitations under // the License.                                                             //                                                                          // The Original Code is eCos - Embedded Configurable Operating System,      // released September 30, 1998.                                             //                                                                          // The Initial Developer of the Original Code is Red Hat.                   // Portions created by Red Hat are                                          // Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.                             // All Rights Reserved.                                                     // -------------------------------------------                              //                                                                          //####COPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s):    // Contributors: // Date:         // Purpose:      // Description:  hardware driver for EP9312 MAC//              ////####DESCRIPTIONEND####////==========================================================================// Ethernet device driver for Cirrus Logic EP93xx#include <pkgconf/system.h>#include <pkgconf/devs_eth_arm_ep93xx.h>#ifdef CYGPKG_NET#include <pkgconf/net.h>#include <cyg/kernel/kapi.h>#endif#include <cyg/infra/cyg_type.h>#include <cyg/hal/hal_arch.h>#include <cyg/hal/hal_intr.h>#include <cyg/hal/hal_io.h>#include <cyg/hal/hal_diag.h>#include <cyg/infra/diag.h>#include <cyg/hal/drv_api.h>#include <cyg/hal/hal_cache.h>#include <cyg/io/eth/netdev.h>#include <cyg/io/eth/eth_drv.h>#include <cyg/hal/ep93xx.h>#include "ep93xx_eth.h"                // ------------------------------------------------------------------------#ifndef CYGSEM_ARM_EP93XX_SET_ESA#ifdef CYGPKG_REDBOOT#include <pkgconf/redboot.h>#ifdef CYGSEM_REDBOOT_FLASH_CONFIG#include <redboot.h>#include <flash_config.h>RedBoot_config_option("Network hardware address [MAC]",                      ep93xx_esa,                      ALWAYS_ENABLED,                       true,                      CONFIG_ESA,                       0x088812345678    );#endif#endif#endif// ------------------------------------------------------------------------extern void *memcpy( void *, const void *, unsigned long );// ------------------------------------------------------------------------//#define ETHDEBUG#ifdef ETHDEBUG#define dprintf diag_printf#else #define dprintf #endif // ETHDEBUG// ------------------------------------------------------------------------#define ETHER_ADDR_LEN 6#define ETHERNET_INTERRUPT (CYGNUM_HAL_INTERRUPT_MAC) // in case it changesstruct ep93xx_priv_data {    // These are fixed, set-up-once, pointers to uncachable    // addresses for the tables the device writes to:    RxHdr        *rxhdrs;    RxStat       *rxstat;    TxHdr        *txhdrs;    TxStat       *txstat;    // These are dynamic status pointers.    RxStat       *rxsp;    TxStat       *txsp;#ifdef CYGPKG_NET    cyg_interrupt interrupt;    cyg_handle_t  interrupt_handle;#endif // CYGPKG_NET    unsigned char enaddr[ETHER_ADDR_LEN];    cyg_uint8     hardwired_esa;    int           txbusy;  // Number of packets already queued    int           txnext;  // Index to next hdr to use              unsigned long txkey[CYGNUM_DEVS_ETH_ARM_EP93XX_TxNUM];   // Used to ack when packet sent    unsigned long rxmode;    // From here downwards, never access these directly, use    // the uncachable pointers above:    RxHdr         _rxhdrs[CYGNUM_DEVS_ETH_ARM_EP93XX_RxNUM];    RxStat        _rxstat[CYGNUM_DEVS_ETH_ARM_EP93XX_RxNUM];    TxHdr         _txhdrs[CYGNUM_DEVS_ETH_ARM_EP93XX_TxNUM];    TxStat        _txstat[CYGNUM_DEVS_ETH_ARM_EP93XX_TxNUM];    // The actual data buffers    unsigned char _rxbufs[CYGNUM_DEVS_ETH_ARM_EP93XX_RxNUM]                        [CYGNUM_DEVS_ETH_ARM_EP93XX_BUFSIZE];    unsigned char _txbufs[CYGNUM_DEVS_ETH_ARM_EP93XX_TxNUM]                        [CYGNUM_DEVS_ETH_ARM_EP93XX_BUFSIZE];} _ep93xx_priv_data = {#ifdef CYGSEM_ARM_EP93XX_SET_ESA    hardwired_esa: 1,    enaddr: CYGDAT_ARM_EP93XX_ESA,#else    hardwired_esa: 0,#endif};ETH_DRV_SC(ep93xx_sc,           &_ep93xx_priv_data, // Driver specific data           "eth0",             // Name for this interface           ep93xx_start,           ep93xx_stop,           ep93xx_control,           ep93xx_can_send,           ep93xx_send,           ep93xx_recv,           ep93xx_deliver,     // "pseudoDSR" called from fast net thread           ep93xx_poll,        // poll function, encapsulates ISR and DSR           ep93xx_int_vector);NETDEVTAB_ENTRY(ep93xx_netdev,                 "ep93xx",                 ep93xx_init,                 &ep93xx_sc);static void ep93xx_poll(struct eth_drv_sc *sc);#ifdef CYGPKG_NET// This ISR is called when the ethernet interrupt occursstatic intep93xx_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs){// in case functionality moves into the ISR so that poll() uses it.#ifdef CYGPKG_NET    cyg_drv_interrupt_mask(ETHERNET_INTERRUPT);#endif // CYGPKG_NET    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR}#endif // CYGPKG_NET// The deliver function (ex-DSR)  handles the ethernet [logical] processingstatic voidep93xx_deliver(struct eth_drv_sc *sc){#ifdef CYGPKG_NET    ep93xx_poll(sc);    // Allow interrupts to happen again    cyg_drv_interrupt_acknowledge(ETHERNET_INTERRUPT);    cyg_drv_interrupt_unmask(ETHERNET_INTERRUPT);#endif // CYGPKG_NET}static intep93xx_int_vector(struct eth_drv_sc *sc){    return (ETHERNET_INTERRUPT);}#define ERR_PHY_OK        (0)#define ERR_PHY_UNKNOWN   (-1)#define ERR_PHY_BUSY      (-2)#define ERR_PHY_TIMEOUT   (-3)#define PHY_TIMEOUT       10000static intreadPHY(int phy, int reg, unsigned long *val){    unsigned long stat;    int timeout;#ifdef ETHDEBUG    //dprintf("readPHY()\n");#endif // ETHDEBUG        timeout = PHY_TIMEOUT;    do {        if (--timeout == 0)         {        #ifdef ETHDEBUG            dprintf("readPHY() Phy Busy\n");        #endif // ETHDEBUG            return ERR_PHY_BUSY;        }        HAL_READ_UINT32(MAC_MiiStat, stat);    } while (stat & MAC_MiiStat_Busy);    HAL_WRITE_UINT32(MAC_MiiCmd, MiiCmdRead|(phy<<5)|reg);    timeout = PHY_TIMEOUT;    do {        if (--timeout == 0)         {        #ifdef ETHDEBUG            dprintf("readPHY() Phy timeout\n");        #endif // ETHDEBUG            return ERR_PHY_TIMEOUT;        }        HAL_READ_UINT32(MAC_MiiStat, stat);    } while (stat & MAC_MiiStat_Busy);    HAL_READ_UINT32(MAC_MiiData, stat);    *val = stat;    return ERR_PHY_OK;}static voidwritePHY(int phy, int reg, unsigned long val){    unsigned long stat;#ifdef ETHDEBUG    //dprintf("writePHY()\n");#endif // ETHDEBUG        do {        HAL_READ_UINT32(MAC_MiiStat, stat);    } while (stat & MAC_MiiStat_Busy);    HAL_WRITE_UINT32(MAC_MiiData, val);    HAL_WRITE_UINT32(MAC_MiiCmd, MiiCmdWrite|(phy<<5)|reg);    do {        HAL_READ_UINT32(MAC_MiiStat, stat);    } while (stat & MAC_MiiStat_Busy);}voiddoPHY(void){    unsigned long stat1, stat2, oldSelfCtlVal, testCtlVal;    int indx, err;    cyg_uint32 phys_found = 0; // bitset of good PHYs found    cyg_uint32 phys_good  = 0; // bitset of PHYs found with good link        HAL_READ_UINT32(MAC_SelfCtl, oldSelfCtlVal);    //Set MDC clock to be divided by 8, and disable PreambleSurpress    //so that MAC can read/write PHY registers.    HAL_WRITE_UINT32(MAC_SelfCtl, 0x0e00);    // First scan for existant PHYs on the MII bus#ifdef ETHDEBUG    dprintf("... Scan for PHY units\n");#endif // ETHDEBUG    // PHY ID 0 is for broadcasting to all PHYs.  Don't scan it.    for (indx = 1;  indx < 32;  indx++) {        err = readPHY(indx, PHY_ID_ONE, &stat1);        if (err != ERR_PHY_OK)            continue;        if (stat1 == 0x0000FFFF) // Most likely, this device isn't there            continue;        err = readPHY(indx, PHY_ID_TWO, &stat2);        if (err != ERR_PHY_OK)            continue;#ifdef ETHDEBUG        dprintf("PHY ID[%x] = %x/%x", indx, stat1, stat2);#endif // ETHDEBUG        // Some of these bits latch and only reflect "the truth" on a 2nd reading.        // So read and discard.        readPHY(indx, PHY_CONTROL_REG, &stat2);        readPHY(indx, PHY_STATUS_REG , &stat1);        readPHY(indx, PHY_CONTROL_REG, &stat2);        readPHY(indx, PHY_STATUS_REG,  &stat1);#ifdef ETHDEBUG        dprintf(", stat = %x, control = %x\n", stat1, stat2);#endif // ETHDEBUG        phys_found |= (1<<indx);        // Command the PHY to renegotiate the link and advertise!        readPHY(indx, PHY_AUTONEG_ADVERT , &stat1);        stat1 |= (PHY_AUTONEG_100BASETX_FDX +                  PHY_AUTONEG_100BASETX_HDX +                   PHY_AUTONEG_10BASET_FDX +                   PHY_AUTONEG_10BASET_HDX);        writePHY(indx, PHY_AUTONEG_ADVERT , stat1);        stat2 |= PHY_CONTROL_AUTONEG_EN | PHY_CONTROL_AUTONEG_RST;        stat2 &=~PHY_CONTROL_POWERDOWN;        writePHY(indx, PHY_CONTROL_REG, stat2 );        hal_delay_us( 1000 );    }    for (indx = 1;  indx < 32;  indx++) {        unsigned long i, j;        if ( 0 == (phys_found & (1<<indx)) )            continue;        i = 3000; // 3 seconds should be enough        do {            hal_delay_us( 1000 );            err = readPHY(indx, PHY_STATUS_REG, &stat1 );            if (err != ERR_PHY_OK || 0 == i-- )                break;        } while ( 0 == (PHY_STATUS_AUTONEG_ACK & stat1) );        // Then autonegotiation is complete (or timed out)        readPHY(indx, PHY_STATUS_REG, &stat1 );        if ( (PHY_STATUS_LINK_OK & stat1) ) {            readPHY(indx, PHY_AUTONEG_ADVERT, &i );            readPHY(indx, PHY_AUTONEG_REMOTE, &j );#ifdef ETHDEBUG            dprintf( "MII %d: capabilities are %04x, %04x; common %04x\n",                     indx,                        i, j, i & j );#endif // ETHDEBUG            j &= i;            if ( j & (PHY_AUTONEG_100BASETX_FDX + PHY_AUTONEG_100BASETX_HDX +                       PHY_AUTONEG_10BASET_FDX + PHY_AUTONEG_10BASET_HDX) ) {                // Then there is commonality of capabilities, we are happy!                phys_good |= (1<<indx);                // OPTIONAL: having found one good interface, that's                // enough: saves wasting time scanning all - when the                // network device seems unable to use other PHYs.                break;            }            if ( j & (PHY_AUTONEG_100BASETX_FDX + PHY_AUTONEG_10BASET_FDX)) {               // If PHY is full duplex, set MAC to full duplex too.               HAL_READ_UINT32(MAC_TestCtl, testCtlVal);               testCtlVal |= MAC_TestCtl_FDX;               HAL_WRITE_UINT32(MAC_TestCtl, testCtlVal);            }        }    }    // so there is at least one good link there    if ( 0 == phys_good )        phys_good = phys_found & ~(phys_found-1);#ifdef ETHDEBUG    dprintf( "After scan, phys_found %08x, phys_good %08x\n",             phys_found, phys_good );#endif // ETHDEBUG    // select the first one we find    phys_good = phys_good & ~(phys_good-1);    for (indx = 1;  indx < 32;  indx++) {        if ( (1<<indx) & phys_found ) {            if ( 0 == ((1<<indx) & phys_good) ) {#ifdef ETHDEBUG                dprintf("Disabling PHY unit %d\n", indx );#endif // ETHDEBUG                // Disable second PHY; Power down device                writePHY(indx, PHY_CONTROL_REG, PHY_CONTROL_POWERDOWN );            }        }    }    // restore the old vaule of SelfCtl register.    HAL_WRITE_UINT32(MAC_SelfCtl, oldSelfCtlVal);}// ------------------------------------------------------------------------//// Reset the receiver and rebuild queues, etc.//static voidep93xx_RxReset(struct ep93xx_priv_data *cpd){    cyg_uint32 stat;    cyg_uint32 phys;    int i;#ifdef ETHDEBUG    dprintf("ep93xx_RxReset()\n");#endif // ETHDEBUG    // Reset Rx engine    HAL_WRITE_UINT32(MAC_BMCtl, MAC_BMCtl_RxReset);    do {        HAL_READ_UINT32(MAC_BMCtl, stat);    } while (stat & MAC_BMCtl_RxReset);    HAL_WRITE_UINT32(MAC_RxCtl, 0);    // Set up queues        HAL_VIRT_TO_PHYS_ADDRESS( (cyg_uint32)cpd->rxhdrs, phys );    HAL_WRITE_UINT32(MAC_RxDBA, phys );    HAL_WRITE_UINT32(MAC_RxDBL, CYGNUM_DEVS_ETH_ARM_EP93XX_RxNUM * sizeof(RxHdr));    HAL_WRITE_UINT32(MAC_RxDCA, phys );    HAL_VIRT_TO_PHYS_ADDRESS( (cyg_uint32)cpd->rxstat, phys );    HAL_WRITE_UINT32(MAC_RxSBA, phys );    HAL_WRITE_UINT32(MAC_RxSBL, CYGNUM_DEVS_ETH_ARM_EP93XX_RxNUM * sizeof(RxStat));    HAL_WRITE_UINT32(MAC_RxSCA, phys );    HAL_WRITE_UINT32(MAC_RxDTH, 0x00040002);    HAL_WRITE_UINT32(MAC_RxSTH, 0x00040002);    HAL_WRITE_UINT32(MAC_RxBTH, 0x00800040);    cpd->rxsp = cpd->rxstat;    for (i = 0;  i < CYGNUM_DEVS_ETH_ARM_EP93XX_RxNUM;  i++)     {        HAL_VIRT_TO_PHYS_ADDRESS( (cyg_uint32)&cpd->_rxbufs[i][0], phys );        cpd->rxhdrs[i].bufaddr = (void *)phys;        cpd->rxhdrs[i].bi = i;        cpd->rxhdrs[i].len = CYGNUM_DEVS_ETH_ARM_EP93XX_BUFSIZE;    }    // Wait for Receiver to get started    HAL_WRITE_UINT32(MAC_BMCtl, MAC_BMCtl_RxEnable);    do {        HAL_READ_UINT32(MAC_BMStat, stat);    } while ((stat & MAC_BMStat_RxAct) == 0) ;    HAL_WRITE_UINT32(MAC_RxDEQ, CYGNUM_DEVS_ETH_ARM_EP93XX_RxNUM);    HAL_WRITE_UINT32(MAC_RxSEQ, CYGNUM_DEVS_ETH_ARM_EP93XX_RxNUM);    // Configure and enable receiver    HAL_WRITE_UINT32(MAC_MaxFL, (CYGNUM_DEVS_ETH_ARM_EP93XX_BUFSIZE<<16));}// ------------------------------------------------------------------------static voidep93xx_TxReset(struct ep93xx_priv_data *cpd){    cyg_uint32 stat;    cyg_uint32 phys;#ifdef ETHDEBUG    dprintf("ep93xx_TxReset()\n");#endif // ETHDEBUG    // Clear all test options (was: set FD => ignore CSMA!)    HAL_WRITE_UINT32(MAC_TestCtl, 0);    HAL_VIRT_TO_PHYS_ADDRESS( (unsigned long)cpd->txhdrs, phys );    HAL_WRITE_UINT32(MAC_TxDBA, phys );    HAL_WRITE_UINT32(MAC_TxDBL, CYGNUM_DEVS_ETH_ARM_EP93XX_TxNUM * sizeof(TxHdr));    HAL_WRITE_UINT32(MAC_TxDCA, phys );    HAL_VIRT_TO_PHYS_ADDRESS( (unsigned long)cpd->txstat, phys );    HAL_WRITE_UINT32(MAC_TxSBA, phys );    HAL_WRITE_UINT32(MAC_TxSBL, CYGNUM_DEVS_ETH_ARM_EP93XX_TxNUM * sizeof(TxStat));    HAL_WRITE_UINT32(MAC_TxSCA, phys );    HAL_WRITE_UINT32(MAC_TxDTH, 0x00040002);    HAL_WRITE_UINT32(MAC_TxSTH, 0x00040002);    HAL_WRITE_UINT32(MAC_TxDTH, 0x00200010);    cpd->txsp = cpd->txstat;    // Configure and enable transmitter    HAL_WRITE_UINT32(MAC_BMCtl, MAC_BMCtl_TxEnable);    do {        HAL_READ_UINT32(MAC_BMStat, stat);

⌨️ 快捷键说明

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