Mercurial > nand-ecoscentric
changeset 3192:1b48b0437ac3
New package -- Ethernet driver for Actel Smartfusion [Bugzilla 1001291]
| author | vae |
|---|---|
| date | Mon, 12 Mar 2012 20:44:39 +0000 |
| parents | 08eb5070a44f |
| children | bbae8ea8a773 |
| files | packages/devs/eth/cortexm/a2fxxx/current/ChangeLog packages/devs/eth/cortexm/a2fxxx/current/cdl/a2fxxx_eth.cdl packages/devs/eth/cortexm/a2fxxx/current/src/if_a2fxxx.c |
| diffstat | 3 files changed, 1271 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/devs/eth/cortexm/a2fxxx/current/ChangeLog @@ -0,0 +1,31 @@ + +2011-05-07 Christophe Coutand <ecos@hotmail.co.uk> + + * src/if_a2fxxx.c: + * cdl/a2fxxx_eth.cdl + New package -- Ethernet driver for Actel Smartfusion + [Bugzilla 1001291] + +//=========================================================================== +// ####GPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2011 Free Software Foundation, Inc. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, +// Fifth Floor, Boston, MA 02110-1301, USA. +// ------------------------------------------- +// ####GPLCOPYRIGHTEND#### +//===========================================================================
new file mode 100644 --- /dev/null +++ b/packages/devs/eth/cortexm/a2fxxx/current/cdl/a2fxxx_eth.cdl @@ -0,0 +1,152 @@ +#========================================================================== +# +# a2fxxx_eth.cdl +# +# Ethernet drivers for Actel AF2xxx Controller +# +#========================================================================== +## ####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 2011 Free Software Foundation, Inc. +## +## eCos is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free +## Software Foundation; either version 2 or (at your option) any later +## version. +## +## eCos is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with eCos; if not, write to the Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## As a special exception, if other files instantiate templates or use +## macros or inline functions from this file, or you compile this file +## and link it with other works to produce a work based on this file, +## this file does not by itself cause the resulting work to be covered by +## the GNU General Public License. However the source code for this file +## must still be made available in accordance with section (3) of the GNU +## General Public License v2. +## +## This exception does not invalidate any other reasons why a work based +## on this file might be covered by the GNU General Public License. +## ------------------------------------------- +## ####ECOSGPLCOPYRIGHTEND#### +#========================================================================== +######DESCRIPTIONBEGIN#### +# +# Author(s): ccoutand +# Contributors: +# Date: 2011-05-04 +# Purpose: +# Description: +# +#####DESCRIPTIONEND#### +# +#========================================================================*/ + +cdl_package CYGPKG_DEVS_ETH_CORTEXM_A2FXXX { + display "Actel Smartfusion Ethernet driver" + parent CYGPKG_IO_ETH_DRIVERS + active_if CYGPKG_IO_ETH_DRIVERS + active_if CYGPKG_HAL_CORTEXM_A2FXXX + + implements CYGHWR_NET_DRIVERS + implements CYGHWR_NET_DRIVER_ETH0 + + include_dir net + description " + Ethernet drivers for Actel AF2xxx Controller." + + compile -library=libextras.a if_a2fxxx.c + + cdl_option CYGSEM_DEVS_ETH_CORTEXM_A2FXXX_PROMISCUOUS { + display "Promiscuous Mode" + flavor bool + default_value 0 + description " + Selecting this option will set the Ethernet MAC in promiscuous mode, all Ethernet + packets will be delivered to the application layer." + } + + cdl_option CYGSEM_DEVS_ETH_CORTEXM_A2FXXX_CHATTER { + display "Display status messages during Ethernet operations" + flavor bool + default_value 0 + description " + Selecting this option will cause the Ethernet driver to print status + messages as various Ethernet operations are undertaken." + } + + cdl_option CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_ISR_PRIORITY { + display "Ethernet interrupt ISR priority" + flavor data + default_value CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_ISR_SP + description " + Set the Ethernet controller ISR priority." + } + + cdl_option CYGSEM_DEVS_ETH_CORTEXM_A2FXXX_STATS { + display "Maintain statistics at the MAC layer" + flavor bool + default_value 0 + description " + Selecting this option will cause the Ethernet driver to accumulate statistics + provided from the MAC layer." + } + + cdl_option CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_BUFSIZE_TX { + display "Buffer size" + flavor data + default_value 1536 + description " + This option specifies the size of the internal transmit buffers used + for the Actel A2Fxxx/Ethernet device." + } + + cdl_option CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_BUFSIZE_RX { + display "Buffer size" + flavor data + default_value 1536 + description " + This option specifies the size of the internal receive buffers used + for the Actel A2Fxxx/Ethernet device." + } + + cdl_option CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_TxNUM { + display "Number of output buffers" + flavor data + legal_values 2 to 8 + default_value 4 + description " + This option specifies the number of output buffer packets + to be used for the Actel A2Fxxx/Ethernet device." + } + + cdl_option CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_RxNUM { + display "Number of input buffers" + flavor data + legal_values 2 to 8 + default_value 4 + description " + This option specifies the number of input buffer packets + to be used for the Actel A2Fxxx/Ethernet device." + } + + cdl_option CYGPKG_DEVS_ETH_CORTEXM_A2FXXX_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "-D_KERNEL -D__ECOS" } + description " + This option modifies the set of compiler flags for + building the Actel A2Fxxx Ethernet driver package. + These flags are used in addition to the set of global flags." + } +} + +# EOF a2fxxx_eth.cdl
new file mode 100644 --- /dev/null +++ b/packages/devs/eth/cortexm/a2fxxx/current/src/if_a2fxxx.c @@ -0,0 +1,1088 @@ +//========================================================================== +// +// if_a2fxxx.c +// +// Ethernet driver for Actel A2Fxxx device family +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2011 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): ccoutand +// Contributors: +// Date: 2011-05-05 +// Purpose: Ethernet driver for Actel A2Fxxx device family +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================*/ + +#include <pkgconf/system.h> +#include <pkgconf/devs_eth_cortexm_a2fxxx.h> + +#ifdef CYGDAT_DEVS_CORTEXM_A2FXXX_ETH_CDL +# include CYGDAT_DEVS_CORTEXM_A2FXXX_ETH_CDL +#endif + +#include <pkgconf/io_eth_drivers.h> + +#ifdef CYGPKG_NET +# include <pkgconf/net.h> +#endif + +#include <cyg/infra/cyg_type.h> + +#include <cyg/hal/hal_arch.h> +#include <cyg/hal/hal_cache.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/hal/drv_api.h> +#include <cyg/hal/hal_if.h> +#include <cyg/hal/var_io.h> + +#include <cyg/io/eth/netdev.h> +#include <cyg/io/eth/eth_drv.h> + +#ifdef CYGPKG_DEVS_ETH_PHY +# include <cyg/io/eth_phy.h> +#endif + +#include <errno.h> +#include <string.h> + +static unsigned char enaddr[6]; + +// Buffer descriptor +struct a2fxxx_bd { + cyg_uint32 des0; + cyg_uint32 des1; + cyg_uint32 des2; + cyg_uint32 des3; + cyg_uint32 private; +}; + +// Some statistics +#ifdef CYGSEM_DEVS_ETH_CORTEXM_A2FXXX_STATS +typedef struct { + cyg_uint32 rx_mcast; + cyg_uint32 rx_des_err; + cyg_uint32 rx_collision; + cyg_uint32 rx_crc_err; + cyg_uint32 rx_too_long; + cyg_uint32 tx_fifo_underflow; + cyg_uint32 tx_frame_deferred; + cyg_uint32 tx_late_collision; + cyg_uint32 tx_no_carrier; + cyg_uint32 tx_loss_carrier; +} a2fxxx_eth_stats; +#endif + +// Internal data structure +struct a2fxxx_eth_info { + volatile struct a2fxxx_bd *txbd, + *rxbd; // Next Tx,Rx descriptor to use + volatile struct a2fxxx_bd *tbase, + *rbase; // First Tx,Rx descriptor + volatile struct a2fxxx_bd *tnext, + *rnext; // Next descriptor to check for interrupt + cyg_uint8 txactive; // Count of active Tx buffers + unsigned long txkey[CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_TxNUM]; + cyg_uint8 mac_address[6]; // mac (hardware) address + cyg_uint8 *init_rxbufs; // Initial base pointer of RX buffers + cyg_uint8 *init_txbufs; // Initial base pointer of TX buffers + volatile struct a2fxxx_bd *init_rxring; // Initial base pointer of RX ring + volatile struct a2fxxx_bd *init_txring; // Initial base pointer of TX ring + cyg_uint32 rx_mac[48]; // Setup frame (192) bytes + cyg_uint32 valid_mac; +#ifdef CYGSEM_DEVS_ETH_CORTEXM_A2FXXX_STATS + a2fxxx_eth_stats stats; // MAC statistics +#endif + cyg_uint32 base; // MAC base address + cyg_uint32 base_bb; // MAC base address (bit-band) + cyg_uint8 if_num; +#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED + cyg_uint8 vector; + cyg_interrupt interrupt; + cyg_handle_t interrupt_handle; +#endif +#ifdef CYGPKG_DEVS_ETH_PHY + eth_phy_access_t *phy; +#endif +}; + +static void a2fxxx_phy_init(void); +static bool a2fxxx_mdio_read(cyg_int32, cyg_int32, cyg_uint16 *); +static void a2fxxx_mdio_write(cyg_int32, cyg_int32, cyg_uint16); + +static void a2fxxx_eth_int(struct eth_drv_sc *data); + +#ifdef CYGDAT_DEVS_CORTEXM_A2FXXX_ETH_INL +# include CYGDAT_DEVS_CORTEXM_A2FXXX_ETH_INL +#endif + +#include <cyg/infra/diag.h> + +#ifdef CYGSEM_DEVS_ETH_CORTEXM_A2FXXX_CHATTER +# define a2fxxx_eth_printf(args...) diag_printf(args) +#else +# define a2fxxx_eth_printf(args...) /* NOOP */ +#endif + +// For fetching the ESA from RedBoot +#include <cyg/hal/hal_if.h> +#ifndef CONFIG_ESA +# define CONFIG_ESA 6 +#endif + +// ---------------------------------------------------------------- +// Definition +// +// + +#define RESET_FULL_DUPLEX 0x00000001 +#define RESET_100MB 0x00000002 + +#define MDIO_PREAMBLE_SEQ 0xffffffff +#define MDIO_START_SEQ 0x01 +#define MDIO_WRITE_SEQ 0x01 +#define MDIO_READ_SEQ 0x02 +#define MDIO_STOP_WRITE_SEQ 0x02 +#define MDIO_STOP_READ_SEQ 0x00 + +#define CYGHWR_HAL_A2FXXX_MAC_CSR5_TI_BB(_base_) \ + ( _base_ + ( CYGHWR_HAL_A2FXXX_MAC_CSR5 << 5 ) + ( 0*sizeof(cyg_uint32) ) ) +#define CYGHWR_HAL_A2FXXX_MAC_CSR5_RI_BB(_base_) \ + ( _base_ + ( CYGHWR_HAL_A2FXXX_MAC_CSR5 << 5 ) + ( 6*sizeof(cyg_uint32) ) ) +#define CYGHWR_HAL_A2FXXX_MAC_CSR5_NIS_BB(_base_) \ + ( _base_ + ( CYGHWR_HAL_A2FXXX_MAC_CSR5 << 5 ) + ( 16*sizeof(cyg_uint32) ) ) + +#define CYGHWR_HAL_A2FXXX_MAC_PRIVATE_SENT BIT_(0) + +#ifdef CYGSEM_DEVS_ETH_CORTEXM_A2FXXX_STATS +# define A2FXXX_INC_STATS(_x_) (qi->stats._x_++) +#endif + +// ---------------------------------------------------------------- +// MDIO API +// +// + +#define MDIO_XFER_BITS( reg, reg_val, sequence, length ) \ +{ \ + cyg_uint32 i; \ + for (i = (1 << (length-1)); i != 0; ) { \ + reg_val &= ~CYGHWR_HAL_A2FXXX_MAC_CSR9_MDC; \ + HAL_WRITE_UINT32( reg, reg_val ); \ + HAL_DELAY_US(1); \ + if( i & sequence ) \ + reg_val |= ( CYGHWR_HAL_A2FXXX_MAC_CSR9_MDO ); \ + else \ + reg_val &= ( ~CYGHWR_HAL_A2FXXX_MAC_CSR9_MDO ); \ + HAL_WRITE_UINT32( reg, reg_val ); \ + reg_val |= CYGHWR_HAL_A2FXXX_MAC_CSR9_MDC; \ + HAL_WRITE_UINT32( reg, reg_val ); \ + HAL_DELAY_US(1); \ + i = i >> 1; \ + } \ +} + +// +// Setup IOs +// +static void +a2fxxx_phy_init(void) +{ + a2fxxx_eth_printf("ETH A2Fxxx - PHY Init\n"); + CYGHWR_HAL_A2FXXX_GPIO_SET(CYGHWR_HAL_A2FXXX_MAC0_MDIO); + CYGHWR_HAL_A2FXXX_GPIO_SET(CYGHWR_HAL_A2FXXX_MAC0_MDC); +} + +// +// Start MDIO transfer -> 32 bits of preamble ('1'), start bits, +// transfer type bits, phy address and register address bits +// +static void +a2fxxx_mdio_xfer_start(cyg_bool rd, cyg_uint8 phy_addr, cyg_uint8 addr) +{ + cyg_uint32 csr9_reg = + (CYGHWR_HAL_A2FXXX_MAC + CYGHWR_HAL_A2FXXX_MAC_CSR9); + cyg_uint32 csr9_data, + bit_sequence; + + // Enable MDIO write + HAL_READ_UINT32(csr9_reg, csr9_data); + csr9_data |= + (CYGHWR_HAL_A2FXXX_MAC_CSR9_MDEN | CYGHWR_HAL_A2FXXX_MAC_CSR9_MDO | + CYGHWR_HAL_A2FXXX_MAC_CSR9_MDC); + HAL_WRITE_UINT32(csr9_reg, csr9_data); + HAL_DELAY_US(1); + + // Send preamble bits + bit_sequence = MDIO_PREAMBLE_SEQ; + MDIO_XFER_BITS(csr9_reg, csr9_data, bit_sequence, 32); + + // Send 2 start bits + bit_sequence = MDIO_START_SEQ; + MDIO_XFER_BITS(csr9_reg, csr9_data, bit_sequence, 2); + + // Send transfer type bits + bit_sequence = (rd == true) ? MDIO_READ_SEQ : MDIO_WRITE_SEQ; + MDIO_XFER_BITS(csr9_reg, csr9_data, bit_sequence, 2); + + // Send PHY address + bit_sequence = (cyg_uint32)phy_addr; + MDIO_XFER_BITS(csr9_reg, csr9_data, bit_sequence, 5); + + // Send register address + bit_sequence = (cyg_uint32)addr; + MDIO_XFER_BITS(csr9_reg, csr9_data, bit_sequence, 5); + + // Send TA sequence + if (rd == true) { + bit_sequence = MDIO_STOP_READ_SEQ; + csr9_data &= ~(CYGHWR_HAL_A2FXXX_MAC_CSR9_MDEN); + HAL_WRITE_UINT32(csr9_reg, csr9_data); + } else { + bit_sequence = MDIO_STOP_WRITE_SEQ; + } + MDIO_XFER_BITS(csr9_reg, csr9_data, bit_sequence, 2); + + // now we can read or write the 16 bits data ... +} + +// +// Read 16 bits data from MDIO interface +// +static cyg_bool +a2fxxx_mdio_xfer_read(cyg_uint16 *data) +{ + cyg_uint32 csr9_reg = + (CYGHWR_HAL_A2FXXX_MAC + CYGHWR_HAL_A2FXXX_MAC_CSR9); + cyg_uint32 csr9_data; + *data = 0; + int i; + + // Read MDIO register + HAL_READ_UINT32(csr9_reg, csr9_data); + + // Clock in the RX data + for (i = (1 << 15); i != 0;) { + csr9_data &= ~CYGHWR_HAL_A2FXXX_MAC_CSR9_MDC; + HAL_WRITE_UINT32(csr9_reg, csr9_data); + HAL_DELAY_US(1); + HAL_READ_UINT32(csr9_reg, csr9_data); + if (csr9_data & CYGHWR_HAL_A2FXXX_MAC_CSR9_MDI) + *data |= i; + csr9_data |= CYGHWR_HAL_A2FXXX_MAC_CSR9_MDC; + HAL_WRITE_UINT32(csr9_reg, csr9_data); + HAL_DELAY_US(1); + i = i >> 1; + } + + return true; +} + +// +// Write 16 bits data to MDIO interface +// +static bool +a2fxxx_mdio_xfer_write(cyg_uint16 data) +{ + cyg_uint32 csr9_reg = + (CYGHWR_HAL_A2FXXX_MAC + CYGHWR_HAL_A2FXXX_MAC_CSR9); + cyg_uint32 csr9_data, + bit_sequence; + + // Read MDIO register + HAL_READ_UINT32(csr9_reg, csr9_data); + + // Write data + bit_sequence = (cyg_uint32)data; + MDIO_XFER_BITS(csr9_reg, csr9_data, bit_sequence, 16); + + // Set back clock to low + csr9_data &= ~CYGHWR_HAL_A2FXXX_MAC_CSR9_MDC; + HAL_WRITE_UINT32(csr9_reg, csr9_data); + + return true; +} + +// +// MDIO read register +// +static bool +a2fxxx_mdio_read(cyg_int32 addr, cyg_int32 phy_addr, cyg_uint16 *data) +{ + bool res; + a2fxxx_mdio_xfer_start(true, phy_addr, addr); + res = a2fxxx_mdio_xfer_read(data); + a2fxxx_eth_printf("ETH A2Fxxx - PHY %x(%x) - RX data %x\n", phy_addr, addr, + *data); + return res; +} + +// +// MDIO write register +// +static void +a2fxxx_mdio_write(cyg_int32 addr, cyg_int32 phy_addr, cyg_uint16 data) +{ + a2fxxx_mdio_xfer_start(false, phy_addr, addr); + a2fxxx_eth_printf("ETH A2Fxxx - PHY %x(%x) - TX data %x\n", phy_addr, addr, + data); + a2fxxx_mdio_xfer_write(data); +} + + +// ---------------------------------------------------------------- +// Ethernet driver +// +// +#define A2FXXX_RESET_MAC( qi ) \ +{ \ + cyg_uint32 swr_addr = \ + qi->base_bb + (CYGHWR_HAL_A2FXXX_MAC_CSR0 << 5); \ + cyg_uint32 swr_data = 0x1; \ + HAL_WRITE_UINT32(swr_addr, swr_data); \ + do { \ + HAL_READ_UINT32(swr_addr, swr_data); \ + } while (swr_data); \ +} + +// +// Deliver function (ex-DSR) handles the Ethernet [logical] processing +// +static void +a2fxxx_eth_deliver(struct eth_drv_sc *sc) +{ +#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *)sc->driver_private; +#endif + a2fxxx_eth_int(sc); +#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED + // Allow interrupts to happen again + cyg_drv_interrupt_unmask(qi->vector); +#endif +} + +#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED +// +// This ISR is called when the Ethernet interrupt occurs +// +static int +a2fxxx_eth_isr(cyg_vector_t vector, cyg_addrword_t data, + HAL_SavedRegisters * regs) +{ + a2fxxx_eth_printf("ETH A2Fxxx - ISR\n"); + cyg_drv_interrupt_mask(vector); + cyg_drv_interrupt_acknowledge(vector); + + return (CYG_ISR_HANDLED | CYG_ISR_CALL_DSR); // Run the DSR +} + +void +a2fxxx_eth_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + a2fxxx_eth_deliver((struct eth_drv_sc *)data); + // Allow interrupts to happen again + cyg_drv_interrupt_unmask(vector); +} +#endif + +// +// This function add MAC address to the list of allowed MAC address +// that the MAC layer can deliver to the application layer +// +static bool +a2fxxx_eth_add_mac ( struct eth_drv_sc *sc, cyg_uint8 *mac ) +{ + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *)sc->driver_private; + cyg_uint8 idx = 12; + struct a2fxxx_bd setup_bd; + cyg_uint32 i, csr4, csr5, csr6, csr7; + + // If no MAC to be added, just re-send the setup frame + if( mac != NULL ) + { + // no more room + if( qi->valid_mac == (cyg_uint32) -1 ) + return false; + + // Search empty spot + while( qi->valid_mac & i ){ + i = i << 1; + idx += 12; + } + + qi->rx_mac[idx+0] = mac[0]; + qi->rx_mac[idx+1] = mac[1]; + qi->rx_mac[idx+4] = mac[2]; + qi->rx_mac[idx+5] = mac[3]; + qi->rx_mac[idx+8] = mac[4]; + qi->rx_mac[idx+9] = mac[6]; + } + + a2fxxx_eth_printf("ETH A2Fxxx - Send setup frame for %s\n", sc->dev_name); + + // Stop TX + HAL_READ_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR6), csr6); + csr6 &= ~( CYGHWR_HAL_A2FXXX_MAC_CSR6_ST ); + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR6), csr6); + + // Wait until controller is halted + do { + HAL_READ_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR5), csr5); + } while( ((csr5 & CYGHWR_HAL_A2FXXX_MAC_CSR5_TS_MASK) + != CYGHWR_HAL_A2FXXX_MAC_CSR5_TS_STOP) ); + + // Backup the current BD / interrupt mask + HAL_READ_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR4), csr4); + HAL_READ_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR7), csr7); + + // Disable interrupt + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR7), 0); + + // Setup descriptor for setup frame + setup_bd.des0 = CYGHWR_HAL_A2FXXX_MAC_TDES0_OWN; + setup_bd.des1 = CYGHWR_HAL_A2FXXX_MAC_TDES1_TER | + CYGHWR_HAL_A2FXXX_MAC_TDES1_SET | + CYGHWR_HAL_A2FXXX_MAC_TDES1_TBS1(192); + setup_bd.des2 = (cyg_uint32) &qi->rx_mac[0]; + setup_bd.des3 = (cyg_uint32) NULL; + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR4), + (cyg_uint32) &setup_bd); + + // Start transmission + csr6 |= ( CYGHWR_HAL_A2FXXX_MAC_CSR6_ST ); + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR6), csr6); + + // Poll for transmission completed + do { + HAL_READ_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR5), csr5); + } while( ((csr5 & A2FXXX_MAC_TX_STATE_MASK) != A2FXXX_MAC_TX_STATE(SUSPEND)) ); + + // Stop transmission + csr6 &= ~( CYGHWR_HAL_A2FXXX_MAC_CSR6_ST ); + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR6), csr6); + + // Wait until controller is halted + do { + HAL_READ_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR5), csr5); + } while( ((csr5 & CYGHWR_HAL_A2FXXX_MAC_CSR5_TS_MASK) + != CYGHWR_HAL_A2FXXX_MAC_CSR5_TS_STOP) ); + + // Restore BD + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR4), csr4); + + HAL_WRITE_UINT32( CYGHWR_HAL_A2FXXX_MAC_CSR5_TI_BB(qi->base_bb), 1); + + // Restore interrupt mask + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR7), csr7); + + return true; +} + +// +// [re]Initialize the Ethernet controller +// Done separately since shutting down the device requires a +// full reconfiguration when re-enabling. +// when +static bool +a2fxxx_eth_setup(struct eth_drv_sc *sc, unsigned char *enaddr, int flags) +{ + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *) sc->driver_private; + volatile struct a2fxxx_bd *rxbd, *txbd; + cyg_uint8 *RxBUF, *TxBUF; + cyg_uint32 csr0, csr6 = 0, csr11; + int i = 0; + + qi->valid_mac = 0; + qi->rx_mac[5] = enaddr[0]; + qi->rx_mac[4] = enaddr[1]; + qi->rx_mac[3] = enaddr[2]; + qi->rx_mac[2] = enaddr[3]; + qi->rx_mac[1] = enaddr[4]; + qi->rx_mac[0] = enaddr[5]; + + txbd = qi->init_txring; + rxbd = qi->init_rxring; + + /* Init Rx / Tx ring base */ + qi->tbase = qi->txbd = qi->tnext = txbd; + qi->rbase = qi->rxbd = qi->rnext = rxbd; + qi->txactive = 0; + + RxBUF = qi->init_rxbufs; + TxBUF = qi->init_txbufs; + + /* Initialize Rx BDs */ + for (i = 0; i < CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_RxNUM; i++) + { + rxbd->des0 = CYGHWR_HAL_A2FXXX_MAC_RDES0_OWN; + rxbd->des1 = + CYGHWR_HAL_A2FXXX_MAC_RDES1_RBS1(CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_ALIGN_BUFSIZE_RX); + rxbd->des2 = (cyg_uint32) RxBUF; + rxbd->des3 = (cyg_uint32) NULL; + RxBUF += CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_ALIGN_BUFSIZE_RX; + rxbd++; + } + rxbd--; + rxbd->des1 |= CYGHWR_HAL_A2FXXX_MAC_RDES1_RER; // Last buffer + + /* Initialize Tx BDs */ + for (i = 0; i < CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_TxNUM; i++) + { + txbd->des1 = 0; + txbd->des2 = (cyg_uint32) TxBUF; + rxbd->des3 = (cyg_uint32) NULL; + txbd->private = 0; + TxBUF += CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_ALIGN_BUFSIZE_TX; + txbd++; + } + txbd--; + txbd->des1 |= CYGHWR_HAL_A2FXXX_MAC_TDES1_TER; // Last buffer + + // Setup automatic polling + csr0 = CYGHWR_HAL_A2FXXX_MAC_CSR0_CLEAR | CYGHWR_HAL_A2FXXX_MAC_CSR0_TAP(3) | + CYGHWR_HAL_A2FXXX_MAC_CSR0_DSL(1); + + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR0), + (cyg_uint32) csr0); + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR3), + (cyg_uint32) (qi->rbase)); + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR4), + (cyg_uint32) (qi->tbase)); + + csr11 = CYGHWR_HAL_A2FXXX_MAC_CSR11_TT(7) | + CYGHWR_HAL_A2FXXX_MAC_CSR11_NTP(1) | + CYGHWR_HAL_A2FXXX_MAC_CSR11_RT(7) | + CYGHWR_HAL_A2FXXX_MAC_CSR11_NRP(1); + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR11), (cyg_uint32) csr11); + + HAL_READ_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR6), csr6); + csr6 |= CYGHWR_HAL_A2FXXX_MAC_CSR6_CLEAR; + + csr6 |= ((flags & RESET_100MB) ? CYGHWR_HAL_A2FXXX_MAC_CSR6_TTM : 0x0) | + ((flags & RESET_FULL_DUPLEX) ? CYGHWR_HAL_A2FXXX_MAC_CSR6_FD : 0x0); + +#ifdef CYGSEM_DEVS_ETH_CORTEXM_A2FXXX_PROMISCUOUS + csr6 |= CYGHWR_HAL_A2FXXX_MAC_CSR6_PR; +#endif + + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR6), csr6); + + return true; +} + +// +// This function is called to shut down the interface. +// +static void +a2fxxx_eth_stop(struct eth_drv_sc *sc) +{ + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *)sc->driver_private; + cyg_uint32 csr6, csr5; + + a2fxxx_eth_printf("ETH A2Fxxx - Stop\n"); + + // Stop RX / TX + HAL_READ_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR6), csr6); + csr6 &= ~( CYGHWR_HAL_A2FXXX_MAC_CSR6_SR | CYGHWR_HAL_A2FXXX_MAC_CSR6_ST ); + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR6), csr6); + + // Stall until controller is halted + do { + HAL_READ_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR5), csr5); + } while( ((csr5 & CYGHWR_HAL_A2FXXX_MAC_CSR5_TS_MASK) != CYGHWR_HAL_A2FXXX_MAC_CSR5_TS_STOP) && + ((csr5 & CYGHWR_HAL_A2FXXX_MAC_CSR5_RS_MASK) != CYGHWR_HAL_A2FXXX_MAC_CSR5_RS_STOP)); + +} + +// +// Setup Ethernet IOs. +// +static void +a2fxxx_eth_io(void) +{ + CYGHWR_HAL_A2FXXX_GPIO_SET(CYGHWR_HAL_A2FXXX_MAC0_TXD0); + CYGHWR_HAL_A2FXXX_GPIO_SET(CYGHWR_HAL_A2FXXX_MAC0_TXD1); + CYGHWR_HAL_A2FXXX_GPIO_SET(CYGHWR_HAL_A2FXXX_MAC0_RXD0); + CYGHWR_HAL_A2FXXX_GPIO_SET(CYGHWR_HAL_A2FXXX_MAC0_RXD1); + CYGHWR_HAL_A2FXXX_GPIO_SET(CYGHWR_HAL_A2FXXX_MAC0_TXEN); + CYGHWR_HAL_A2FXXX_GPIO_SET(CYGHWR_HAL_A2FXXX_MAC0_CRSDV); + CYGHWR_HAL_A2FXXX_GPIO_SET(CYGHWR_HAL_A2FXXX_MAC0_RXER); +} + +// +// Initialize the interface - performed at system startup +// This function must set up the interface, including arranging to +// handle interrupts, etc, so that it may be "started" cheaply later. +// +static bool +a2fxxx_eth_init(struct cyg_netdevtab_entry *tab) +{ + struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance; + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *)sc->driver_private; + cyg_uint32 speed100 = 0, full_duplex = 0; + bool esa_ok; + cyg_uint16 phy_state = 0; + cyg_uint32 istate, csr7; + bool ret = true; + + a2fxxx_eth_printf("ETH A2Fxxx - Initialization for %s\n", sc->dev_name); + + // Release MAC controller + CYGHWR_HAL_A2FXXX_PERIPH_RELEASE(CYGHWR_HAL_A2FXXX_PERIPH_SOFTRST(MAC)); + + // Setup IOs + a2fxxx_eth_io(); + + // Reset MAC + A2FXXX_RESET_MAC( qi ); + + HAL_DISABLE_INTERRUPTS(istate); + + a2fxxx_eth_stop(sc); + +#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED + cyg_drv_interrupt_create(qi->vector, + CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_ISR_PRIORITY, + (cyg_addrword_t)sc, // Data item passed to interrupt handler + (cyg_ISR_t *)a2fxxx_eth_isr, + (cyg_DSR_t *)eth_drv_dsr, + &qi->interrupt_handle, &qi->interrupt); + cyg_drv_interrupt_attach(qi->interrupt_handle); + cyg_drv_interrupt_unmask(qi->vector); +#endif + + esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET, + "a2fxxx_esa", enaddr, CONFIG_ESA); + + if (!esa_ok) { + a2fxxx_eth_printf("ETH A2Fxxx - Warning! ESA unknown for %s\n", sc->dev_name); + memcpy(&enaddr, &qi->mac_address, sizeof(enaddr)); + } + +#ifdef CYGPKG_DEVS_ETH_PHY + if (!_eth_phy_init(qi->phy)) { + a2fxxx_eth_printf("ETH A2Fxxx - Failed to initialize PHY of %s\n", + sc->dev_name); + ret = false; + goto exit; + } + phy_state = _eth_phy_state(qi->phy); + + if (phy_state & ETH_PHY_STAT_100MB) + speed100 = 1; + if (phy_state & ETH_PHY_STAT_FDX) + full_duplex = 1; + if (phy_state & ETH_PHY_STAT_LINK) { + a2fxxx_eth_printf("Ethernet Mode (%s): %sMbps/%s\n", + sc->dev_name, + (speed100 ? "100" : "10"), + (full_duplex ? "Full" : "Half")); + } else { + a2fxxx_eth_printf("ETH A2Fxxx - NO LINK on %s\n", sc->dev_name); + } +#else + a2fxxx_eth_printf("ETH A2Fxxx - No PHY interface specified for %s\n", + sc->dev_name); + ret = false; + goto exit; +#endif + + if (!a2fxxx_eth_setup(sc, enaddr, (full_duplex ? RESET_FULL_DUPLEX + : 0x00000000) | (speed100 ? RESET_100MB : 0x00000000))) + { + ret = false; + goto exit; + } + + a2fxxx_eth_add_mac( sc, NULL ); + + HAL_WRITE_UINT32( CYGHWR_HAL_A2FXXX_MAC_CSR5_RI_BB(qi->base_bb), 1); + HAL_WRITE_UINT32( CYGHWR_HAL_A2FXXX_MAC_CSR5_TI_BB(qi->base_bb), 1); + + csr7 = ( CYGHWR_HAL_A2FXXX_MAC_CSR7_TIE | CYGHWR_HAL_A2FXXX_MAC_CSR7_RIE | + CYGHWR_HAL_A2FXXX_MAC_CSR7_NIE); + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR7), csr7); + + HAL_WRITE_UINT32( CYGHWR_HAL_A2FXXX_MAC_CSR5_NIS_BB(qi->base_bb), + (cyg_uint32) 0x1); + + // Call upper layer initialization + (sc->funs->eth_drv->init)(sc, (unsigned char *) &enaddr); + +exit: + HAL_RESTORE_INTERRUPTS(istate); + return ret; +} + +// +// This function is called to "start up" the interface. It may be called +// multiple times, even when the hardware is already running. It will be +// called whenever something "hardware oriented" changes and should leave +// the hardware ready to send/receive packets. +// +static void +a2fxxx_eth_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags) +{ + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *)sc->driver_private; + cyg_uint32 csr6; + + a2fxxx_eth_printf("ETH A2Fxxx - Start\n"); + + // Stop RX / TX + HAL_READ_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR6), csr6); + csr6 |= ( CYGHWR_HAL_A2FXXX_MAC_CSR6_SR | CYGHWR_HAL_A2FXXX_MAC_CSR6_ST ); + HAL_WRITE_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR6), csr6); +} + +// +// This function is called for low level "control" operations +// +static int +a2fxxx_eth_control(struct eth_drv_sc *sc, unsigned long key, + void *data, int length) +{ + switch (key) + { + case ETH_DRV_SET_MAC_ADDRESS: + return 0; + break; +#ifdef ETH_DRV_SET_MC_ALL + case ETH_DRV_SET_MC_ALL: + case ETH_DRV_SET_MC_LIST: + // TODO + return 0; + break; +#endif + default: + return 1; + break; + } +} + +// +// This function is called to see if another packet can be sent. +// It should return the number of packets which can be handled. +// Zero should be returned if the interface is busy and can not send any more. +// +static int +a2fxxx_eth_can_send(struct eth_drv_sc *sc) +{ + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *) sc->driver_private; + + return (qi->txactive < CYGNUM_DEVS_ETH_CORTEXM_A2FXXX_TxNUM); +} + +// +// This routine is called to send data to the hardware. +static void +a2fxxx_eth_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, + int sg_len, int total_len, unsigned long key) +{ + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *) sc->driver_private; + volatile struct a2fxxx_bd *txbd, *txfirst; + cyg_uint32 des1 = CYGHWR_HAL_A2FXXX_MAC_TDES1_TBS1(total_len); + volatile cyg_uint8 *bp; + cyg_int32 i, txindex, istate; + + a2fxxx_eth_printf("ETH A2Fxxx - transmit pkt, length %d\n", total_len); + + // Continue from current descriptor + txbd = txfirst = qi->txbd; + + if ( (txbd->des0 & CYGHWR_HAL_A2FXXX_MAC_TDES0_OWN) == CYGHWR_HAL_A2FXXX_MAC_TDES0_OWN ) { + a2fxxx_eth_printf("ETH A2Fxxx - Fatal error, no free BD for %s\n", + sc->dev_name); + a2fxxx_eth_printf("ETH A2Fxxx - Cannot transmit packet, active pkt in queue:%d\n", + qi->txactive); + return; + } + + // Set up buffer + bp = (cyg_uint8 *) txbd->des2; + for (i = 0; i < sg_len; i++) { + memcpy((void *) bp, (void *) sg_list[i].buf, sg_list[i].len); + bp += sg_list[i].len; + } + + if (txbd->des1 & CYGHWR_HAL_A2FXXX_MAC_TDES1_TER) { + des1 |= CYGHWR_HAL_A2FXXX_MAC_TDES1_TER; + } + txbd->des1 = + ( des1 | CYGHWR_HAL_A2FXXX_MAC_TDES1_LS | CYGHWR_HAL_A2FXXX_MAC_TDES1_FS | + CYGHWR_HAL_A2FXXX_MAC_TDES1_IC ); + txindex = ((unsigned long) txbd - (unsigned long) qi->tbase) + / sizeof(*txbd); + qi->txkey[txindex] = key; + + qi->txactive++; + + HAL_DISABLE_INTERRUPTS(istate); + // Give ownership to the MAC + txbd->des0 = CYGHWR_HAL_A2FXXX_MAC_TDES0_OWN; + txbd->private = CYGHWR_HAL_A2FXXX_MAC_PRIVATE_SENT; + + // Remember the next buffer to try + if (qi->txbd->des1 & CYGHWR_HAL_A2FXXX_MAC_TDES1_TER){ + qi->txbd = qi->tbase; + } + else { + qi->txbd++; + } + HAL_RESTORE_INTERRUPTS(istate); +} + +// +// This function is called for low level "control" operations +// +static void +a2fxxx_eth_TxEvent(struct eth_drv_sc *sc) +{ + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *) sc->driver_private; + volatile struct a2fxxx_bd *txbd; + int key, txindex; + + txbd = qi->tnext; + + while ( ( (txbd->des0 & CYGHWR_HAL_A2FXXX_MAC_TDES0_OWN ) == 0) && + (txbd->private & CYGHWR_HAL_A2FXXX_MAC_PRIVATE_SENT) ) + { + txindex = ((unsigned long) txbd - (unsigned long) qi->tbase) + / sizeof(*txbd); + if ((key = qi->txkey[txindex]) != 0) + { + qi->txkey[txindex] = 0; + (sc->funs->eth_drv->tx_done)(sc, key, 0); + } + qi->txactive--; +#ifdef CYGSEM_DEVS_ETH_CORTEXM_A2FXXX_STATS + if( (txbd->des0 & CYGHWR_HAL_A2FXXX_MAC_TDES0_LC) ) { + A2FXXX_INC_STATS(tx_late_collision); + } + if( (txbd->des0 & CYGHWR_HAL_A2FXXX_MAC_TDES0_NC) ) { + A2FXXX_INC_STATS(tx_no_carrier); + } + if( (txbd->des0 & CYGHWR_HAL_A2FXXX_MAC_TDES0_LO) ) { + A2FXXX_INC_STATS(tx_loss_carrier); + } + if( (txbd->des0 & CYGHWR_HAL_A2FXXX_MAC_TDES0_DE) ) { + A2FXXX_INC_STATS(tx_frame_deferred); + } + if( (txbd->des0 & CYGHWR_HAL_A2FXXX_MAC_TDES0_UF) ) { + A2FXXX_INC_STATS(tx_fifo_underflow); + } +#endif + txbd->private &= ~CYGHWR_HAL_A2FXXX_MAC_PRIVATE_SENT; + if (txbd->des1 & CYGHWR_HAL_A2FXXX_MAC_TDES1_TER){ + txbd = qi->tbase; + } else { + txbd++; + } + } + // Remember where we left off + qi->tnext = (struct a2fxxx_bd *) txbd; +} + +// +// Interrupt vector +// +static int +a2fxxx_eth_int_vector(struct eth_drv_sc *sc) +{ +#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *) sc->driver_private; + return (qi->vector); +#else + return 0; +#endif +} + +// +// This function is called when a packet has been received. It's job is +// to prepare to unload the packet from the hardware. Once the length of +// the packet is known, the upper layer of the driver can be told. When +// the upper layer is ready to unload the packet, the internal function +// 'fec_eth_recv' will be called to actually fetch it from the hardware. +// +static void +a2fxxx_eth_RxEvent(struct eth_drv_sc *sc) +{ + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *) sc->driver_private; + volatile struct a2fxxx_bd *rxbd, *rxfirst; + int cnt_bd = 0; + cyg_int32 len; + + rxbd = rxfirst = qi->rnext; + while ((rxbd->des0 & CYGHWR_HAL_A2FXXX_MAC_RDES0_OWN) == 0) + { + cnt_bd++; + qi->rxbd = rxbd; // Save for callback + +#ifdef CYGSEM_DEVS_ETH_CORTEXM_A2FXXX_STATS + if( (rxbd->des0 & CYGHWR_HAL_A2FXXX_MAC_RDES0_CE) ) { + A2FXXX_INC_STATS(rx_crc_err); + } + if( (rxbd->des0 & CYGHWR_HAL_A2FXXX_MAC_RDES0_CS) ) { + A2FXXX_INC_STATS(rx_collision); + } + if( (rxbd->des0 & CYGHWR_HAL_A2FXXX_MAC_RDES0_TL) ) { + A2FXXX_INC_STATS(rx_too_long); + } + if( (rxbd->des0 & CYGHWR_HAL_A2FXXX_MAC_RDES0_MF) ) { + A2FXXX_INC_STATS(rx_mcast); + } + if( (rxbd->des0 & CYGHWR_HAL_A2FXXX_MAC_RDES0_DE) ) { + A2FXXX_INC_STATS(rx_des_err); + } +#endif + + len = (rxbd->des0 >> 16) & 0x3fff; + a2fxxx_eth_printf("ETH A2Fxxx - Receive pkt, length %d\n", len); + + (sc->funs->eth_drv->recv)(sc, len - 4); + if (rxbd->des1 & CYGHWR_HAL_A2FXXX_MAC_RDES1_RER){ + rxbd = qi->rbase; + } else { + rxbd++; + } + } + // Remember where we left off + qi->rnext = (struct a2fxxx_bd *) rxbd; +} + +// +// Interrupt processing +// +static void +a2fxxx_eth_int(struct eth_drv_sc *sc) +{ + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *) sc->driver_private; + cyg_uint32 csr5; + + // Check interrupt status + HAL_READ_UINT32( (qi->base + CYGHWR_HAL_A2FXXX_MAC_CSR5), csr5); + + if (( csr5 & CYGHWR_HAL_A2FXXX_MAC_CSR5_TI ) != 0) + { + a2fxxx_eth_printf("%s - Transmit packet irq\n", sc->dev_name); + a2fxxx_eth_TxEvent(sc); + HAL_WRITE_UINT32( CYGHWR_HAL_A2FXXX_MAC_CSR5_TI_BB(qi->base_bb), 1); + } + + if (( csr5 & CYGHWR_HAL_A2FXXX_MAC_CSR5_RI ) != 0) + { + a2fxxx_eth_printf("%s - Receive packet irq\n", sc->dev_name); + a2fxxx_eth_RxEvent(sc); + HAL_WRITE_UINT32( CYGHWR_HAL_A2FXXX_MAC_CSR5_RI_BB(qi->base_bb), 1); + } +} + +// +// Polling function +// +static void +a2fxxx_eth_poll(struct eth_drv_sc *sc) +{ + a2fxxx_eth_int(sc); + CYGACC_CALL_IF_DELAY_US(500); +} + +static void +a2fxxx_eth_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len) +{ + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *) sc->driver_private; + cyg_uint8 *bp; + int i; + + bp = (cyg_uint8 *) qi->rxbd->des2; + for (i = 0; i < sg_len; i++) + { + if (sg_list[i].buf != 0) + { + memcpy((void *) sg_list[i].buf, bp, sg_list[i].len); + bp += sg_list[i].len; + } + } + qi->rxbd->des0 |= CYGHWR_HAL_A2FXXX_MAC_RDES0_OWN; +} + + +// +// Display ETH statistics +// +#ifdef CYGSEM_DEVS_ETH_CORTEXM_A2FXXX_STATS +externC void +a2fxxx_disp_stats(struct eth_drv_sc *sc , char flag ) +{ + struct a2fxxx_eth_info *qi = (struct a2fxxx_eth_info *) sc->driver_private; + + diag_printf("Ethernet Statistics\n"); + + diag_printf("%17s %10d\n", + "RX MCAST", + qi->stats.rx_mcast); + diag_printf("%17s %10d\n", + "RX DESC ERR", + qi->stats.rx_des_err); + diag_printf("%17s %10d\n", + "RX COLLISION", + qi->stats.rx_collision); + diag_printf("%17s %10d\n", + "RX CRC ERR", + qi->stats.rx_crc_err); + diag_printf("%17s %10d\n", + "RX TOO LONG", + qi->stats.rx_too_long); + diag_printf("%17s %10d\n", + "TX FIFO UNDERFLOW", + qi->stats.tx_fifo_underflow); + diag_printf("%17s %10d\n", + "TX FRAME DEFERRED", + qi->stats.tx_frame_deferred); + diag_printf("%17s %10d\n", + "TX LATE COLLISION", + qi->stats.tx_late_collision); + diag_printf("%17s %10d\n", + "TX NO CARRIER", + qi->stats.tx_no_carrier); + diag_printf("%17s %10d\n", + "TX LOSS CARRIER", + qi->stats.tx_loss_carrier); +} +#endif + +// EOF if_a2fxxx.c
