This is the mail archive of the
ecos-patches@sourceware.org
mailing list for the eCos project.
AT91 Eth driver
- From: Andrew Lunn <andrew at lunn dot ch>
- To: eCos Patches <ecos-patches at ecos dot sourceware dot org>
- Date: Mon, 5 Mar 2007 20:06:50 +0100
- Subject: AT91 Eth driver
Attached is the AT91 Ethernet drive written by John Eigelaar and
myself.
Andrew
Index: ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/ChangeLog,v
retrieving revision 1.177
diff -u -r1.177 ChangeLog
--- ChangeLog 18 Jan 2007 09:18:50 -0000 1.177
+++ ChangeLog 5 Mar 2007 19:02:33 -0000
@@ -1,5 +1,11 @@
+2007-02-13 John Eigelaar <jeigelaar@mweb.co.za>
+ Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * ecos.db: Ethernet device driver for AT91 EMAC.
+
2007-01-10 Ilija Koco <ilijak@siva.com.mk>
- * ecos.db: Splitted esci directory in esci/drv and esci/hdr
+
+ * ecos.db: Splitted esci directory in esci/drv and esci/hdr
2007-01-02 Uwe Kindler <uwe_kindler@web.de>
Index: NEWS
===================================================================
RCS file: /cvs/ecos/ecos/packages/NEWS,v
retrieving revision 1.103
diff -u -r1.103 NEWS
--- NEWS 21 Sep 2006 17:03:53 -0000 1.103
+++ NEWS 5 Mar 2007 19:02:34 -0000
@@ -1,3 +1,4 @@
+* AT91 Ethernet device driver for EMAC by John Eigelaar and Andrew Lunn.
* MMC/SPI driver provided by eCosCentric Ltd.
* USB device driver for Philips D12.
* Port to ATMEL AT91SAM7X by John Eigelaar
Index: ecos.db
===================================================================
RCS file: /cvs/ecos/ecos/packages/ecos.db,v
retrieving revision 1.163
diff -u -r1.163 ecos.db
--- ecos.db 18 Jan 2007 09:18:50 -0000 1.163
+++ ecos.db 5 Mar 2007 19:02:42 -0000
@@ -4204,6 +4204,16 @@
Davicom DM9000 ethernet interface."
}
+
+package CYGPKG_DEVS_ETH_ARM_AT91 {
+ alias { "AT91 Ethernet driver" at91_eth_driver }
+ directory devs/eth/arm/at91
+ script at91_eth.cdl
+ hardware
+ description "Ethernet driver for the AT91 family of chips"
+}
+
+
# --------------------------------------------------------------------------
# ==========================================================================
@@ -4396,8 +4406,8 @@
CYGPKG_DEVICES_WATCHDOG_ARM_AT91WDTC
CYGPKG_DEVS_USB_AT91
CYGPKG_DEVS_ETH_PHY
+ CYGPKG_DEVS_ETH_ARM_AT91
}
-# CYGPKG_DEVS_ETH_ARM_AT91
description "
The at91sam7xek target provides the packages needed to run eCos on an
Atmel AT91SAM7X-EK evaluation board."
Index: devs/eth/arm/at91/current/ChangeLog
===================================================================
RCS file: devs/eth/arm/at91/current/ChangeLog
diff -N devs/eth/arm/at91/current/ChangeLog
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ devs/eth/arm/at91/current/ChangeLog 5 Mar 2007 19:02:43 -0000
@@ -0,0 +1,42 @@
+2007-01-17 John Eigelaar <jeigelaar@mweb.co.za>
+
+ * src/if_at91.c * include/at91_eth.cdl: Working implementation
+ of a device driver for the AT91 EMAC device.
+
+2006-06-02 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * src/if_at91.c * include/at91_eth.cdl: Partially implementation
+ of a device driver for the AT91 EMAC device.
+
+//===========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright 2006 Andrew Lunn
+//
+// 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.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+//
+// 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####
+//===========================================================================
Index: devs/eth/arm/at91/current/cdl/at91_eth.cdl
===================================================================
RCS file: devs/eth/arm/at91/current/cdl/at91_eth.cdl
diff -N devs/eth/arm/at91/current/cdl/at91_eth.cdl
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ devs/eth/arm/at91/current/cdl/at91_eth.cdl 5 Mar 2007 19:02:43 -0000
@@ -0,0 +1,164 @@
+#==========================================================================
+#
+# at91_eth.cdl
+#
+# Ethernet drivers for Atmel AT91 Cores
+#
+#==========================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+## Copyright (C) 2002 Jonathan Larmour
+## Copyright (C) 2006 Andrew Lunn
+##
+## 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.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+##
+## 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): Andrew Lunn
+# Contributors:
+# Date: 2006-05-10
+# Purpose:
+# Description:
+#
+#####DESCRIPTIONEND####
+#
+#========================================================================*/
+
+cdl_package CYGPKG_DEVS_ETH_ARM_AT91 {
+ display "Atmel AT91 ethernet driver"
+ parent CYGPKG_IO_ETH_DRIVERS
+ active_if CYGPKG_IO_ETH_DRIVERS
+ implements CYGHWR_NET_DRIVERS
+ implements CYGHWR_NET_DRIVER_ETH0
+
+ include_dir net
+ description "
+ Ethernet driver for Atmel AT91 core. This has been tested with the
+ AT91SAM7X, but should be easy to get to work on other AT91 cores that
+ have the EMAC core."
+
+ compile -library=libextras.a if_at91.c
+
+ cdl_option CYGPKG_DEVS_ETH_ARM_AT91_DEBUG_LEVEL {
+ display "AT91RM9200 device driver debug output level"
+ flavor data
+ legal_values {0 1 2}
+ default_value 1
+ description "
+ This option specifies the level of debug data output by
+ the AT91 ethernet device driver. A value of 0 signifies
+ no debug data output; 1 signifies normal debug data
+ output; and 2 signifies maximum debug data output (not
+ suitable when GDB and application are sharing an ethernet
+ port)."
+ }
+
+ cdl_option CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS {
+ display "Number of RX buffers"
+ flavor data
+ default_value 32
+ description "
+ Number of receive buffers. Each buffer is 128 bytes in size"
+ }
+
+ cdl_option CYGNUM_DEVS_ETH_ARM_AT91_TX_BUFS {
+ display "Number of TX buffers"
+ flavor data
+ default_value 10
+ description "
+ Number of transmit buffer descriptors. We need one descriptor
+ for each element in the scatter/gather list."
+ }
+
+ cdl_option CYGPKG_DEVS_ETH_ARM_AT91_PHYADDR {
+ display "PHY MII address"
+ flavor data
+ legal_values 0 to 31
+ default_value 1
+ description "This option specifies the MII address of the PHY"
+ }
+
+ cdl_component CYGPKG_DEVS_ETH_ARM_AT91_REDBOOT_HOLDS_ESA {
+ display "RedBoot manages ESA initialization data"
+ flavor bool
+ default_value 0
+
+ active_if CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
+ active_if (CYGPKG_REDBOOT || CYGSEM_HAL_USE_ROM_MONITOR)
+
+ description "
+ Enabling this option will allow the ethernet station
+ address to be acquired from RedBoot's configuration data,
+ stored in flash memory. It can be overridden individually
+ by the 'Set the ethernet station address' option for each
+ interface."
+
+
+ cdl_component CYGPKG_DEVS_ETH_ARM_AT91_REDBOOT_HOLDS_ESA_VARS {
+ display "Export RedBoot command to set ESA in FLASH config"
+ flavor none
+ no_define
+ description "
+ This component contains options which, when enabled, allow
+ RedBoot to support the setting of the ESA in the FLASH
+ configuration. This can then subsequently be accessed by
+ applications using virtual vector calls if those applications
+ are also built with
+ CYGPKG_DEVS_ETH_ARM_AT91_REDBOOT_HOLDS_ESA enabled."
+
+ cdl_option CYGSEM_DEVS_ETH_ARM_AT91_REDBOOT_HOLDS_ESA_ETH0 {
+ display "RedBoot manages ESA for eth0"
+ flavor bool
+ default_value 1
+ active_if CYGSEM_REDBOOT_FLASH_CONFIG
+ active_if CYGPKG_REDBOOT_NETWORKING
+ }
+ }
+ }
+ cdl_option CYGPKG_DEVS_ETH_ARM_AT91_MACADDR {
+ display "Ethernet station (MAC) address for eth0"
+ flavor data
+ default_value {"0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC"}
+ description "The default ethernet station address. This is the
+ MAC address used when no value is found in the
+ RedBoot FLASH configuration field."
+ }
+
+ cdl_option CYGPKG_DEVS_ETH_ARM_AT91_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 Atmel AT91 ethernet driver package.
+ These flags are used in addition to the set of global flags."
+ }
+}
+
+# EOF at91_eth.cdl
Index: devs/eth/arm/at91/current/src/if_at91.c
===================================================================
RCS file: devs/eth/arm/at91/current/src/if_at91.c
diff -N devs/eth/arm/at91/current/src/if_at91.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ devs/eth/arm/at91/current/src/if_at91.c 5 Mar 2007 19:02:44 -0000
@@ -0,0 +1,980 @@
+//==========================================================================
+//
+// if_at91.c
+//
+//
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2006 Andrew Lunn <andrew.lunn@ascom.ch>
+//
+// 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.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+//
+// 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): Andrew Lunn, John Eigelaar
+// Contributors:
+// Date: 2006-05-10
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//========================================================================*/
+
+#include <pkgconf/system.h>
+#include <pkgconf/hal.h>
+#include <pkgconf/devs_eth_arm_at91.h>
+#include <pkgconf/io_eth_drivers.h>
+#if defined(CYGPKG_REDBOOT)
+ #include <pkgconf/redboot.h>
+#endif
+
+#include <cyg/hal/hal_io.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/drv_api.h>
+#include <cyg/hal/hal_diag.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/diag.h>
+#include <cyg/io/eth/netdev.h>
+#include <cyg/io/eth/eth_drv.h>
+#include <cyg/io/eth/eth_drv_stats.h>
+#include <cyg/io/eth_phy.h>
+#include <errno.h>
+#include <string.h>
+
+// Set up the level of debug output
+#if CYGPKG_DEVS_ETH_ARM_AT91_DEBUG_LEVEL > 0
+ #define debug1_printf(args...) diag_printf(args)
+#else
+ #define debug1_printf(args...)
+#endif
+#if CYGPKG_DEVS_ETH_ARM_AT91_DEBUG_LEVEL > 1
+ #define debug2_printf(args...) diag_printf(args)
+#else
+ #define debug2_printf(args...)
+#endif
+
+//Driver interface callbacks
+#define _eth_drv_init(sc,mac) \
+ (sc->funs->eth_drv->init)(sc,(unsigned char *)mac)
+#define _eth_drv_tx_done(sc,key,status) \
+ (sc->funs->eth_drv->tx_done)(sc,key,status)
+#define _eth_drv_recv(sc,len) \
+ (sc->funs->eth_drv->recv)(sc,len)
+
+#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+static cyg_uint32
+at91_eth_isr (cyg_vector_t vector, cyg_addrword_t data);
+#endif
+
+// --------------------------------------------------------------
+// RedBoot configuration options for managing ESAs for us
+
+// Decide whether to have redboot config vars for it...
+#if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGPKG_REDBOOT_NETWORKING)
+ #include <redboot.h>
+ #include <flash_config.h>
+
+ #ifdef CYGSEM_DEVS_ETH_ARM_AT91_REDBOOT_HOLDS_ESA_ETH0
+RedBoot_config_option("Network hardware address [MAC] for eth0",
+ eth0_esa_data,
+ ALWAYS_ENABLED, true,
+ CONFIG_ESA, 0);
+ #endif
+
+#endif // CYGPKG_REDBOOT_NETWORKING && CYGSEM_REDBOOT_FLASH_CONFIG
+
+// and initialization code to read them
+// - independent of whether we are building RedBoot right now:
+#ifdef CYGPKG_DEVS_ETH_ARM_AT91_REDBOOT_HOLDS_ESA
+
+ #include <cyg/hal/hal_if.h>
+
+ #ifndef CONFIG_ESA
+ #define CONFIG_ESA (6)
+ #endif
+
+ #define CYGHWR_DEVS_ETH_ARM_AT91_GET_ESA( mac_address, ok ) \
+ CYG_MACRO_START \
+ ok = CYGACC_CALL_IF_FLASH_CFG_OP( CYGNUM_CALL_IF_FLASH_CFG_GET, \
+ "eth0_esa_data", \
+ mac_address, \
+ CONFIG_ESA); \
+ CYG_MACRO_END
+
+#endif // CYGPKG_DEVS_ETH_AT91_ETH_REDBOOT_HOLDS_ESA
+
+//============================================================================
+
+// Private Data structures
+
+#ifndef AT91_EMAC_RX_BUFF_SIZE
+#define AT91_EMAC_RX_BUFF_SIZE 128
+#endif
+
+// Receive Buffer Descriptor
+typedef struct rbd_s
+{
+ cyg_uint32 addr;
+ cyg_uint32 sr;
+} rbd_t;
+
+// Receive Buffer
+typedef struct rb_s
+{
+ cyg_uint8 rb[AT91_EMAC_RX_BUFF_SIZE];
+} rb_t;
+
+// Transmit Buffer Descriptor
+typedef struct tbd_s
+{
+ cyg_uint32 addr;
+ cyg_uint32 sr;
+} tbd_t;
+
+// AT91 Ethernet private data
+typedef struct at91_eth_priv_s
+{
+ cyg_uint32 intr_vector;
+ char *esa_key; // RedBoot 'key' for device ESA
+ cyg_uint8 *enaddr;
+ cyg_uint32 base; // Base address of device
+ eth_phy_access_t *phy;
+ rbd_t rbd[CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS];
+ rb_t rb[CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS];
+ tbd_t tbd[CYGNUM_DEVS_ETH_ARM_AT91_TX_BUFS];
+ unsigned long curr_tx_key;
+ cyg_bool tx_busy;
+ cyg_uint32 curr_tbd_idx;
+ cyg_uint32 curr_rbd_idx;
+#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+ cyg_interrupt intr;
+ cyg_handle_t intr_handle;
+#endif
+} at91_eth_priv_t;
+
+//============================================================================
+// PHY access bits and pieces
+//
+
+static void
+at91_mdio_enable(void)
+{
+ cyg_uint32 val;
+ HAL_READ_UINT32(AT91_EMAC + AT91_EMAC_NCR, val);
+ val |= AT91_EMAC_NCR_MPE; /* enable management port */
+ HAL_WRITE_UINT32(AT91_EMAC + AT91_EMAC_NCR, val);
+}
+
+static void
+at91_mdio_disable(void)
+{
+ cyg_uint32 val;
+ HAL_READ_UINT32(AT91_EMAC + AT91_EMAC_NCR, val);
+ val &= ~AT91_EMAC_NCR_MPE; /* disable management port */
+ HAL_WRITE_UINT32(AT91_EMAC + AT91_EMAC_NCR, val);
+}
+
+// Write one of the PHY registers via the MII bus
+static void
+at91_write_phy(int reg_addr, int phy_addr, unsigned short data)
+{
+ cyg_uint32 val, cnt=0;
+
+ CYG_ASSERTC(reg_addr >= 0 && reg_addr <= AT91_EMAC_MAN_REGA_MASK);
+ CYG_ASSERTC(phy_addr >= 0 && phy_addr <= AT91_EMAC_MAN_PHY_MASK);
+
+ val = (AT91_EMAC_MAN_SOF |
+ AT91_EMAC_MAN_WR |
+ AT91_EMAC_MAN_CODE |
+ AT91_EMAC_MAN_PHYA(phy_addr) |
+ AT91_EMAC_MAN_REGA(reg_addr) |
+ AT91_EMAC_MAN_DATA(data));
+
+ HAL_WRITE_UINT32(AT91_EMAC + AT91_EMAC_MAN, val);
+
+ /* Wait until IDLE bit in Network Status register is cleared */
+ while (cnt < 1000000)
+ {
+ HAL_READ_UINT32((AT91_EMAC + AT91_EMAC_NSR), val);
+ if (!(val & AT91_EMAC_NSR_IDLE))
+ break;
+ }
+ CYG_ASSERTC(cnt < 1000000);
+}
+
+
+// Read one of the PHY registers via the MII bus
+static bool
+at91_read_phy(int reg_addr, int phy_addr, unsigned short *data)
+{
+ cyg_uint32 val;
+
+ CYG_ASSERTC(reg_addr >= 0 && reg_addr <= AT91_EMAC_MAN_REGA_MASK);
+ CYG_ASSERTC(phy_addr >= 0 && phy_addr <= AT91_EMAC_MAN_PHY_MASK);
+
+ val = (AT91_EMAC_MAN_SOF |
+ AT91_EMAC_MAN_RD |
+ AT91_EMAC_MAN_CODE |
+ AT91_EMAC_MAN_PHYA(phy_addr) |
+ AT91_EMAC_MAN_REGA(reg_addr));
+
+
+ HAL_WRITE_UINT32(AT91_EMAC + AT91_EMAC_MAN, val);
+ /* Wait until IDLE bit in Network Status register is cleared */
+ do
+ {
+ HAL_READ_UINT32((AT91_EMAC + AT91_EMAC_NSR), val);
+ }while(val & AT91_EMAC_NSR_IDLE);
+
+ HAL_DELAY_US(50);
+
+ HAL_READ_UINT32(AT91_EMAC + AT91_EMAC_MAN, val);
+ *data = val & AT91_EMAC_MAN_DATA_MASK;
+
+ return (true);
+}
+
+// Enable the MDIO bit in MAC control register so that we can talk to
+// the PHY. Also set the clock divider so that MDC is less than 2.5MHz.
+static void
+at91_init_phy(void)
+{
+ cyg_uint32 cfg;
+ cyg_uint32 div;
+
+ HAL_READ_UINT32(AT91_EMAC + AT91_EMAC_NCFG, cfg);
+ cfg &=~ AT91_EMAC_NCFG_CLK_MASK;
+
+ div = (CYGNUM_HAL_ARM_AT91_CLOCK_SPEED / 2500000);
+ if (div < 8)
+ {
+ cfg |= AT91_EMAC_NCFG_CLK_HCLK_8;
+ }
+ else if (div < 16)
+ {
+ cfg |= AT91_EMAC_NCFG_CLK_HCLK_16;
+ }
+ else if (div < 32)
+ {
+ cfg |= AT91_EMAC_NCFG_CLK_HCLK_32;
+ }
+ else if (div < 64)
+ {
+ cfg |= AT91_EMAC_NCFG_CLK_HCLK_64;
+ }
+ else
+ {
+ CYG_FAIL("Unable to program MII clock");
+ }
+
+ HAL_WRITE_UINT32(AT91_EMAC + AT91_EMAC_NCFG, cfg);
+}
+
+ETH_PHY_REG_LEVEL_ACCESS_FUNS(at91_phy,
+ at91_init_phy,
+ NULL,
+ at91_write_phy,
+ at91_read_phy);
+
+//======================================================================
+// Receiver buffer handling
+
+// Initialize the receiver buffers and descriptors
+static void
+at91_rb_init(at91_eth_priv_t *priv)
+{
+ int i;
+ for (i = 0 ; i < CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS; i++)
+ {
+ priv->rbd[i].addr = ((cyg_uint32)&priv->rb[i]) & AT91_EMAC_RBD_ADDR_MASK;
+ priv->rbd[i].sr = 0;
+ }
+ // Set the wrap bit on the last entry
+ priv->rbd[CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS-1].addr |=
+ AT91_EMAC_RBD_ADDR_WRAP;
+}
+
+//======================================================================
+// Transmit buffer handling
+
+// Initialize the transmit buffer descriptors
+static void
+at91_tb_init(at91_eth_priv_t *priv)
+{
+ int i;
+ for (i = 0 ; i < CYGNUM_DEVS_ETH_ARM_AT91_TX_BUFS; i++)
+ {
+ priv->tbd[i].addr = 0;
+ priv->tbd[i].sr = AT91_EMAC_TBD_SR_USED;
+ }
+ // Set the wrap bit on the last entry
+ priv->tbd[CYGNUM_DEVS_ETH_ARM_AT91_TX_BUFS-1].sr |= AT91_EMAC_TBD_SR_WRAP;
+}
+
+//======================================================================
+// Enable and Disable of the receiver and transmitter.
+
+static void
+at91_disable_rx(at91_eth_priv_t *priv)
+{
+ cyg_uint32 ctl;
+
+ HAL_READ_UINT32(priv->base + AT91_EMAC_NCR, ctl);
+ ctl &= ~AT91_EMAC_NCR_RE;
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_NCR, ctl);
+}
+
+static void
+at91_disable_tx(at91_eth_priv_t *priv)
+{
+ cyg_uint32 ctl;
+
+ HAL_READ_UINT32(priv->base + AT91_EMAC_NCR, ctl);
+ ctl &= ~AT91_EMAC_NCR_TX;
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_NCR, ctl);
+}
+
+static void
+at91_enable_rx(at91_eth_priv_t *priv)
+{
+ cyg_uint32 ctl;
+
+ HAL_READ_UINT32(priv->base + AT91_EMAC_NCR, ctl);
+ ctl |= AT91_EMAC_NCR_RE;
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_NCR, ctl);
+}
+
+static void
+at91_enable_tx(at91_eth_priv_t *priv)
+{
+ cyg_uint32 ctl;
+
+ HAL_READ_UINT32(priv->base + AT91_EMAC_NCR, ctl);
+ ctl |= AT91_EMAC_NCR_TX;
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_NCR, ctl);
+}
+
+static void
+at91_enable(at91_eth_priv_t *priv)
+{
+ at91_enable_tx(priv);
+ at91_enable_rx(priv);
+}
+
+static void
+at91_disable(at91_eth_priv_t *priv)
+{
+ at91_disable_tx(priv);
+ at91_disable_rx(priv);
+}
+
+static void
+at91_start_transmitter(at91_eth_priv_t *priv)
+{
+ cyg_uint32 ctl;
+
+ HAL_READ_UINT32(priv->base + AT91_EMAC_NCR, ctl);
+ ctl |= AT91_EMAC_NCR_TSTART;
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_NCR, ctl);
+}
+
+
+//======================================================================
+// Initialization code
+
+// Configure the pins so that the EMAC has control of them. This
+// assumes the MII is used, not the RMII
+static void
+at91_cfg_pins(void)
+{
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_EREFCK);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ECRS);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ECOL);
+
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ERXDV);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ERX0);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ERX1);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ERX2);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ERX3);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ERXER);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ERXCK);
+
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ETXEN);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ETX0);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ETX1);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ETX2);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ETX3);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_ETXER);
+
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_EMDC);
+ HAL_ARM_AT91_PIO_CFG(AT91_EMAC_EMDIO);
+}
+
+// Set a specific address match to a given address. Packets received which
+// match this address will be passed on.
+static void
+at91_set_mac(at91_eth_priv_t * priv, cyg_uint8 * enaddr, int sa)
+{
+ cyg_uint32 hi, lo;
+
+ CYG_ASSERTC(sa > 0 && sa < 5);
+ sa--;
+
+ lo = ((enaddr[3] << 24) |
+ (enaddr[2] << 16) |
+ (enaddr[1] << 8) |
+ (enaddr[0]));
+
+ hi = ((enaddr[5] << 8) |
+ (enaddr[4]));
+
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_SA1L + (8*sa), lo);
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_SA1H + (8*sa), hi);
+}
+
+static void
+at91_clear_stats(at91_eth_priv_t *priv)
+{
+ cyg_uint32 ctl;
+
+ HAL_READ_UINT32(priv->base + AT91_EMAC_NCR, ctl);
+ ctl |= AT91_EMAC_NCR_CSR;
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_NCR, ctl);
+}
+
+// Enable and Disable of the receiver and transmitter.
+// Initialize the interface. This configures the interface ready for use.
+// Interrupts are grabbed etc. This means the start function has
+// little to do except enable the receiver
+static bool
+at91_eth_init(struct cyg_netdevtab_entry *tab)
+{
+ struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
+ at91_eth_priv_t *priv = (at91_eth_priv_t *)sc->driver_private;
+ bool esa_ok = false;
+ unsigned char enaddr[6] = { CYGPKG_DEVS_ETH_ARM_AT91_MACADDR};
+ unsigned char enzero[6] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+ unsigned short phy_state = 0;
+ cyg_uint32 ncfg = 0;
+
+ debug1_printf("\nAT91_ETH: Initialising @ %x\n",priv->base);
+
+ priv->tx_busy = false;
+ priv->curr_tbd_idx = 0;
+ priv->curr_rbd_idx = 0;
+
+ // Enable the clock to the EMAC
+ HAL_WRITE_UINT32(AT91_PMC + AT91_PMC_PCER, AT91_PMC_PCER_EMAC);
+ HAL_WRITE_UINT32(AT91_PMC + AT91_PMC_PCER, AT91_PMC_PCER_PIOB);
+ HAL_WRITE_UINT32(AT91_PMC + AT91_PMC_PCER, AT91_PMC_PCER_PIOA);
+
+ //at91_disable(priv);
+ at91_cfg_pins();
+
+ /* Enable IO Clock */
+ HAL_WRITE_UINT32(priv->base+AT91_EMAC_USRIO,AT91_EMAC_USRIO_CLKEN);
+
+ /* Disable all the interrupts for the moment */
+ /* The Start function actually enables all that we need */
+ //HAL_WRITE_UINT32(priv->base + AT91_EMAC_IDR, 0x3FFF);
+
+ // If we are building an interrupt enabled version, install the
+ // interrupt handler
+#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+ debug1_printf("AT91_ETH: Installing Interrupts on IRQ %d\n",
+ priv->intr_vector);
+ cyg_drv_interrupt_create(priv->intr_vector,
+ 4,
+ (cyg_addrword_t)sc,
+ at91_eth_isr,
+ eth_drv_dsr,
+ &priv->intr_handle,
+ &priv->intr);
+
+ cyg_drv_interrupt_attach(priv->intr_handle);
+ cyg_drv_interrupt_unmask(priv->intr_vector);
+#endif
+
+#ifdef CYGHWR_DEVS_ETH_ARM_AT91_GET_ESA
+ // Get MAC address from RedBoot configuration variables
+ CYGHWR_DEVS_ETH_ARM_AT91_GET_ESA(&enaddr[0], esa_ok);
+ // If this call fails myMacAddr is unchanged and MAC address from
+ // CDL is used
+#endif
+
+ if (!esa_ok)
+ {
+ // Can't figure out ESA
+ debug1_printf("AT91_ETH - Warning! ESA unknown\n");
+ }
+ debug1_printf("AT91_ETH: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ enaddr[0],enaddr[1],enaddr[2],
+ enaddr[3],enaddr[4],enaddr[5]);
+
+ // Give the EMAC its address
+ at91_set_mac(priv, enaddr, 1);
+ at91_set_mac(priv, enzero, 2);
+ at91_set_mac(priv, enzero, 3);
+ at91_set_mac(priv, enzero, 4);
+
+ // Setup the receiver buffers and descriptors
+ at91_rb_init(priv);
+
+ // And tell the EMAC where the first receive buffer descriptor is
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_RBQP, (cyg_uint32)priv->rbd);
+
+ // Setup the transmit descriptors
+ at91_tb_init(priv);
+
+ // And tell the EMAC where the first transmit buffer descriptor is
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_TBQP, (cyg_uint32)priv->tbd);
+
+ // Setup the PHY
+ CYG_ASSERTC(priv->phy);
+
+ at91_mdio_enable();
+ if (!_eth_phy_init(priv->phy))
+ {
+ at91_mdio_disable();
+ return (false);
+ }
+
+ // Get the current mode and print it
+ phy_state = _eth_phy_state(priv->phy);
+ at91_mdio_disable();
+
+ HAL_READ_UINT32(priv->base + AT91_EMAC_NCFG,ncfg);
+
+
+ if ((phy_state & ETH_PHY_STAT_LINK) != 0)
+ {
+ if (((phy_state & ETH_PHY_STAT_100MB) != 0))
+ {
+ debug1_printf("AT91_ETH: 100Mbyte/s");
+ ncfg |= AT91_EMAC_NCFG_SPD_100Mbps;
+ }
+ else
+ {
+ debug1_printf("AT91_ETH: 10Mbyte/s");
+ ncfg &= ~(AT91_EMAC_NCFG_SPD_100Mbps);
+ }
+ if((phy_state & ETH_PHY_STAT_FDX))
+ {
+ debug1_printf(" Full Duplex\n");
+ ncfg |= AT91_EMAC_NCFG_FD;
+ }
+ else
+ {
+ debug1_printf(" Half Duplex\n");
+ ncfg &= ~(AT91_EMAC_NCFG_FD);
+ }
+ }
+ else
+ {
+ debug1_printf("AT91_ETH: No Link\n");
+ }
+
+
+ //Setup the network configuration
+ ncfg |= (AT91_EMAC_NCFG_RLCE);
+
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_NCFG,ncfg);
+
+ // Clear the Statistics counters;
+ at91_clear_stats(priv);
+
+
+ /* Clear the status registers */
+ HAL_READ_UINT32(priv->base + AT91_EMAC_ISR,ncfg);
+ HAL_READ_UINT32(priv->base + AT91_EMAC_RSR,ncfg);
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_RSR,ncfg);
+ HAL_READ_UINT32(priv->base + AT91_EMAC_TSR,ncfg);
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_TSR,ncfg);
+
+ // Initialize the upper layer driver
+ _eth_drv_init(sc,enaddr);
+
+ return (true);
+}
+
+// This function is called to stop the interface.
+static void
+at91_eth_stop(struct eth_drv_sc *sc)
+{
+ at91_eth_priv_t *priv = (at91_eth_priv_t *)sc->driver_private;
+
+ at91_disable(priv);
+}
+
+// This function is called to "start up" the interface. It may be called
+// multiple times, even when the hardware is already running.
+static void
+at91_eth_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
+{
+ at91_eth_priv_t *priv = (at91_eth_priv_t *)sc->driver_private;
+ cyg_uint32 bits;
+
+ // Enable the interrupts we are interested in
+ // TODO: We probably need to add at least the RBNA interrupt here
+ // as well in order to do some error handling
+ bits = (AT91_EMAC_ISR_RCOM | AT91_EMAC_ISR_TCOM);
+
+ HAL_WRITE_UINT32(priv->base + AT91_EMAC_IER, bits);
+
+ // Enable the receiver and transmitter
+ at91_enable(priv);
+}
+
+// This function is called for low level "control" operations
+static int
+at91_eth_control(struct eth_drv_sc *sc, unsigned long key,
+ void *data, int length)
+{
+ diag_printf("%s.%d: key %lx\n", __FUNCTION__, __LINE__, key);
+ return (1);
+}
+
+// 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.
+//
+// We allocate one buffer descriptor per scatter/gather entry. We assume that
+// a typical packet will not have more than 3 such entries, and so we say we
+// can send a packet when we have 3 or more buffer descriptors free
+//
+// TODO: Implement what the comment actually says!
+static int
+at91_eth_can_send(struct eth_drv_sc *sc)
+{
+ int can_send;
+ at91_eth_priv_t *priv = (at91_eth_priv_t *)sc->driver_private;
+ if(priv->tx_busy)
+ {
+ can_send = 0;
+ }
+ else
+ {
+ can_send = 1;
+ }
+ return (can_send);
+}
+
+// This routine is called to send data to the hardware
+static void
+at91_eth_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
+ int total_len, unsigned long key)
+{
+ at91_eth_priv_t *priv = (at91_eth_priv_t *)sc->driver_private;
+ int i;
+ cyg_uint32 sr;
+
+ priv->tx_busy = true;
+ for(i = 0;i<sg_len;i++)
+ {
+ priv->tbd[priv->curr_tbd_idx].addr = sg_list[i].buf;
+
+ sr = (sg_list[i].len & AT91_EMAC_TBD_SR_LEN_MASK);
+ // Set the End Of Frame bit in the last descriptor
+ if(i == (sg_len-1))
+ {
+ sr |= AT91_EMAC_TBD_SR_EOF;
+ }
+
+ if(priv->curr_tbd_idx < (CYGNUM_DEVS_ETH_ARM_AT91_TX_BUFS-1))
+ {
+ priv->tbd[priv->curr_tbd_idx].sr = sr;
+ priv->curr_tbd_idx++;
+ }
+ else
+ {
+ priv->tbd[priv->curr_tbd_idx].sr = (sr | AT91_EMAC_TBD_SR_WRAP);
+ priv->curr_tbd_idx = 0;
+ }
+ }
+
+ // Store away the key for when the transmit has completed
+ // and we need to tell the stack which transmit has completed.
+ priv->curr_tx_key = key;
+
+ at91_start_transmitter(priv);
+}
+
+//======================================================================
+
+#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
+static cyg_uint32
+at91_eth_isr (cyg_vector_t vector, cyg_addrword_t data)
+{
+ struct eth_drv_sc *sc = (struct eth_drv_sc *)data;
+ at91_eth_priv_t *priv = (at91_eth_priv_t *)sc->driver_private;
+ cyg_uint32 ret;
+ cyg_uint32 isr;
+
+ /* Get the interrupt status */
+ HAL_READ_UINT32(priv->base+AT91_EMAC_ISR,isr);
+
+ ret = CYG_ISR_HANDLED;
+
+ //TODO: We should probably be handling some of the error interrupts as well
+ if(isr & AT91_EMAC_ISR_TCOM)
+ {
+ ret = CYG_ISR_CALL_DSR;
+ }
+
+ if(isr & AT91_EMAC_ISR_RCOM)
+ {
+ ret = CYG_ISR_CALL_DSR;
+ }
+ cyg_interrupt_acknowledge(vector);
+ return(ret);
+}
+#endif
+
+static void
+at91_eth_deliver(struct eth_drv_sc *sc)
+{
+ at91_eth_priv_t *priv = (at91_eth_priv_t *)sc->driver_private;
+
+ cyg_uint32 tsr;
+ cyg_uint32 rsr;
+
+ cyg_uint32 ctr;
+ cyg_uint32 cnt;
+ cyg_uint32 idx;
+
+ /* Get the Transmit Status */
+ HAL_READ_UINT32(priv->base+AT91_EMAC_TSR,tsr);
+ HAL_WRITE_UINT32(priv->base+AT91_EMAC_TSR,tsr);
+
+ /* Get the Receive Status */
+ HAL_READ_UINT32(priv->base+AT91_EMAC_RSR,rsr);
+ HAL_WRITE_UINT32(priv->base+AT91_EMAC_RSR,rsr);
+
+
+ //TODO: The interrupts other than RCOMP and TCOMP needs to be
+ // handled properly especially stuff like RBNA which could have
+ // serious effects on driver performance
+
+ /* Service the TX buffers */
+ if (tsr&AT91_EMAC_TSR_COL) //1
+ {
+ debug1_printf("AT91_ETH: Tx COL\n");
+ }
+
+ if (tsr&AT91_EMAC_TSR_RLE) //2
+ {
+ debug1_printf("AT91_ETH: Tx RLE\n");
+ }
+
+ if (tsr&AT91_EMAC_TSR_BNQ) //4
+ {
+ debug1_printf("AT91_ETH: Tx BEX\n");
+ }
+
+ if (tsr&AT91_EMAC_TSR_UND) //6
+ {
+ debug1_printf("AT91_ETH: Tx UND\n");
+ }
+
+ /* Check that the last transmission is completed */
+ if (tsr&AT91_EMAC_TSR_COMP) //5
+ {
+ _eth_drv_tx_done(sc,priv->curr_tx_key,0);
+ priv->tx_busy = false;
+ }
+
+ /* Service the RX buffers when we get something */
+ if (rsr&AT91_EMAC_RSR_REC)
+ {
+ /* Do this all until we find the first EMAC Buffer */
+ while (priv->rbd[priv->curr_rbd_idx].addr & AT91_EMAC_RBD_ADDR_OWNER_SW)
+ {
+
+ //Firstly walk through to either the first buffer that belongs
+ // to the controller or the first SOF
+ while ((priv->rbd[priv->curr_rbd_idx].addr &
+ AT91_EMAC_RBD_ADDR_OWNER_SW) &&
+ !(priv->rbd[priv->curr_rbd_idx].sr &
+ AT91_EMAC_RBD_SR_SOF))
+ {
+ priv->rbd[priv->curr_rbd_idx].addr &=
+ ~(AT91_EMAC_RBD_ADDR_OWNER_SW);
+ priv->curr_rbd_idx++;
+ if (priv->curr_rbd_idx >= CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS)
+ {
+ priv->curr_rbd_idx = 0;
+ }
+ }
+
+ /* Check that we did find a SOF*/
+ if ((priv->rbd[priv->curr_rbd_idx].addr &
+ AT91_EMAC_RBD_ADDR_OWNER_SW) &&
+ (priv->rbd[priv->curr_rbd_idx].sr & AT91_EMAC_RBD_SR_SOF))
+ {
+ cnt = 0;
+ for (ctr=0;ctr<CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS;ctr++)
+ {
+ idx = (ctr+priv->curr_rbd_idx)%CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS;
+ cnt += (priv->rbd[idx].sr & AT91_EMAC_RBD_SR_LEN_MASK);
+ if (priv->rbd[idx].sr & AT91_EMAC_RBD_SR_EOF)
+ {
+ /* The recv function will adjust the current buffer idx
+ after the buffer has been cleared
+ */
+ if (cnt)
+ _eth_drv_recv(sc,cnt);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (rsr&AT91_EMAC_RSR_BNA)
+ {
+ debug1_printf("AT91_ETH: Rx BNA\n");
+ }
+ if (rsr&AT91_EMAC_RSR_OVR)
+ {
+ debug1_printf("AT91_ETH: Rx OVR\n");
+ }
+
+}
+
+static void
+at91_eth_recv(struct eth_drv_sc *sc,
+ struct eth_drv_sg *sg_list,
+ int sg_len)
+{
+ at91_eth_priv_t *priv = (at91_eth_priv_t *)sc->driver_private;
+ int i;
+ cyg_uint32 bytes_in_buffer;
+ cyg_uint32 bytes_in_list = 0;
+ cyg_uint32 bytes_needed_list = 0;
+ cyg_uint32 buffer_pos = 0;
+ cyg_uint8 * sg_buf;
+ cyg_uint32 total_bytes = 0;
+
+ for(i = 0;i<sg_len;i++)
+ {
+ while(bytes_in_list < sg_list[i].len)
+ {
+ bytes_needed_list = sg_list[i].len - bytes_in_list;
+
+ if(priv->rbd[priv->curr_rbd_idx].sr & AT91_EMAC_RBD_SR_EOF)
+ {
+ bytes_in_buffer =
+ ((priv->rbd[priv->curr_rbd_idx].sr & AT91_EMAC_RBD_SR_LEN_MASK)
+ - total_bytes) - buffer_pos;
+ }
+ else
+ {
+ bytes_in_buffer = AT91_EMAC_RX_BUFF_SIZE - buffer_pos;
+ }
+
+ sg_buf = (cyg_uint8 *)(sg_list[i].buf);
+
+ if(bytes_needed_list < bytes_in_buffer)
+ {
+ if(sg_buf != NULL)
+ memcpy(&sg_buf[bytes_in_list],
+ &priv->rb[priv->curr_rbd_idx].rb[buffer_pos],
+ bytes_needed_list);
+ bytes_in_list += bytes_needed_list;
+ buffer_pos += bytes_needed_list;
+ total_bytes += bytes_needed_list;
+ }
+ else
+ {
+ if(sg_buf != NULL)
+ memcpy(&sg_buf[bytes_in_list],
+ &priv->rb[priv->curr_rbd_idx].rb[buffer_pos],
+ bytes_in_buffer);
+ bytes_in_list += bytes_in_buffer;
+ total_bytes += bytes_in_buffer;
+
+ /* Step our buffer on one */
+ priv->rbd[priv->curr_rbd_idx].addr &=
+ ~(AT91_EMAC_RBD_ADDR_OWNER_SW);
+ priv->curr_rbd_idx++;
+ if(priv->curr_rbd_idx >= CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS)
+ {
+ priv->curr_rbd_idx = 0;
+ }
+ buffer_pos = 0;
+ }
+ }
+ }
+}
+
+// routine called to handle ethernet controller in polled mode
+static void
+at91_eth_poll(struct eth_drv_sc *sc)
+{
+ /* Service the buffers */
+ at91_eth_deliver(sc);
+}
+
+static int
+at91_eth_int_vector(struct eth_drv_sc *sc)
+{
+ return(CYGNUM_HAL_INTERRUPT_EMAC);
+}
+
+at91_eth_priv_t at91_priv_data =
+{
+ .intr_vector = CYGNUM_HAL_INTERRUPT_EMAC,
+ .base = AT91_EMAC,
+ .phy = &at91_phy
+};
+
+ETH_DRV_SC(at91_sc,
+ &at91_priv_data, // Driver specific data
+ "eth0", // Name for this interface
+ at91_eth_start,
+ at91_eth_stop,
+ at91_eth_control,
+ at91_eth_can_send,
+ at91_eth_send,
+ at91_eth_recv,
+ at91_eth_deliver,
+ at91_eth_poll,
+ at91_eth_int_vector);
+
+NETDEVTAB_ENTRY(at91_netdev,
+ "at91",
+ at91_eth_init,
+ &at91_sc);
+
+// EOF if_at91.c
Index: hal/arm/at91/at91sam7s/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/arm/at91/at91sam7s/current/ChangeLog,v
retrieving revision 1.10
diff -u -r1.10 ChangeLog
--- hal/arm/at91/at91sam7s/current/ChangeLog 7 Jan 2007 15:22:52 -0000 1.10
+++ hal/arm/at91/at91sam7s/current/ChangeLog 5 Mar 2007 19:02:50 -0000
@@ -1,3 +1,9 @@
+2007-01-17 John Eigelaar <jeigelaar@mweb.co.za>
+
+ * include/plf_io.h
+ * src/at91sam7s_misc.c
+ Added code to initialise the platform ethernet hardware if need be
+
2007-01-02 Uwe Kindler <uwe_kindler@web.de>
* cdl/hal_arm_at91sam7s.cdl Moved HAL_PLATFORM_XXX defines and
Index: hal/arm/at91/at91sam7s/current/include/plf_io.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/arm/at91/at91sam7s/current/include/plf_io.h,v
retrieving revision 1.6
diff -u -r1.6 plf_io.h
--- hal/arm/at91/at91sam7s/current/include/plf_io.h 9 Sep 2006 13:26:05 -0000 1.6
+++ hal/arm/at91/at91sam7s/current/include/plf_io.h 5 Mar 2007 19:02:50 -0000
@@ -62,6 +62,9 @@
#define AT91_SPI AT91_SPI0
+//Extra SPI control bits
+#define AT91_SPI_MR_MODFDIS (1<<4)
+
// DMA registers
#define AT91_SPI_RPR 0x100 // Receive Pointer Register
#define AT91_SPI_RCR 0x104 // Receive Counter Register
@@ -188,8 +191,14 @@
extern void hal_plf_hardware_init(void);
#define HAL_PLF_HARDWARE_INIT() \
hal_plf_hardware_init()
+
+#ifdef CYGHWR_HAL_ARM_AT91SAM7X
+extern void hal_plf_eth_init(void);
+#define HAL_PLF_ETH_INIT() \
+ hal_plf_eth_init()
#endif
+#endif //__ASSEMBLER__
#endif //CYGONCE_HAL_PLF_IO_H
Index: hal/arm/at91/at91sam7s/current/src/at91sam7s_misc.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/arm/at91/at91sam7s/current/src/at91sam7s_misc.c,v
retrieving revision 1.4
diff -u -r1.4 at91sam7s_misc.c
--- hal/arm/at91/at91sam7s/current/src/at91sam7s_misc.c 2 Jun 2006 18:15:29 -0000 1.4
+++ hal/arm/at91/at91sam7s/current/src/at91sam7s_misc.c 5 Mar 2007 19:02:50 -0000
@@ -120,6 +120,17 @@
watchdog driver, hence the conditional compilation. */
HAL_WRITE_UINT32(AT91_WDTC + AT91_WDTC_WDMR, AT91_WDTC_WDMR_DIS);
#endif
+
+/* Perform some platform specific bits to get the Ethernet hardware
+ setup. Specifically if a specific phy is used and does not start in
+ the correct mode a function needs to be supplied as part of the plf
+ to do the necessary initializations.
+*/
+#ifdef CYGPKG_DEVS_ETH_ARM_AT91
+#ifdef HAL_PLF_ETH_INIT
+ HAL_PLF_ETH_INIT();
+#endif
+#endif
}
// Calculate the baud value to be programmed into the serial port baud
Index: hal/arm/at91/at91sam7xek/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/arm/at91/at91sam7xek/current/ChangeLog,v
retrieving revision 1.2
diff -u -r1.2 ChangeLog
--- hal/arm/at91/at91sam7xek/current/ChangeLog 7 Jan 2007 15:23:26 -0000 1.2
+++ hal/arm/at91/at91sam7xek/current/ChangeLog 5 Mar 2007 19:02:50 -0000
@@ -1,3 +1,8 @@
+2007-01-17 John Eigelaar <jeigelaar@mweb.co.za>
+
+ * Added hal_plf_eth_init() in order to initialise the Davicom
+ 9161A PHY properly on the Evaluation board
+
2007-01-02 Uwe Kindler <uwe_kindler@web.de>
* cdl/hal_arm_at91sam7s.cdl Moved HAL_PLATFORM_XXX defines and
Index: hal/arm/at91/at91sam7xek/current/cdl/hal_arm_at91sam7xek.cdl
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/arm/at91/at91sam7xek/current/cdl/hal_arm_at91sam7xek.cdl,v
retrieving revision 1.2
diff -u -r1.2 hal_arm_at91sam7xek.cdl
--- hal/arm/at91/at91sam7xek/current/cdl/hal_arm_at91sam7xek.cdl 7 Jan 2007 15:23:26 -0000 1.2
+++ hal/arm/at91/at91sam7xek/current/cdl/hal_arm_at91sam7xek.cdl 5 Mar 2007 19:02:51 -0000
@@ -58,7 +58,10 @@
requires { CYGHWR_HAL_ARM_AT91 == "AT91SAM7S" }
requires { CYGHWR_HAL_ARM_AT91SAM7 == "at91sam7x256" ||
CYGHWR_HAL_ARM_AT91SAM7 == "at91sam7x128" }
-
+
+ requires { is_active(CYGPKG_DEVS_ETH_PHY) implies
+ (1 == CYGHWR_DEVS_ETH_PHY_DM9161A) }
+
define_proc {
puts $::cdl_system_header "#define CYGBLD_HAL_PLATFORM_H <pkgconf/hal_arm_at91sam7xek.h>"
puts $::cdl_header "/***** proc output start *****/"
Index: hal/arm/at91/at91sam7xek/current/src/at91sam7xek_misc.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/arm/at91/at91sam7xek/current/src/at91sam7xek_misc.c,v
retrieving revision 1.1
diff -u -r1.1 at91sam7xek_misc.c
--- hal/arm/at91/at91sam7xek/current/src/at91sam7xek_misc.c 2 Jun 2006 18:22:47 -0000 1.1
+++ hal/arm/at91/at91sam7xek/current/src/at91sam7xek_misc.c 5 Mar 2007 19:02:51 -0000
@@ -73,5 +73,41 @@
HAL_ARM_AT91_GPIO_PUT(AT91_GPIO_PB22, !(val & 8));
}
+void hal_plf_eth_init(void)
+{
+ cyg_uint32 stat;
+
+ /* Enable the PIOB Clock */
+ HAL_WRITE_UINT32(AT91_PMC + AT91_PMC_PCER, AT91_PMC_PCER_PIOB);
+
+ /* RXDV / Testmode select */
+ HAL_ARM_AT91_GPIO_CFG_DIRECTION(AT91_GPIO_PB15, AT91_PIN_IN);
+ HAL_ARM_AT91_GPIO_CFG_PULLUP(AT91_GPIO_PB15, AT91_PIN_PULLUP_DISABLE);
+
+ //TODO: The errata reports that the RMII mode for the SAM7X does not work.
+ // It would probably still be a good idea to use the RMII/MII CDL
+ // configuration to select the appropriate mode here
+ /* COL / !MII select */
+ HAL_ARM_AT91_GPIO_CFG_DIRECTION(AT91_GPIO_PB16, AT91_PIN_IN);
+ HAL_ARM_AT91_GPIO_CFG_PULLUP(AT91_GPIO_PB16, AT91_PIN_PULLUP_DISABLE);
+
+ /* TXCLK / ISOLATE */
+ HAL_ARM_AT91_GPIO_CFG_DIRECTION(AT91_GPIO_PB0, AT91_PIN_IN);
+ HAL_ARM_AT91_GPIO_CFG_PULLUP(AT91_GPIO_PB0, AT91_PIN_PULLUP_DISABLE);
+
+ /* Power Down Mode */
+ HAL_ARM_AT91_GPIO_CFG_DIRECTION(AT91_GPIO_PB18, AT91_PIN_OUT);
+ HAL_ARM_AT91_GPIO_PUT(AT91_GPIO_PB19,0);
+
+ /* All the lines setup correctly. Now do a external reset and let the phy
+ start up in the correct mode */
+ HAL_WRITE_UINT32(AT91_RST+AT91_RST_RMR,AT91_RST_RMR_KEY|(1<<0x8));
+ HAL_WRITE_UINT32(AT91_RST+AT91_RST_RCR,AT91_RST_RCR_KEY|AT91_RST_RCR_EXTRST);
+
+ do {
+ HAL_READ_UINT32(AT91_RST+AT91_RST_RSR,stat);
+ } while (!(stat&AT91_RST_RSR_NRST_SET));
+}
+
//--------------------------------------------------------------------------
// EOF at91sam7sek_misc.c