]> Zhao Yanbai Git Server - minix.git/commitdiff
Lan8710 driver initial version, after first review 87/687/6
authorMichal Maka <mmaka@jpembedded.eu>
Wed, 24 Jul 2013 13:07:28 +0000 (15:07 +0200)
committerBen Gras <ben@minix3.org>
Sun, 4 Aug 2013 21:31:05 +0000 (21:31 +0000)
Change-Id: If00cf1e098da5875eb040f8765273a6fa5e43e33

distrib/sets/lists/minix/md.evbarm
drivers/Makefile
drivers/lan8710a/Makefile [new file with mode: 0644]
drivers/lan8710a/README.txt [new file with mode: 0644]
drivers/lan8710a/lan8710a.c [new file with mode: 0644]
drivers/lan8710a/lan8710a.conf [new file with mode: 0644]
drivers/lan8710a/lan8710a.h [new file with mode: 0644]
drivers/lan8710a/lan8710a_reg.h [new file with mode: 0644]

index 70d70eaa9f193c514c6eeeadb4a1148d5285f219..bf52cea7c0c2e711c245dd8973a0c2e381feac8c 100644 (file)
@@ -4,6 +4,7 @@
 ./boot/minix/.temp/mod10_vm            minix-sys
 ./boot/minix/.temp/mod11_pfs           minix-sys
 ./boot/minix/.temp/mod12_init          minix-sys
+./etc/system.conf.d/lan8710a           minix-sys
 ./multiboot/mod07_log                  minix-sys
 ./multiboot/mod08_tty                  minix-sys
 ./multiboot/mod09_mfs                  minix-sys
 ./usr/sbin/fb                          minix-sys
 ./usr/sbin/gpio                                minix-sys
 ./usr/sbin/i2c                         minix-sys
+./usr/sbin/lan8710a                    minix-sys
 ./usr/sbin/random                      minix-sys
 ./usr/sbin/tda19988                    minix-sys
 ./usr/tests/minix-posix/mod            minix-sys
index 3a5e7c3530af0f4db6aa8140aa47997665e5eca5..1053102852fbf8cc96f7e460a55f7bf93cda9d43 100644 (file)
@@ -23,7 +23,7 @@ SUBDIR= ahci amddev atl2 at_wini audio dec21140A dp8390 dpeth \
 .endif
 
 .if ${MACHINE_ARCH} == "earm"
-SUBDIR=  cat24c256 fb gpio i2c mmc log tda19988 tty random
+SUBDIR=  cat24c256 fb gpio i2c mmc log tda19988 tty random lan8710a
 .endif
 
 .endif # ${MKIMAGEONLY} != "yes"
