This is the mail archive of the ecos-patches@sourceware.org mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]