diff --git a/drivers/lan8710a/Makefile b/drivers/lan8710a/Makefile
new file mode 100644 (file)
index 0000000..8e5a932
--- /dev/null
@@ -0,0 +1,16 @@
+# Makefile for the lan8710a ethernet driver.
+PROG=   lan8710a
+SRCS=   lan8710a.c
+
+FILES=$(PROG).conf
+FILESNAME=$(PROG)
+FILESDIR= /etc/system.conf.d
+
+DPADD+=        ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS}
+LDADD+=        -lnetdriver -lsys -ltimers
+
+MAN=
+
+BINDIR?= /usr/sbin
+
+.include <minix.service.mk>
\ No newline at end of file
diff --git a/drivers/lan8710a/README.txt b/drivers/lan8710a/README.txt
new file mode 100644 (file)
index 0000000..6b6e6e9
--- /dev/null
@@ -0,0 +1,41 @@
+--------------------------------------------------------------------------------
+*                           INFORMATION:                                       *
+--------------------------------------------------------------------------------
+README file for the LAN8710A ethernet board driver for BeagleBone Rev. A6a
+
+created July 2013, JPEmbedded (info@jpembedded.eu)
+
+--------------------------------------------------------------------------------
+*                           INSTALLATION:                                      *
+--------------------------------------------------------------------------------
+To install LAN8710A for BeagleBone under MINIX you have to edit /etc/inet.conf
+by adding line:
+eth0 lan8710a 0 { default; };
+and changing:
+psip0 { default; };
+to:
+psip1;
+Restart the system and the driver should work.
+
+--------------------------------------------------------------------------------
+*                                 TESTS:                                       *
+--------------------------------------------------------------------------------
+Driver was tested using various tools, i. e.
+* fetch - downloading file from the Internet and also local server. Every file
+         downloaded well, but speed was about 50-200 kB/s.
+* ftp - downloading and uploading 20 MB file completed.
+* ping - checking connection between BeagleBone and computer passed using stan -
+        dard  settings,  when we set ping  requests interval  to 200 ms it also
+        passed. But  with 20 ms  and 2 ms  driver dropped some packets (20 ms -
+        about 20% loss, 2 ms - 50% loss).
+* udpstat, hostaddr, dhcpd, ifconfig, arp gave proper results.
+Tests passed, so driver meets the requirements of ethernet driver.
+
+--------------------------------------------------------------------------------
+*                                LIMITATION:                                   *
+--------------------------------------------------------------------------------
+Download speed:  50-200 kB/s
+Low bandwidth is probably caused by memory copy functions. Standard Linux driver 
+copies packets data directly to destination buffer using DMA. Minix driver needs
+to do a safe copy (sys_safecopyfrom and sys_safecopyto) from local buffer to the 
+system buffer. This operation slows down the whole driver.
diff --git a/drivers/lan8710a/lan8710a.c b/drivers/lan8710a/lan8710a.c
new file mode 100644 (file)
index 0000000..506236f
--- /dev/null
@@ -0,0 +1,1249 @@
+#include <minix/drivers.h>
+#include <minix/netdriver.h>
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+#include <minix/sysutil.h>
+#include "assert.h"
+#include "lan8710a.h"
+#include "lan8710a_reg.h"
+
+/* Local functions */
+#ifdef AM335X
+static void lan8710a_readv_s(message *m, int from_int);
+static void lan8710a_writev_s(message *m, int from_int);
+static void lan8710a_conf(message *m);
+static void lan8710a_getstat(message *m);
+
+static void lan8710a_init(void);
+static void lan8710a_enable_interrupt(int interrupt);
+static void lan8710a_interrupt(message *m);
+static void lan8710a_map_regs(void);
+static void lan8710a_stop(void);
+static void lan8710a_dma_config_tx(u8_t desc_idx);
+static void lan8710a_dma_reset_init(void);
+static void lan8710a_init_addr(void);
+static void lan8710a_init_desc(void);
+static void lan8710a_init_mdio(void);
+static int lan8710a_init_hw(void);
+static void lan8710a_reset_hw();
+
+static void lan8710a_phy_write(u32_t reg, u32_t value);
+static u32_t lan8710a_phy_read(u32_t reg);
+
+static u32_t lan8710a_reg_read(volatile u32_t *reg);
+static void lan8710a_reg_write(volatile u32_t *reg, u32_t value);
+static void lan8710a_reg_set(volatile u32_t *reg, u32_t value);
+static void lan8710a_reg_unset(volatile u32_t *reg, u32_t value);
+
+static void mess_reply(message *req, message *reply);
+static void reply(lan8710a_t *e);
+
+/* Local variables */
+static lan8710a_t lan8710a_state;
+
+/* SEF functions and variables. */
+static void sef_local_startup(void);
+static int sef_cb_init_fresh(int type, sef_init_info_t *info);
+static void sef_cb_signal_handler(int signal);
+#endif /* AM335X */
+
+/*============================================================================*
+ *                             main                                          *
+ *============================================================================*/
+int
+main(int argc, char *argv[])
+{
+#ifdef AM335X
+       /* Local variables */
+       message m;
+       int r;
+       int ipc_status;
+       static int rx_first_enabled = FALSE;
+
+       /* SEF local startup */
+       env_setargs(argc, argv);
+       sef_local_startup();
+
+       /* Main driver loop */
+       for (;;) {
+               r = netdriver_receive(ANY, &m, &ipc_status);
+               if (r != OK) {
+                       panic("netdriver_receive failed: %d", r);
+               }
+
+               if (is_ipc_notify(ipc_status)) {
+                       switch (_ENDPOINT_P(m.m_source)) {
+                       case HARDWARE:
+                               lan8710a_interrupt(&m);
+                               break;
+                       }
+               } else {
+                       switch (m.m_type) {
+                       case DL_WRITEV_S:
+                               lan8710a_writev_s(&m, FALSE);
+                               break;
+                       case DL_READV_S:
+                               lan8710a_readv_s(&m, FALSE);
+                               break;
+                       case DL_CONF:
+                               lan8710a_conf(&m);
+                               break;
+                       case DL_GETSTAT_S:
+                               lan8710a_getstat(&m);
+                               /*
+                                * Workaround:
+                                * Re-enabling interrupts here is made to avoid
+                                * problem that Rx interrupt came when it can't
+                                * be handled. When this problem occurs next Rx
+                                * interrupts don't appear.
+                                */
+                                if(rx_first_enabled == FALSE) {
+                                       rx_first_enabled = TRUE;
+                                       lan8710a_enable_interrupt(RX_INT |
+                                                                 TX_INT);
+                               }
+                               break;
+                       default:
+                               panic("Illegal message: %d", m.m_type);
+                       }
+               }
+       }
+#endif /* AM335X */
+       return EXIT_SUCCESS;
+}
+#ifdef AM335X
+/*============================================================================*
+ *                             sef_local_startup                             *
+ *============================================================================*/
+static void
+sef_local_startup()
+{
+       /* Register init callbacks. */
+       sef_setcb_init_fresh(sef_cb_init_fresh);
+       sef_setcb_init_lu(sef_cb_init_fresh);
+       sef_setcb_init_restart(sef_cb_init_fresh);
+
+       /* Register live update callbacks. */
+       sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
+       sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree);
+
+       /* Register signal callbacks. */
+       sef_setcb_signal_handler(sef_cb_signal_handler);
+
+       /* Let SEF perform startup. */
+       sef_startup();
+}
+
+/*============================================================================*
+ *                             sef_cb_init_fresh                             *
+ *============================================================================*/
+static int
+sef_cb_init_fresh(int UNUSED( type), sef_init_info_t *UNUSED( info))
+{
+       /* Initialize the ethernet driver. */
+       long v = 0;
+
+       /* Clear state. */
+       memset(&lan8710a_state, 0, sizeof(lan8710a_state));
+
+       /* Initialize driver. */
+       lan8710a_init();
+
+       /* Get instance of ethernet device */
+       env_parse("instance", "d", 0, &v, 0, 255);
+       lan8710a_state.instance = (int) v;
+
+       /* Announce we are up! */
+       netdriver_announce();
+
+       return OK;
+}
+
+/*============================================================================*
+ *                             sef_cb_signal_handler                         *
+ *============================================================================*/
+static void
+sef_cb_signal_handler(int signal)
+{
+       /* Only check for termination signal, ignore anything else. */
+       if (signal != SIGTERM)
+               return;
+
+       lan8710a_stop();
+}
+
+/*============================================================================*
+ *                             lan8710a_enable_interrupt                     *
+ *============================================================================*/
+static void
+lan8710a_enable_interrupt(interrupt)
+u8_t interrupt;
+{
+       int r;
+
+       if (interrupt & RX_INT) {
+               if ((r = sys_irqenable(&lan8710a_state.irq_rx_hook)) != OK) {
+                       panic("sys_irqenable failed: %d", r);
+               }
+       }
+       if (interrupt & TX_INT) {
+               if ((r = sys_irqenable(&lan8710a_state.irq_tx_hook)) != OK) {
+                       panic("sys_irqenable failed: %d", r);
+               }
+       }
+}
+/*============================================================================*
+ *                             lan8710a_interrupt                            *
+ *============================================================================*/
+static void
+lan8710a_interrupt(m)
+message *m;
+{
+       lan8710a_t *e = &lan8710a_state;
+       u32_t dma_status;
+
+       /* Check the card for interrupt reason(s). */
+       u32_t rx_stat = lan8710a_reg_read(CPSW_WR_C0_RX_STAT);
+       u32_t tx_stat = lan8710a_reg_read(CPSW_WR_C0_TX_STAT);
+       u32_t cp;
+
+       /* Handle interrupts. */
+       if (rx_stat) {
+               cp = lan8710a_reg_read(CPDMA_STRAM_RX_CP(0));
+
+               lan8710a_readv_s(&(e->rx_message), TRUE);
+
+               lan8710a_reg_write(CPDMA_STRAM_RX_CP(0), cp);
+               lan8710a_reg_write(CPDMA_EOI_VECTOR, RX_INT);
+       }
+       if (tx_stat) {
+               cp = lan8710a_reg_read(CPDMA_STRAM_TX_CP(0));
+
+               /* Disabling channels, where Tx interrupt occurred */
+               lan8710a_reg_set(CPDMA_TX_INTMASK_CLEAR, tx_stat);
+
+               lan8710a_writev_s(&(e->tx_message), TRUE);
+
+               lan8710a_reg_write(CPDMA_STRAM_TX_CP(0), cp);
+               lan8710a_reg_write(CPDMA_EOI_VECTOR, TX_INT);
+       }
+
+       dma_status = lan8710a_reg_read(CPDMA_STATUS);
+
+       if (dma_status & CPDMA_ERROR) {
+               LAN8710A_DEBUG_PRINT(("CPDMA error: 0x%X, reset", dma_status));
+               lan8710a_dma_reset_init();
+       }
+
+       /* Re-enable Rx interrupt. */
+       if(m->NOTIFY_ARG & (1 << RX_INT))
+               lan8710a_enable_interrupt(RX_INT);
+
+       /* Re-enable Tx interrupt. */
+       if(m->NOTIFY_ARG & (1 << TX_INT))
+               lan8710a_enable_interrupt(TX_INT);
+}
+
+/*============================================================================*
+ *                             lan8710a_conf                                 *
+ *============================================================================*/
+static void
+lan8710a_conf(m)
+message *m;
+{
+       message reply;
+
+       if (!(lan8710a_state.status & LAN8710A_ENABLED) &&
+                                               !(lan8710a_init_hw())) {
+               reply.m_type = DL_CONF_REPLY;
+               reply.DL_STAT = ENXIO;
+               mess_reply(m, &reply);
+               return;
+       }
+       /* Reply back to INET. */
+       reply.m_type = DL_CONF_REPLY;
+       reply.DL_STAT = OK;
+       *(ether_addr_t *) reply.DL_HWADDR = lan8710a_state.address;
+       mess_reply(m, &reply);
+}
+
+/*============================================================================*
+ *                             lan8710a_init                                 *
+ *============================================================================*/
+static void
+lan8710a_init(void)
+{
+       lan8710a_map_regs();
+       strlcpy(lan8710a_state.name, "lan8710a#0", LAN8710A_NAME_LEN);
+       lan8710a_state.name[9] += lan8710a_state.instance;
+       lan8710a_state.status |= LAN8710A_DETECTED;
+
+       if (!(lan8710a_state.status & LAN8710A_ENABLED) &&
+                                               !(lan8710a_init_hw())) {
+               return;
+       }
+}
+
+/*============================================================================*
+ *                             lan8710a_init_addr                            *
+ *============================================================================*/
+static void
+lan8710a_init_addr(void)
+{
+       static char eakey[]= LAN8710A_ENVVAR "#_EA";
+       static char eafmt[]= "x:x:x:x:x:x";
+       int i;
+       long v;
+
+       /*
+        * Do we have a user defined ethernet address?
+        */
+       eakey[sizeof(LAN8710A_ENVVAR)-1] = '0' + lan8710a_state.instance;
+
+       for (i= 0; i < 6; i++) {
+               if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
+                       break;
+               else
+                       lan8710a_state.address.ea_addr[i] = v;
+       }
+       if (i != 6) {
+               lan8710a_state.address.ea_addr[0] =
+                       (lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF);
+               lan8710a_state.address.ea_addr[1] =
+                       ((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF00) >> 8);
+               lan8710a_state.address.ea_addr[2] =
+                       ((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF0000) >> 16);
+               lan8710a_state.address.ea_addr[3] =
+                       ((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF000000) >> 24);
+               lan8710a_state.address.ea_addr[4] =
+                       (lan8710a_reg_read(CTRL_MAC_ID0_LO) & 0xFF);
+               lan8710a_state.address.ea_addr[5] =
+                       ((lan8710a_reg_read(CTRL_MAC_ID0_LO) & 0xFF00) >> 8);
+       }
+}
+
+/*============================================================================*
+ *                             lan8710a_map_regs                             *
+ *============================================================================*/
+static void
+lan8710a_map_regs(void)
+{
+       struct minix_mem_range mr;
+       mr.mr_base = CM_PER_BASE_ADR;
+       mr.mr_limit = CM_PER_BASE_ADR + MEMORY_LIMIT;
+
+       if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
+               panic("Unable to request permission to map memory");
+       }
+       lan8710a_state.regs_cp_per =
+               (vir_bytes)vm_map_phys(SELF, (void *)CM_PER_BASE_ADR, 512);
+       if ((void *)lan8710a_state.regs_cp_per == MAP_FAILED) {
+               panic("lan8710a_state.regs_cp_per: vm_map_phys failed");
+       }
+       lan8710a_state.regs_cpdma_stram =
+               (vir_bytes)vm_map_phys(SELF, (void *)CPDMA_STRAM_BASE_ADR, 512);
+       if ((void *)lan8710a_state.regs_cpdma_stram == MAP_FAILED) {
+               panic("lan8710a_state.regs_cpdma_stram: vm_map_phys failed");
+       }
+       lan8710a_state.regs_cpsw_cpdma =
+               (vir_bytes)vm_map_phys(SELF, (void *)CPSW_CPDMA_BASE_ADR, 512);
+       if ((void *)lan8710a_state.regs_cpsw_cpdma == MAP_FAILED) {
+               panic("lan8710a_state.regs_cpsw_cpdma: vm_map_phys failed");
+       }
+       lan8710a_state.regs_cpsw_ale =
+               (vir_bytes)vm_map_phys(SELF, (void *)CPSW_ALE_BASE_ADR, 256);
+       if ((void *)lan8710a_state.regs_cpsw_ale == MAP_FAILED) {
+               panic("lan8710a_state.regs_cpsw_ale: vm_map_phys failed");
+       }
+       lan8710a_state.regs_cpsw_sl =
+               (vir_bytes)vm_map_phys(SELF, (void *)CPSW_SL_BASE_ADR, 512);
+       if ((void *)lan8710a_state.regs_cpsw_sl == MAP_FAILED) {
+               panic("lan8710a_state.regs_cpsw_sl: vm_map_phys failed");
+       }
+       lan8710a_state.regs_cpsw_ss =
+               (vir_bytes)vm_map_phys(SELF, (void *)CPSW_SS_BASE_ADR, 512);
+       if ((void *)lan8710a_state.regs_cpsw_ss == MAP_FAILED) {
+               panic("lan8710a_state.regs_cpsw_ss: vm_map_phys failed");
+       }
+       lan8710a_state.regs_cpsw_wr =
+               (vir_bytes)vm_map_phys(SELF, (void *)CPSW_WR_BASE_ADR, 512);
+       if ((void *)lan8710a_state.regs_cpsw_wr == MAP_FAILED) {
+               panic("lan8710a_state.regs_cpsw_wr: vm_map_phys failed");
+       }
+       lan8710a_state.regs_ctrl_mod =
+               (vir_bytes)vm_map_phys(SELF, (void *)CTRL_MOD_BASE_ADR, 2560);
+       if ((void *)lan8710a_state.regs_ctrl_mod == MAP_FAILED) {
+               panic("lan8710a_state.regs_ctrl_mod: vm_map_phys failed");
+       }
+       lan8710a_state.regs_intc =
+               (vir_bytes)vm_map_phys(SELF, (void *)INTC_BASE_ADR, 512);
+       if ((void *)lan8710a_state.regs_intc == MAP_FAILED) {
+               panic("lan8710a_state.regs_intc: vm_map_phys failed");
+       }
+       lan8710a_state.regs_mdio =
+               (vir_bytes)vm_map_phys(SELF, (void *)MDIO_BASE_ADDR, 512);
+       if ((void *)lan8710a_state.regs_mdio == MAP_FAILED) {
+               panic("lan8710a_state.regs_mdio: vm_map_phys failed");
+       }
+
+       mr.mr_base = BEGINNING_DESC_MEM;
+       mr.mr_limit = BEGINNING_DESC_MEM + DESC_MEMORY_LIMIT;
+
+       if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
+               panic("Unable to request permission to map memory");
+       }
+       lan8710a_state.rx_desc_phy = BEGINNING_RX_DESC_MEM;
+       lan8710a_state.tx_desc_phy = BEGINNING_TX_DESC_MEM;
+       lan8710a_state.rx_desc = (lan8710a_desc_t *)vm_map_phys(SELF,
+                               (void *)lan8710a_state.rx_desc_phy, 1024);
+       if ((void *)lan8710a_state.rx_desc == MAP_FAILED) {
+               panic("lan8710a_state.rx_desc: vm_map_phys failed");
+       }
+       lan8710a_state.tx_desc = (lan8710a_desc_t *)vm_map_phys(SELF,
+                               (void *)lan8710a_state.tx_desc_phy, 1024);
+       if ((void *)lan8710a_state.tx_desc == MAP_FAILED) {
+               panic("lan8710a_state.tx_desc: vm_map_phys failed");
+       }
+
+       mr.mr_base = CPSW_STATS_BASE_ADR;
+       mr.mr_limit = CPSW_STATS_BASE_ADR + CPSW_STATS_MEM_LIMIT;
+
+       if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
+               panic("Unable to request permission to map memory");
+       }
+       lan8710a_state.regs_cpsw_stats =
+               (vir_bytes)vm_map_phys(SELF, (void *)CPSW_STATS_BASE_ADR, 256);
+       if ((void *)lan8710a_state.regs_cpsw_stats == MAP_FAILED) {
+               panic("lan8710a_state.regs_cpsw_stats: vm_map_phys failed");
+       }
+}
+
+/*============================================================================*
+ *                             lan8710a_getstat                              *
+ *============================================================================*/
+static void
+lan8710a_getstat(mp)
+message *mp;
+{
+       int r;
+       eth_stat_t stats;
+
+       stats.ets_recvErr   = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR)
+                               + lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR)
+                               + lan8710a_reg_read(CPSW_STAT_RX_OVERSIZE);
+       stats.ets_sendErr   = 0;
+       stats.ets_OVW       = 0;
+       stats.ets_CRCerr    = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR);
+       stats.ets_frameAll  = lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR);
+       stats.ets_missedP   = 0;
+       stats.ets_packetR   = lan8710a_reg_read(CPSW_STAT_RX_GOOD);
+       stats.ets_packetT   = lan8710a_reg_read(CPSW_STAT_TX_GOOD);
+       stats.ets_collision = lan8710a_reg_read(CPSW_STAT_COLLISIONS);
+       stats.ets_transAb   = 0;
+       stats.ets_carrSense = lan8710a_reg_read(CPSW_STAT_CARR_SENS_ERR);
+       stats.ets_fifoUnder = lan8710a_reg_read(CPSW_STAT_TX_UNDERRUN);
+       stats.ets_fifoOver  = lan8710a_reg_read(CPSW_STAT_RX_OVERRUN);
+       stats.ets_CDheartbeat = 0;
+       stats.ets_OWC = 0;
+
+       sys_safecopyto(mp->m_source, mp->DL_GRANT, 0, (vir_bytes)&stats,
+                       sizeof(stats));
+       mp->m_type  = DL_STAT_REPLY;
+
+       if ((r=send(mp->m_source, mp)) != OK) {
+               panic("lan8710a_getstat: send() failed: %d", r);
+       }
+}
+
+/*============================================================================*
+ *                             lan8710a_stop                                 *
+ *============================================================================*/
+static void
+lan8710a_stop(void)
+{
+       /* Reset hardware. */
+       lan8710a_reset_hw();
+
+       /* Exit driver. */
+       exit(EXIT_SUCCESS);
+}
+
+/*============================================================================*
+ *                             lan8710a_dma_config_tx                        *
+ *============================================================================*/
+static void
+lan8710a_dma_config_tx(desc_idx)
+u8_t desc_idx;
+{
+       phys_bytes phys_addr;
+       int i;
+       for (i = 0; i < TX_DMA_CHANNELS; ++i) {
+               if (!lan8710a_reg_read(CPDMA_STRAM_TX_HDP(i))) break;
+       }
+       if (i == TX_DMA_CHANNELS) {
+               panic("There are no free TX DMA channels.");
+       }
+
+       /* Enabling only one channel Tx interrupt */
+       lan8710a_reg_write(CPDMA_TX_INTMASK_SET, 1 << i);
+       /* Routing only one channel Tx int to TX_PULSE signal */
+       lan8710a_reg_write(CPSW_WR_C0_TX_EN, 1 << i);
+
+       /* Setting HDP */
+       phys_addr = lan8710a_state.tx_desc_phy +
+                                       (desc_idx * sizeof(lan8710a_desc_t));
+       lan8710a_reg_write(CPDMA_STRAM_TX_HDP(i), (u32_t)phys_addr);
+}
+
+/*============================================================================*
+ *                             lan8710a_dma_reset_init                       *
+ *============================================================================*/
+static void
+lan8710a_dma_reset_init(void)
+{
+       int i;
+       lan8710a_reg_write(CPDMA_SOFT_RESET, SOFT_RESET);
+       while ((lan8710a_reg_read(CPDMA_SOFT_RESET) & SOFT_RESET));
+
+       /*
+        * Initialize the HDPs (Header Description Pointers) and
+        * CPs (Completion Pointers) to NULL.
+        */
+       for (i = 0; i < DMA_MAX_CHANNELS; ++i) {
+               lan8710a_reg_write(CPDMA_STRAM_TX_HDP(i), 0);
+               lan8710a_reg_write(CPDMA_STRAM_RX_HDP(i), 0);
+               lan8710a_reg_write(CPDMA_STRAM_TX_CP(i), 0);
+               lan8710a_reg_write(CPDMA_STRAM_RX_CP(i), 0);
+       }
+
+       lan8710a_reg_write(CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF);
+       lan8710a_reg_write(CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF);
+
+       /* Configure the CPDMA controller. */
+       lan8710a_reg_set(CPDMA_RX_CONTROL, CPDMA_RX_EN); /* RX Enabled */
+       lan8710a_reg_set(CPDMA_TX_CONTROL, CPDMA_TX_EN); /* TX Enabled */
+
+       /* Enabling first channel Rx interrupt */
+       lan8710a_reg_set(CPDMA_RX_INTMASK_SET, CPDMA_FIRST_CHAN_INT);
+
+       /*
+        * Writing the address of the first buffer descriptor in the queue
+        * (nonzero value)to the channel\92s head descriptor pointer in the
+        * channel\92s Rx DMA state.
+        */
+       lan8710a_reg_write(CPDMA_STRAM_RX_HDP(0),
+                         (u32_t)lan8710a_state.rx_desc_phy);
+
+       lan8710a_state.rx_desc_idx = 0;
+       lan8710a_state.tx_desc_idx = 0;
+}
+
+/*============================================================================*
+ *                             lan8710a_init_desc                            *
+ *============================================================================*/
+static void
+lan8710a_init_desc(void)
+{
+       lan8710a_desc_t *p_rx_desc;
+       lan8710a_desc_t *p_tx_desc;
+       phys_bytes   buf_phys_addr;
+       u8_t *p_buf;
+       u8_t i;
+
+       /* Attempt to allocate. */
+       if ((lan8710a_state.p_rx_buf = alloc_contig((LAN8710A_NUM_RX_DESC
+                       * LAN8710A_IOBUF_SIZE), AC_ALIGN4K,
+                       &buf_phys_addr)) == NULL) {
+               panic("failed to allocate RX buffers.");
+       }
+       p_buf = lan8710a_state.p_rx_buf;
+       for (i = 0; i < LAN8710A_NUM_RX_DESC; i++) {
+               p_rx_desc = &(lan8710a_state.rx_desc[i]);
+               memset(p_rx_desc, 0x0, sizeof(lan8710a_desc_t));
+               p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN;
+               p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE;
+               p_rx_desc->buffer_pointer = (u32_t)(buf_phys_addr +
+                                               (i * LAN8710A_IOBUF_SIZE));
+
+               p_rx_desc->next_pointer =
+                  (u32_t)((i == (LAN8710A_NUM_RX_DESC - 1)) ?
+                          (lan8710a_state.rx_desc_phy) :
+                          (lan8710a_state.rx_desc_phy +
+                            ((i + 1) * sizeof(lan8710a_desc_t))));
+       }
+
+       /* Attempt to allocate. */
+       if ((lan8710a_state.p_tx_buf = alloc_contig((LAN8710A_NUM_TX_DESC
+                       * LAN8710A_IOBUF_SIZE), AC_ALIGN4K,
+                       &buf_phys_addr)) == NULL) {
+               panic("failed to allocate TX buffers");
+       }
+       p_buf = lan8710a_state.p_tx_buf;
+       for (i = 0; i < LAN8710A_NUM_TX_DESC; i++) {
+               p_tx_desc = &(lan8710a_state.tx_desc[i]);
+               memset(p_tx_desc, 0x0, sizeof(lan8710a_desc_t));
+               p_tx_desc->buffer_pointer = (u32_t)(buf_phys_addr +
+                               (i * LAN8710A_IOBUF_SIZE));
+       }
+       lan8710a_state.rx_desc_idx = 0;
+       lan8710a_state.tx_desc_idx = 0;
+}
+
+/*============================================================================*
+ *                             lan8710a_init_hw                              *
+ *============================================================================*/
+static int
+lan8710a_init_hw(void)
+{
+       int r, i;
+
+       lan8710a_state.status |= LAN8710A_ENABLED;
+
+       /*
+        * Set the interrupt handler and policy. Do not automatically
+        * re-enable interrupts. Return the IRQ line number on interrupts.
+        */
+       lan8710a_state.irq_rx_hook = RX_INT;
+       if ((r = sys_irqsetpolicy(LAN8710A_RX_INTR, 0,
+                                       &lan8710a_state.irq_rx_hook)) != OK) {
+               panic("sys_irqsetpolicy failed: %d", r);
+       }
+       lan8710a_state.irq_tx_hook = TX_INT;
+       if ((r = sys_irqsetpolicy(LAN8710A_TX_INTR, 0,
+                                       &lan8710a_state.irq_tx_hook)) != OK) {
+               panic("sys_irqsetpolicy failed: %d", r);
+       }
+
+       /* Reset hardware. */
+       lan8710a_reset_hw();
+
+       /*
+        * Select the Interface (GMII/RGMII/MII) Mode in the Control Module.
+        * Port1 GMII/MII Mode, Port2 not used.
+        */
+       lan8710a_reg_write(GMII_SEL, (GMII2_SEL_BIT1 | GMII2_SEL_BIT0));
+
+       /*
+        * Configure pads (PIN muxing) as per the Interface Selected using the
+        * appropriate pin muxing conf_xxx registers in the Control Module.
+        *
+        * CONF_MOD_SLEW_CTRL when 0 - Fast Mode, when 1 - Slow Mode
+        * CONF_MOD_RX_ACTIVE when 0 - Only output, when 1 - Also input
+        * CONF_MOD_PU_TYPESEL when 0 - Pull-down, when 1 - Pull-up
+        * CONF_MOD_PUDEN when 0 Pull* enabled, when 1 Pull* disabled
+        * CONF_MOD_MMODE_MII selects pin to work for MII interface
+        */
+       lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_set(CONF_MII1_COL, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_COL, CONF_MOD_PU_TYPESEL);
+       lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_set(CONF_MII1_CRS, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_CRS, CONF_MOD_PU_TYPESEL);
+       lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_set(CONF_MII1_RX_ER, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_RX_ER, CONF_MOD_PU_TYPESEL);
+       lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_TX_EN, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_set(CONF_MII1_RX_DV, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_RX_DV, CONF_MOD_PU_TYPESEL);
+       lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_TXD3, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_TXD2, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_TXD1, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_TXD0, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_TX_CLK, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_set(CONF_MII1_TX_CLK, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_TX_CLK, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_TX_CLK, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_RX_CLK, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_set(CONF_MII1_RX_CLK, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_RX_CLK, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_RX_CLK, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_set(CONF_MII1_RXD3, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_RXD3, CONF_MOD_PU_TYPESEL);
+       lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_set(CONF_MII1_RXD2, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_RXD2, CONF_MOD_PU_TYPESEL);
+       lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_set(CONF_MII1_RXD1, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_RXD1, CONF_MOD_PU_TYPESEL);
+       lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_set(CONF_MII1_RXD0, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MII1_RXD0, CONF_MOD_PU_TYPESEL);
+       lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MDIO, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_set(CONF_MDIO, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MDIO, CONF_MOD_PU_TYPESEL);
+       lan8710a_reg_unset(CONF_MDIO, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MDIO, CONF_MOD_MMODE_MII);
+
+       lan8710a_reg_unset(CONF_MDC, CONF_MOD_SLEW_CTRL);
+       lan8710a_reg_unset(CONF_MDC, CONF_MOD_RX_ACTIVE);
+       lan8710a_reg_set(CONF_MDC, CONF_MOD_PUDEN);
+       lan8710a_reg_unset(CONF_MDC, CONF_MOD_MMODE_MII);
+
+       /* Apply soft reset to 3PSW Subsytem, CPSW_3G, CPGMAC_SL, and CPDMA. */
+       lan8710a_reg_write(CPSW_SS_SOFT_RESET, SOFT_RESET);
+       lan8710a_reg_write(CPSW_SL_SOFT_RESET(1), SOFT_RESET);
+       lan8710a_reg_write(CPSW_SL_SOFT_RESET(2), SOFT_RESET);
+
+       /* Wait for software resets completion */
+       while ((lan8710a_reg_read(CPSW_SS_SOFT_RESET) & SOFT_RESET) ||
+               (lan8710a_reg_read(CPSW_SL_SOFT_RESET(1)) & SOFT_RESET) ||
+               (lan8710a_reg_read(CPSW_SL_SOFT_RESET(2)) & SOFT_RESET));
+
+       /* Configure the Statistics Port Enable register. */
+       /* Enable port 0 and 1 statistics. */
+       lan8710a_reg_write(CPSW_SS_STAT_PORT_EN, (CPSW_P1_STAT_EN |
+                                                       CPSW_P0_STAT_EN));
+
+       /*
+        * Configure the ALE.
+        * Enabling Ale.
+        * All packets received on ports 1 are
+        * sent to the host (only to the host).
+        */
+       lan8710a_reg_write(CPSW_ALE_CONTROL, (CPSW_ALE_ENABLE |
+                                               CPSW_ALE_BYPASS));
+       /* Port 0 (host) in forwarding mode. */
+       lan8710a_reg_write(CPSW_ALE_PORTCTL0, CPSW_ALE_PORT_FWD);
+       /* Port 1 in forwarding mode. */
+       lan8710a_reg_write(CPSW_ALE_PORTCTL1, CPSW_ALE_PORT_FWD);
+
+       /*
+        * Configure CPSW_SL Register
+        * Full duplex mode.
+        */
+       lan8710a_reg_write(CPSW_SL_MACCONTROL(1), CPSW_SL_FULLDUPLEX);
+
+       /* Initialize MDIO Protocol */
+       lan8710a_init_mdio();
+
+       /* Getting MAC Address */
+       lan8710a_init_addr();
+
+       /* Initialize descriptors */
+       lan8710a_init_desc();
+
+       /* Reset and initialize CPDMA */
+       lan8710a_dma_reset_init();
+
+       /*
+        * Configure the Interrupts.
+        * Routing all channel Rx int to RX_PULSE signal.
+        */
+       lan8710a_reg_set(CPSW_WR_C0_RX_EN, CPSW_FIRST_CHAN_INT);
+
+       /*
+        * Enabling LAN8710A Auto-negotiation
+        */
+       lan8710a_phy_write(LAN8710A_CTRL_REG, LAN8710A_AUTO_NEG);
+
+       /* Waiting for auto-negotiaion completion. */
+       for (i = 0; !(lan8710a_phy_read(LAN8710A_STATUS_REG) &
+                                       LAN8710A_AUTO_NEG_COMPL); ++i) {
+               if (i == 100) {
+                       LAN8710A_DEBUG_PRINT(("Autonegotiation failed"));
+                       break;
+               }
+               tickdelay(100);
+       }
+
+       /* GMII RX and TX release from reset. */
+       lan8710a_reg_set(CPSW_SL_MACCONTROL(1), CPSW_SL_GMII_EN);
+
+       return TRUE;
+}
+
+/*============================================================================*
+ *                             lan8710a_init_mdio                            *
+ *============================================================================*/
+static void
+lan8710a_init_mdio(void)
+{
+       u16_t address = 0;
+       u32_t r;
+
+       /* Clearing MDIOCONTROL register */
+       lan8710a_reg_write(MDIOCONTROL, 0);
+       /* Configure the PREAMBLE and CLKDIV in the MDIO control register */
+       lan8710a_reg_unset(MDIOCONTROL, MDIO_PREAMBLE); /* CLKDIV default */
+       /* Enable sending MDIO frame preambles */
+       lan8710a_reg_set(MDIOCONTROL, (MDCLK_DIVIDER | MDIO_ENABLE));
+       /* Enable the MDIO module by setting the ENABLE bit in MDIOCONTROL */
+
+       while (!(r = lan8710a_reg_read(MDIOALIVE)));
+
+       /* Get PHY address */
+       while (r >>= 1) {
+               ++address;
+       }
+       lan8710a_state.phy_address = address;
+
+       /* Setup appropiate address in MDIOUSERPHYSEL0 */
+       lan8710a_reg_set(MDIOUSERPHYSEL0, address);
+}
+
+/*============================================================================*
+ *                             lan8710a_writev_s                             *
+ *============================================================================*/
+static void
+lan8710a_writev_s(mp, from_int)
+message *mp;
+int from_int;
+{
+       iovec_s_t iovec[LAN8710A_IOVEC_NR];
+       lan8710a_t *e = &lan8710a_state;
+       lan8710a_desc_t *p_tx_desc;
+       u8_t *p_buf;
+       int r, size, buf_data_len, i;
+
+       /* Are we called from the interrupt handler? */
+       if (!from_int) {
+               /* We cannot write twice simultaneously. */
+               assert(!(e->status & LAN8710A_WRITING));
+
+               /* Copy write message. */
+               e->tx_message = *mp;
+               e->client = mp->m_source;
+               e->status |= LAN8710A_WRITING;
+
+               /* verify vector count */
+               assert(mp->DL_COUNT > 0);
+               assert(mp->DL_COUNT < LAN8710A_IOVEC_NR);
+
+               /*
+                * Copy the I/O vector table.
+                */
+               if ((r = sys_safecopyfrom(mp->m_source, mp->DL_GRANT, 0,
+                               (vir_bytes) iovec,
+                               mp->DL_COUNT * sizeof(iovec_s_t))) != OK) {
+                       panic("sys_safecopyfrom() failed: %d", r);
+               }
+               /* setup descriptors */
+               p_tx_desc = &(e->tx_desc[e->tx_desc_idx]);
+
+               /*
+                * Check if descriptor is available for host
+                * and drop the packet if not.
+                */
+               if (LAN8710A_DESC_FLAG_OWN & p_tx_desc->pkt_len_flags) {
+                       panic("No available transmit descriptor.");
+               }
+
+               /* virtual address of buffer */
+               p_buf = e->p_tx_buf + e->tx_desc_idx * LAN8710A_IOBUF_SIZE;
+               buf_data_len = 0;
+               for (i = 0; i < mp->DL_COUNT; i++) {
+                       if ((buf_data_len + iovec[i].iov_size)
+                            > LAN8710A_IOBUF_SIZE) {
+                               panic("packet too long");
+                       }
+
+                       /* copy data to buffer */
+                       size = iovec[i].iov_size
+                               < (LAN8710A_IOBUF_SIZE - buf_data_len) ?
+                                   iovec[i].iov_size
+                                   : (LAN8710A_IOBUF_SIZE - buf_data_len);
+
+                       /* Copy bytes to TX queue buffers. */
+                       if ((r = sys_safecopyfrom(mp->m_source,
+                                       iovec[i].iov_grant, 0,
+                                       (vir_bytes) p_buf, size)) != OK) {
+                               panic("sys_safecopyfrom() failed: %d", r);
+                       }
+                       p_buf += size;
+                       buf_data_len += size;
+               }
+
+               /* set descriptor length */
+               p_tx_desc->buffer_length_off = buf_data_len;
+               /* set flags */
+               p_tx_desc->pkt_len_flags = (LAN8710A_DESC_FLAG_OWN |
+                                               LAN8710A_DESC_FLAG_SOP |
+                                               LAN8710A_DESC_FLAG_EOP |
+                                               TX_DESC_TO_PORT1 |
+                                               TX_DESC_TO_PORT_EN);
+               p_tx_desc->pkt_len_flags |= buf_data_len;
+
+               /* setup DMA transfer */
+               lan8710a_dma_config_tx(e->tx_desc_idx);
+
+               e->tx_desc_idx++;
+               if (LAN8710A_NUM_TX_DESC == e->tx_desc_idx) {
+                       e->tx_desc_idx = 0;
+               }
+       } else {
+               e->status |= LAN8710A_TRANSMIT;
+       }
+       reply(e);
+}
+
+/*============================================================================*
+ *                             lan8710a_readv_s                              *
+ *============================================================================*/
+static void
+lan8710a_readv_s(mp, from_int)
+message *mp;
+int from_int;
+{
+       iovec_s_t iovec[LAN8710A_IOVEC_NR];
+       lan8710a_t *e = &lan8710a_state;
+       lan8710a_desc_t *p_rx_desc;
+       u32_t  flags;
+       u8_t *p_buf;
+       u16_t pkt_data_len;
+       u16_t buf_bytes, buf_len;
+       int i, r, size;
+
+       /* Are we called from the interrupt handler? */
+       if (!from_int) {
+               e->rx_message = *mp;
+               e->client = mp->m_source;
+               e->status |= LAN8710A_READING;
+               e->rx_size = 0;
+
+               assert(e->rx_message.DL_COUNT > 0);
+               assert(e->rx_message.DL_COUNT < LAN8710A_IOVEC_NR);
+       }
+       if (e->status & LAN8710A_READING) {
+               /*
+                * Copy the I/O vector table first.
+                */
+               if ((r = sys_safecopyfrom(e->rx_message.m_source,
+                               e->rx_message.DL_GRANT, 0, (vir_bytes) iovec,
+                               e->rx_message.DL_COUNT *
+                                   sizeof(iovec_s_t))) != OK) {
+                       panic("sys_safecopyfrom() failed: %d", r);
+               }
+
+               /*
+                * Only handle one packet at a time.
+                */
+               p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
+               /* find next OWN descriptor with SOP flag */
+               while ((0 == (LAN8710A_DESC_FLAG_SOP &
+                                       p_rx_desc->pkt_len_flags)) &&
+                               (0 == (LAN8710A_DESC_FLAG_OWN &
+                                       p_rx_desc->pkt_len_flags))) {
+                       p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE;
+                       /* set ownership of current descriptor to EMAC */
+                       p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN;
+
+                       e->rx_desc_idx++;
+                       if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx)
+                               e->rx_desc_idx = 0;
+                       p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
+               }
+               if (0 == (LAN8710A_DESC_FLAG_SOP & p_rx_desc->pkt_len_flags)) {
+                       /* SOP was not found */
+                       reply(e);
+                       return;
+               }
+
+               /*
+                * Copy to vector elements.
+                */
+               pkt_data_len = 0;
+               buf_bytes = 0;
+               p_buf = e->p_rx_buf + e->rx_desc_idx * LAN8710A_IOBUF_SIZE;
+               for (i = 0; i < e->rx_message.DL_COUNT; i++) {
+                       buf_len = p_rx_desc->buffer_length_off & 0xFFFF;
+                       if (buf_bytes == buf_len) {
+                               /* Whole buffer move to the next descriptor */
+                               p_rx_desc->buffer_length_off =
+                                                       LAN8710A_IOBUF_SIZE;
+                               /* set ownership of current desc to EMAC */
+                               p_rx_desc->pkt_len_flags =
+                                                       LAN8710A_DESC_FLAG_OWN;
+                               buf_bytes = 0;
+
+                               e->rx_desc_idx++;
+                               if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx)
+                                       e->rx_desc_idx = 0;
+                               p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
+                               p_buf = e->p_rx_buf + (e->rx_desc_idx *
+                                           LAN8710A_IOBUF_SIZE) +
+                                           (p_rx_desc->buffer_length_off >> 16);
+                               buf_len = p_rx_desc->buffer_length_off & 0xFFFF;
+                       }
+                       size = iovec[i].iov_size < (buf_len - buf_bytes) ?
+                                  iovec[i].iov_size :
+                                  (buf_len - buf_bytes);
+
+                       if ((r = sys_safecopyto(e->rx_message.m_source,
+                                               iovec[i].iov_grant, 0,
+                                               (vir_bytes) p_buf,
+                                               size)) != OK) {
+                               panic("sys_safecopyto() failed: %d", r);
+                       }
+                       p_buf += size;
+                       buf_bytes += size;
+                       pkt_data_len += size;
+
+                       /* if EOP flag is set -> stop processing */
+                       if ((LAN8710A_DESC_FLAG_EOP & p_rx_desc->pkt_len_flags) &&
+                                                       (buf_bytes == buf_len)) {
+                               /* end of packet */
+                               break;
+                       }
+               }
+               do {
+                       /* reset owned descriptors up to EOP flag */
+                       flags = p_rx_desc->pkt_len_flags;
+                       p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE;
+                       /* set ownership of current descriptor to EMAC */
+                       p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN;
+
+                       e->rx_desc_idx++;
+                       if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx)
+                               e->rx_desc_idx = 0;
+
+                       p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
+               }
+               while (0 == (flags & LAN8710A_DESC_FLAG_EOP));
+
+               /*
+                * Update state.
+                */
+               e->status |= LAN8710A_RECEIVED;
+               e->rx_size = pkt_data_len;
+
+       }
+       reply(e);
+}
+
+/*============================================================================*
+ *                             lan8710a_phy_write                            *
+ *============================================================================*/
+static void
+lan8710a_phy_write(reg, value)
+u32_t reg;
+u32_t value;
+{
+       if (!(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)) {
+               /* Clearing MDIOUSERACCESS0 register */
+               lan8710a_reg_write(MDIOUSERACCESS0, 0);
+               /* Setting proper values in MDIOUSERACCESS0 */
+               lan8710a_reg_set(MDIOUSERACCESS0, MDIO_WRITE);
+               lan8710a_reg_set(MDIOUSERACCESS0, reg << MDIO_REGADR);
+               lan8710a_reg_set(MDIOUSERACCESS0,
+                               lan8710a_state.phy_address << MDIO_PHYADR);
+               /* Data written only 16 bits. */
+               lan8710a_reg_set(MDIOUSERACCESS0, (value & 0xFFFF) << MDIO_DATA);
+               lan8710a_reg_set(MDIOUSERACCESS0, MDIO_GO);
+
+               /* Waiting for writing completion */
+               while (lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO);
+       }
+}
+
+/*============================================================================*
+ *                             lan8710a_phy_read                             *
+ *============================================================================*/
+static u32_t
+lan8710a_phy_read(reg)
+u32_t reg;
+{
+       u32_t value = 0xFFFFFFFF;
+
+       if (!(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)) {
+               /* Clearing MDIOUSERACCESS0 register */
+               lan8710a_reg_write(MDIOUSERACCESS0, 0);
+               /* Setting proper values in MDIOUSERACCESS0 */
+               lan8710a_reg_unset(MDIOUSERACCESS0, MDIO_WRITE);
+               /* Reg number must be 5 bit long */
+               lan8710a_reg_set(MDIOUSERACCESS0, (reg & 0x1F) << MDIO_REGADR);
+               /* Addr must be 5 bit long */
+               lan8710a_reg_set(MDIOUSERACCESS0,
+                       (lan8710a_state.phy_address & 0x1F) << MDIO_PHYADR);
+               lan8710a_reg_set(MDIOUSERACCESS0, MDIO_GO);
+
+               /* Waiting for reading completion */
+               while ((lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)
+                       && !(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_ACK));
+
+               /* Reading data */
+               value = lan8710a_reg_read(MDIOUSERACCESS0) & 0xFFFF;
+       }
+       return value;
+}
+
+/*============================================================================*
+ *                             lan8710a_reset_hw                             *
+ *============================================================================*/
+static void
+lan8710a_reset_hw()
+{
+       /* Assert a Device Reset signal. */
+       lan8710a_phy_write(LAN8710A_CTRL_REG, LAN8710A_SOFT_RESET);
+
+       /* Waiting for reset completion. */
+       while (lan8710a_phy_read(LAN8710A_CTRL_REG) & LAN8710A_SOFT_RESET);
+}
+
+/*============================================================================*
+ *                             lan8710a_reg_read                             *
+ *============================================================================*/
+static u32_t
+lan8710a_reg_read(reg)
+volatile u32_t *reg;
+{
+       u32_t value;
+
+       /* Read from memory mapped register. */
+       value = *reg;
+
+       /* Return the result. */
+       return value;
+}
+
+/*============================================================================*
+ *                             lan8710a_reg_write                            *
+ *============================================================================*/
+static void
+lan8710a_reg_write(reg, value)
+volatile u32_t *reg;
+u32_t value;
+{
+       /* Write to memory mapped register. */
+       *reg = value;
+}
+
+/*============================================================================*
+ *                             lan8710a_reg_set                              *
+ *============================================================================*/
+static void
+lan8710a_reg_set(reg, value)
+volatile u32_t *reg;
+u32_t value;
+{
+       u32_t data;
+
+       /* First read the current value. */
+       data = lan8710a_reg_read(reg);
+
+       /* Set value, and write back. */
+       lan8710a_reg_write(reg, data | value);
+}
+
+/*============================================================================*
+ *                             lan8710a_reg_unset                            *
+ *============================================================================*/
+static void
+lan8710a_reg_unset(reg, value)
+volatile u32_t *reg;
+u32_t value;
+{
+       u32_t data;
+
+       /* First read the current value. */
+       data = lan8710a_reg_read(reg);
+
+       /* Unset value, and write back. */
+       lan8710a_reg_write(reg, data & ~value);
+}
+
+/*============================================================================*
+ *                             mess_reply                                    *
+ *============================================================================*/
+static void
+mess_reply(req, reply)
+message *req;message *reply;
+{
+       if (send(req->m_source, reply) != OK) {
+               panic("unable to send reply message");
+       }
+}
+
+/*============================================================================*
+ *                             reply                                         *
+ *============================================================================*/
+static void
+reply(e)
+lan8710a_t *e;
+{
+       message msg;
+       int r;
+
+       /* Only reply to client for read/write request. */
+       if (!(e->status & LAN8710A_READING ||
+                       e->status & LAN8710A_WRITING)) {
+               return;
+       }
+       /* Construct reply message. */
+       msg.m_type   = DL_TASK_REPLY;
+       msg.DL_FLAGS = DL_NOFLAGS;
+       msg.DL_COUNT = 0;
+
+       /* Did we successfully receive packet(s)? */
+       if (e->status & LAN8710A_READING &&
+       e->status & LAN8710A_RECEIVED) {
+               msg.DL_FLAGS |= DL_PACK_RECV;
+               msg.DL_COUNT = e->rx_size >= ETH_MIN_PACK_SIZE ?
+                              e->rx_size :
+                              ETH_MIN_PACK_SIZE;
+
+               /* Clear flags. */
+               e->status &= ~(LAN8710A_READING | LAN8710A_RECEIVED);
+       }
+       /* Did we successfully transmit packet(s)? */
+       if (e->status & LAN8710A_TRANSMIT &&
+               e->status & LAN8710A_WRITING) {
+               msg.DL_FLAGS |= DL_PACK_SEND;
+
+               /* Clear flags. */
+               e->status &= ~(LAN8710A_WRITING | LAN8710A_TRANSMIT);
+       }
+
+       /* Acknowledge to INET. */
+       if ((r = send(e->client, &msg) != OK)) {
+               panic("send() failed: %d", r);
+       }
+}
+#endif /* AM335X */
diff --git a/drivers/lan8710a/lan8710a.conf b/drivers/lan8710a/lan8710a.conf
new file mode 100644 (file)
index 0000000..4c37a77
--- /dev/null
@@ -0,0 +1,17 @@
+service lan8710a
+{
+       type net;
+       descr "Beaglebone Ethernet Controller LAN8710A";
+       system
+               PRIVCTL         #  4
+               UMAP            # 14
+               IRQCTL          # 19
+               DEVIO           # 21
+       ;
+       ipc
+               tty inet lwip
+       ;
+       irq     41              # IRQ 41 allowed
+               42              # IRQ 42 allowed
+       ;
+};
diff --git a/drivers/lan8710a/lan8710a.h b/drivers/lan8710a/lan8710a.h
new file mode 100644 (file)
index 0000000..214df87
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef LAN8710A_H_
+#define LAN8710A_H_
+
+#include <net/gen/ether.h>
+
+#define LAN8710A_DEBUG         (1)
+
+#if LAN8710A_DEBUG == 1
+       #define LAN8710A_DEBUG_PRINT(args)              \
+               do {                                    \
+                       printf("LAN8710A DEBUG: ");     \
+                       printf args;                    \
+                       printf("\n");                   \
+               } while (0)
+#else
+       #define LAN8710A_DEBUG_PRINT(args)
+#endif
+
+#ifndef ERR
+       #define ERR (-1)        /* general error flag */
+#endif
+#ifndef OK
+       #define OK 0            /* general OK flag */
+#endif
+
+#define MAP_FAILED             ((void *) -1)   /* mmap() failed */
+
+/* Ethernet driver defines */
+#define LAN8710A_NAME_LEN      (11)
+
+/* Ethernet driver states */
+#define LAN8710A_DETECTED      (1 << 0)
+#define LAN8710A_ENABLED       (1 << 1)
+#define LAN8710A_READING       (1 << 2)
+#define LAN8710A_WRITING       (1 << 3)
+#define LAN8710A_RECEIVED      (1 << 4)
+#define LAN8710A_TRANSMIT      (1 << 5)
+
+/* Descriptors flags */
+#define LAN8710A_DESC_FLAG_OWN         (1 << 29) /* ownership flag */
+#define LAN8710A_DESC_FLAG_SOP         (1 << 31) /* start of packet flag */
+#define LAN8710A_DESC_FLAG_EOP         (1 << 30) /* end of packet flag */
+
+/* Number of Tx and Rx interrupts */
+#define LAN8710A_RX_INTR               (41)
+#define LAN8710A_TX_INTR               (42)
+
+/* Values to be written after interrupt handle and interrupt masks*/
+#define RX_INT                         (1)
+#define TX_INT                         (2)
+
+/** Numbers of Tx DMA channels */
+#define TX_DMA_CHANNELS                        (8)
+
+/** Number of transmit descriptors */
+#define LAN8710A_NUM_TX_DESC           (255)
+
+/** Number of receive descriptors */
+#define LAN8710A_NUM_RX_DESC           (255)
+
+/** Number of I/O vectors to use. */
+#define LAN8710A_IOVEC_NR              (16)
+
+/** Size of each I/O buffer per descriptor. */
+#define LAN8710A_IOBUF_SIZE            (1520)
+
+/** MAC address override variable. */
+#define LAN8710A_ENVVAR                "LAN8710AETH"
+
+/** MAX DMA Channels */
+#define DMA_MAX_CHANNELS               (8)
+
+/* Setting of Tx descriptors */
+#define TX_DESC_TO_PORT1               (1 << 16)
+#define TX_DESC_TO_PORT_EN             (1 << 20)
+
+typedef struct lan8710a_desc_t
+{
+       u32_t  next_pointer;
+       u32_t  buffer_pointer;
+       u32_t  buffer_length_off;
+       u32_t  pkt_len_flags;
+} lan8710a_desc_t;
+
+typedef struct lan8710a_t
+{
+       lan8710a_desc_t  *rx_desc;
+       lan8710a_desc_t  *tx_desc;
+       phys_bytes  rx_desc_phy;
+       phys_bytes  tx_desc_phy;
+       char  name[LAN8710A_NAME_LEN];
+       int  status;
+       int  irq_rx_hook;       /* Rx interrupt Request Vector Hook. */
+       int  irq_tx_hook;       /* Tx interrupt Request Vector Hook. */
+       int  instance;
+       ether_addr_t  address;  /* Ethernet MAC address. */
+       u8_t  *regs;
+       u32_t  phy_address;
+       u8_t  *p_rx_buf;        /* pointer to the buffer with receive frames */
+       u8_t  *p_tx_buf;        /* pointer to the buffer with transmit frames */
+
+       u16_t  tx_desc_idx;     /* index of the next transmit desciptor */
+       u16_t  rx_desc_idx;     /* index of the next receive desciptor */
+       int  client;
+       message  tx_message;
+       message  rx_message;
+       unsigned int  rx_size;
+
+       /* register mapping */
+       vir_bytes  regs_cp_per;
+       vir_bytes  regs_mdio;
+       vir_bytes  regs_cpsw_cpdma;
+       vir_bytes  regs_ctrl_mod;
+       vir_bytes  regs_cpsw_sl;
+       vir_bytes  regs_cpsw_ss;
+       vir_bytes  regs_cpsw_stats;
+       vir_bytes  regs_cpsw_ale;
+       vir_bytes  regs_cpsw_wr;
+       vir_bytes  regs_intc;
+       vir_bytes  regs_cpdma_stram;
+} lan8710a_t;
+
+#endif /* LAN8710A_H_ */
diff --git a/drivers/lan8710a/lan8710a_reg.h b/drivers/lan8710a/lan8710a_reg.h
new file mode 100644 (file)
index 0000000..68a38be
--- /dev/null
@@ -0,0 +1,203 @@
+#ifndef LAN8710A_REG_H_
+#define LAN8710A_REG_H_
+
+/* How much memory we should map */
+#define MEMORY_LIMIT           (0x5302000)
+#define BEGINNING_DESC_MEM     (0x4A102000)
+#define DESC_MEMORY_LIMIT      (0x2000)
+#define BEGINNING_RX_DESC_MEM  (0x4A102000)
+#define BEGINNING_TX_DESC_MEM  (0x4A103000)
+
+/* MDIO Registers */
+#define MDIO_BASE_ADDR         (0x4A101000)
+#define MDIOVER                        ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x00))
+#define MDIOCONTROL            ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x04))
+#define MDIOALIVE              ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x08))
+#define MDIOLINK               ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x0C))
+#define MDIOLINKINTRAW         ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x10))
+#define MDIOLINKINTMASKED      ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x14))
+#define MDIOUSERINTRAW         ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x20))
+#define MDIOUSERINTMASKED      ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x24))
+#define MDIOUSERINTMASKSET     ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x28))
+#define MDIOUSERINTMASKCLR     ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x2C))
+#define MDIOUSERACCESS0                ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x80))
+#define MDIOUSERPHYSEL0                ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x84))
+#define MDIOUSERACCESS1                ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x88))
+#define MDIOUSERPHYSEL1                ((volatile u32_t *)( lan8710a_state.regs_mdio + 0x8C))
+
+#define MDIO_PREAMBLE          (1 << 20)
+#define MDCLK_DIVIDER          (0x255)
+#define MDIO_ENABLE            (1 << 30)
+#define MDIO_GO                        (1 << 31)
+#define MDIO_WRITE             (1 << 30)
+#define MDIO_ACK               (1 << 29)
+
+#define MDIO_REGADR            (21)
+#define MDIO_PHYADR            (16)
+#define MDIO_DATA              (0)
+
+/* CONTROL MODULE Registers */
+#define CTRL_MOD_BASE_ADR      (0x44E10000)
+#define CTRL_MAC_ID0_LO                ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x630))
+#define CTRL_MAC_ID0_HI                ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x634))
+#define GMII_SEL               ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x650))
+#define CONF_MII1_COL          ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x908))
+#define CONF_MII1_CRS          ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x90C))
+#define CONF_MII1_RX_ER                ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x910))
+#define CONF_MII1_TX_EN                ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x914))
+#define CONF_MII1_RX_DV                ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x918))
+#define CONF_MII1_TXD3         ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x91C))
+#define CONF_MII1_TXD2         ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x920))
+#define CONF_MII1_TXD1         ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x924))
+#define CONF_MII1_TXD0         ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x928))
+#define CONF_MII1_TX_CLK       ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x92C))
+#define CONF_MII1_RX_CLK       ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x930))
+#define CONF_MII1_RXD3         ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x934))
+#define CONF_MII1_RXD2         ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x938))
+#define CONF_MII1_RXD1         ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x93C))
+#define CONF_MII1_RXD0         ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x940))
+#define CONF_MDIO              ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x948))
+#define CONF_MDC               ((volatile u32_t *)( lan8710a_state.regs_ctrl_mod + 0x94C))
+
+#define CONF_MOD_SLEW_CTRL     (1 << 6)
+#define CONF_MOD_RX_ACTIVE     (1 << 5)
+#define CONF_MOD_PU_TYPESEL    (1 << 4)
+#define CONF_MOD_PUDEN         (1 << 3)
+#define CONF_MOD_MMODE_MII     (7 << 0)
+#define RMII1_IO_CLK_EN                (1 << 6)
+#define RGMII1_IDMODE          (1 << 4)
+#define GMII2_SEL_BIT1         (1 << 3)
+#define GMII2_SEL_BIT0         (1 << 2)
+#define GMII1_SEL_BIT1         (1 << 1)
+#define GMII1_SEL_BIT0         (1 << 0)
+
+/* CLOCK MODULE Registers */
+#define CM_PER_BASE_ADR                (0x44E00000)
+#define CM_PER_CPSW_CLKSTCTRL  ((volatile u32_t *)( lan8710a_state.regs_cp_per + 0x144))
+
+#define CM_PER_CPSW_CLKSTCTRL_BIT1     (1 << 1)
+#define CM_PER_CPSW_CLKSTCTRL_BIT0     (1 << 0)
+
+/* CPSW_ALE Registers */
+#define CPSW_ALE_BASE_ADR      (0x4A100D00)
+#define CPSW_ALE_CONTROL       ((volatile u32_t *)( lan8710a_state.regs_cpsw_ale + 0x08))
+#define CPSW_ALE_PORTCTL0      ((volatile u32_t *)( lan8710a_state.regs_cpsw_ale + 0x40))
+#define CPSW_ALE_PORTCTL1      ((volatile u32_t *)( lan8710a_state.regs_cpsw_ale + 0x44))
+
+#define CPSW_ALE_ENABLE                (1 << 31)
+#define CPSW_ALE_BYPASS                (1 << 4)
+#define CPSW_ALE_PORT_FWD      (3 << 0)
+
+/* CPSW_SL Registers */
+#define CPSW_SL_BASE_ADR       (0x4A100D80)
+#define CPSW_SL_MACCONTROL(x)  ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x04))
+#define CPSW_SL_SOFT_RESET(x)  ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x0C))
+#define CPSW_SL_RX_MAXLEN(x)   ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x10))
+#define CPSW_SL_BOFFTEST(x)    ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x14))
+#define CPSW_SL_EMCONTROL(x)   ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x20))
+#define CPSW_SL_RX_PRI_MAP(x)  ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x24))
+#define CPSW_SL_TX_GAP(x)      ((volatile u32_t *)( lan8710a_state.regs_cpsw_sl + ((x)-1)*64 + 0x28))
+
+#define CPSW_SL_GMII_EN                (1 << 5)
+#define CPSW_SL_FULLDUPLEX     (1 << 0)
+#define SOFT_RESET             (1 << 0)
+
+/* CPSW_STATS Registers */
+#define CPSW_STATS_BASE_ADR    (0x4A100900)
+#define CPSW_STATS_MEM_LIMIT   (0x90)
+#define CPSW_STAT_RX_GOOD      ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x00))
+#define CPSW_STAT_RX_CRC_ERR   ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x10))
+#define CPSW_STAT_RX_AGNCD_ERR ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x14))
+#define CPSW_STAT_RX_OVERSIZE  ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x18))
+#define CPSW_STAT_TX_GOOD      ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x34))
+#define CPSW_STAT_COLLISIONS   ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x48))
+#define CPSW_STAT_TX_UNDERRUN  ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x5C))
+#define CPSW_STAT_CARR_SENS_ERR        ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x60))
+#define CPSW_STAT_RX_OVERRUN   ((volatile u32_t *)( lan8710a_state.regs_cpsw_stats + 0x8C))
+
+/* CPSW_CPDMA Registers */
+#define CPSW_CPDMA_BASE_ADR    (0x4A100800)
+#define CPDMA_SOFT_RESET       ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x1C))
+#define CPDMA_TX_CONTROL       ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x04))
+#define CPDMA_RX_CONTROL       ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x14))
+#define CPDMA_CONTROL          ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x20))
+#define CPDMA_STATUS           ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x24))
+#define CPDMA_RX_BUFFER_OFFSET ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x28))
+#define CPDMA_EMCONTROL                ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x2C))
+#define CPDMA_TX_INTMASK_SET   ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x88))
+#define CPDMA_TX_INTMASK_CLEAR ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x8C))
+#define CPDMA_EOI_VECTOR       ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0x94))
+#define CPDMA_RX_INTMASK_SET   ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0xA8))
+#define CPDMA_RX_INTMASK_CLEAR ((volatile u32_t *)( lan8710a_state.regs_cpsw_cpdma + 0xAC))
+
+#define CPDMA_IDLE             (1 << 31)
+#define CPDMA_TX_RLIM          (0xFF << 8)
+#define CPDMA_NO_OFFSET                (0xFFFF << 0)
+#define CPDMA_RX_CEF           (1 << 4)
+#define CPDMA_CMD_IDLE         (1 << 3)
+#define RX_OFFLEN_BLOCK                (1 << 2)
+#define RX_OWNERSHIP           (1 << 1)
+#define TX_PTYPE               (1 << 0)
+#define CPDMA_TX_EN            (1 << 0)
+#define CPDMA_RX_EN            (1 << 0)
+#define CPDMA_FIRST_CHAN_INT   (1 << 0)
+#define CPDMA_ALL_CHAN_INT     (0xFF << 0)
+#define CPDMA_TX_PTYPE         (1 << 0)
+#define CPDMA_ERROR            (0x00F7F700)
+
+/* CPSW_SS Registers */
+#define CPSW_SS_BASE_ADR       (0x4A100000)
+#define CPSW_SS_SOFT_RESET     ((volatile u32_t *)( lan8710a_state.regs_cpsw_ss + 0x08))
+#define CPSW_SS_STAT_PORT_EN   ((volatile u32_t *)( lan8710a_state.regs_cpsw_ss + 0x0C))
+#define CPSW_SS_TX_START_WDS   ((volatile u32_t *)( lan8710a_state.regs_cpsw_ss + 0x20))
+
+#define CPSW_P2_STAT_EN                (1 << 2)
+#define CPSW_P1_STAT_EN                (1 << 1)
+#define CPSW_P0_STAT_EN                (1 << 0)
+
+/* CPSW_WR Registers */
+#define CPSW_WR_BASE_ADR       (0x4A101200)
+#define CPSW_WR_INT_CONTROL    ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x0C))
+#define CPSW_WR_C0_RX_EN       ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x14))
+#define CPSW_WR_C1_RX_EN       ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x24))
+#define CPSW_WR_C2_RX_EN       ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x34))
+#define CPSW_WR_C0_RX_STAT     ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x44))
+#define CPSW_WR_C0_TX_EN       ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x18))
+#define CPSW_WR_C0_TX_STAT     ((volatile u32_t *)( lan8710a_state.regs_cpsw_wr + 0x48))
+
+#define CPSW_FIRST_CHAN_INT    (1 << 0)
+#define CPSW_ALL_CHAN_INT      (0xFF << 0)
+
+/* INTERRUPTION CONTROLLER Registers */
+#define INTC_BASE_ADR          (0x48200000)
+#define INTC_SYSCONFIG         ((volatile u32_t *)( lan8710a_state.regs_intc + 0x10))
+#define INTC_IDLE              ((volatile u32_t *)( lan8710a_state.regs_intc + 0x50))
+#define INTC_MIR_CLEAR1                ((volatile u32_t *)( lan8710a_state.regs_intc + 0xA8))
+#define INTC_ILR(x)            ((volatile u32_t *)( lan8710a_state.regs_intc + 0x100 + 4*(x)))
+
+#define INTC_AUTOIDLE          (1 << 0)
+#define INTC_FUNCIDLE          (1 << 0)
+#define INTC_TURBO             (1 << 1)
+#define INTC_FIQnIRQ           (1 << 0)
+#define INTC_RX_MASK           (1 << 9)
+#define INTC_TX_MASK           (1 << 10)
+
+/* DMA STATERAM Registers */
+#define CPDMA_STRAM_BASE_ADR   (0x4A100A00)
+#define CPDMA_STRAM_TX_HDP(x)  ((volatile u32_t *)( lan8710a_state.regs_cpdma_stram + 4*(x)))
+#define CPDMA_STRAM_RX_HDP(x)  ((volatile u32_t *)( lan8710a_state.regs_cpdma_stram + 0x20 + 4*(x)))
+#define CPDMA_STRAM_TX_CP(x)   ((volatile u32_t *)( lan8710a_state.regs_cpdma_stram + 0x40 + 4*(x)))
+#define CPDMA_STRAM_RX_CP(x)   ((volatile u32_t *)( lan8710a_state.regs_cpdma_stram + 0x60 + 4*(x)))
+
+#define ALL_BITS               (0xFFFFFFFF)
+
+/* LAN8710A Registers */
+#define PHY_REGISTERS          (31)
+#define LAN8710A_CTRL_REG      (0)
+#define LAN8710A_STATUS_REG    (1)
+
+#define LAN8710A_SOFT_RESET    (1 << 15)
+#define LAN8710A_AUTO_NEG      (1 << 12)
+#define LAN8710A_AUTO_NEG_COMPL        (1 << 5)
+
+#endif /* LAN8710A_REG_H_ */