Atmel MACB ethernet driver
authorHaavard Skinnemoen <hskinnemoen@atmel.com>
Fri, 20 Jan 2006 09:03:34 +0000 (10:03 +0100)
committerHaavard Skinnemoen <hskinnemoen@atmel.com>
Sat, 14 Apr 2007 14:14:06 +0000 (16:14 +0200)
Driver for the Atmel MACB on-chip ethernet controller.

This driver has been tested on the ATSTK1000 board with a AT32AP7000
CPU. It should probably work on AT91SAM926x as well with some minor
modifications.

Hardware documentation can be found in the AT32AP7000 data sheet,
which can be downloaded from

http://www.atmel.com/dyn/products/datasheets.asp?family_id=682

Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
drivers/Makefile
drivers/macb.c [new file with mode: 0644]
drivers/macb.h [new file with mode: 0644]

index fffc22a5e1d72451739d67ffe17ba3df105c3fb1..2eac7c848558a8eb069e99e5ef9ade47f8a9bb4b 100644 (file)
@@ -32,7 +32,7 @@ COBJS = 3c589.o 5701rls.o ali512x.o atmel_usart.o \
          cs8900.o ct69000.o dataflash.o dc2114x.o dm9000x.o \
          e1000.o eepro100.o \
          i8042.o inca-ip_sw.o keyboard.o \
-         lan91c96.o \
+         lan91c96.o macb.o \
          natsemi.o ne2000.o netarm_eth.o netconsole.o \
          ns16550.o ns8382x.o ns87308.o ns7520_eth.o omap1510_i2c.o \
          omap24xx_i2c.o pci.o pci_auto.o pci_indirect.o \
diff --git a/drivers/macb.c b/drivers/macb.c
new file mode 100644 (file)
index 0000000..186ab19
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <common.h>
+
+#if defined(CONFIG_MACB) && (CONFIG_COMMANDS & (CFG_CMD_NET | CFG_CMD_MII))
+
+/*
+ * The u-boot networking stack is a little weird.  It seems like the
+ * networking core allocates receive buffers up front without any
+ * regard to the hardware that's supposed to actually receive those
+ * packets.
+ *
+ * The MACB receives packets into 128-byte receive buffers, so the
+ * buffers allocated by the core isn't very practical to use.  We'll
+ * allocate our own, but we need one such buffer in case a packet
+ * wraps around the DMA ring so that we have to copy it.
+ *
+ * Therefore, define CFG_RX_ETH_BUFFER to 1 in the board-specific
+ * configuration header.  This way, the core allocates one RX buffer
+ * and one TX buffer, each of which can hold a ethernet packet of
+ * maximum size.
+ *
+ * For some reason, the networking core unconditionally specifies a
+ * 32-byte packet "alignment" (which really should be called
+ * "padding").  MACB shouldn't need that, but we'll refrain from any
+ * core modifications here...
+ */
+
+#include <net.h>
+#include <malloc.h>
+
+#include <linux/mii.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+#include <asm/arch/clk.h>
+
+#include "macb.h"
+
+#define CFG_MACB_RX_BUFFER_SIZE                4096
+#define CFG_MACB_RX_RING_SIZE          (CFG_MACB_RX_BUFFER_SIZE / 128)
+#define CFG_MACB_TX_RING_SIZE          16
+#define CFG_MACB_TX_TIMEOUT            1000
+#define CFG_MACB_AUTONEG_TIMEOUT       5000000
+
+struct macb_dma_desc {
+       u32     addr;
+       u32     ctrl;
+};
+
+#define RXADDR_USED            0x00000001
+#define RXADDR_WRAP            0x00000002
+
+#define RXBUF_FRMLEN_MASK      0x00000fff
+#define RXBUF_FRAME_START      0x00004000
+#define RXBUF_FRAME_END                0x00008000
+#define RXBUF_TYPEID_MATCH     0x00400000
+#define RXBUF_ADDR4_MATCH      0x00800000
+#define RXBUF_ADDR3_MATCH      0x01000000
+#define RXBUF_ADDR2_MATCH      0x02000000
+#define RXBUF_ADDR1_MATCH      0x04000000
+#define RXBUF_BROADCAST                0x80000000
+
+#define TXBUF_FRMLEN_MASK      0x000007ff
+#define TXBUF_FRAME_END                0x00008000
+#define TXBUF_NOCRC            0x00010000
+#define TXBUF_EXHAUSTED                0x08000000
+#define TXBUF_UNDERRUN         0x10000000
+#define TXBUF_MAXRETRY         0x20000000
+#define TXBUF_WRAP             0x40000000
+#define TXBUF_USED             0x80000000
+
+struct macb_device {
+       void                    *regs;
+
+       unsigned int            rx_tail;
+       unsigned int            tx_head;
+       unsigned int            tx_tail;
+
+       void                    *rx_buffer;
+       void                    *tx_buffer;
+       struct macb_dma_desc    *rx_ring;
+       struct macb_dma_desc    *tx_ring;
+
+       unsigned long           rx_buffer_dma;
+       unsigned long           rx_ring_dma;
+       unsigned long           tx_ring_dma;
+
+       const struct device     *dev;
+       struct eth_device       netdev;
+       unsigned short          phy_addr;
+};
+#define to_macb(_nd) container_of(_nd, struct macb_device, netdev)
+
+static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
+{
+       unsigned long netctl;
+       unsigned long netstat;
+       unsigned long frame;
+
+       netctl = macb_readl(macb, NCR);
+       netctl |= MACB_BIT(MPE);
+       macb_writel(macb, NCR, netctl);
+
+       frame = (MACB_BF(SOF, 1)
+                | MACB_BF(RW, 1)
+                | MACB_BF(PHYA, macb->phy_addr)
+                | MACB_BF(REGA, reg)
+                | MACB_BF(CODE, 2)
+                | MACB_BF(DATA, value));
+       macb_writel(macb, MAN, frame);
+
+       do {
+               netstat = macb_readl(macb, NSR);
+       } while (!(netstat & MACB_BIT(IDLE)));
+
+       netctl = macb_readl(macb, NCR);
+       netctl &= ~MACB_BIT(MPE);
+       macb_writel(macb, NCR, netctl);
+}
+
+static u16 macb_mdio_read(struct macb_device *macb, u8 reg)
+{
+       unsigned long netctl;
+       unsigned long netstat;
+       unsigned long frame;
+
+       netctl = macb_readl(macb, NCR);
+       netctl |= MACB_BIT(MPE);
+       macb_writel(macb, NCR, netctl);
+
+       frame = (MACB_BF(SOF, 1)
+                | MACB_BF(RW, 2)
+                | MACB_BF(PHYA, macb->phy_addr)
+                | MACB_BF(REGA, reg)
+                | MACB_BF(CODE, 2));
+       macb_writel(macb, MAN, frame);
+
+       do {
+               netstat = macb_readl(macb, NSR);
+       } while (!(netstat & MACB_BIT(IDLE)));
+
+       frame = macb_readl(macb, MAN);
+
+       netctl = macb_readl(macb, NCR);
+       netctl &= ~MACB_BIT(MPE);
+       macb_writel(macb, NCR, netctl);
+
+       return MACB_BFEXT(DATA, frame);
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_NET)
+
+static int macb_send(struct eth_device *netdev, volatile void *packet,
+                    int length)
+{
+       struct macb_device *macb = to_macb(netdev);
+       unsigned long paddr, ctrl;
+       unsigned int tx_head = macb->tx_head;
+       int i;
+
+       paddr = dma_map_single(packet, length, DMA_TO_DEVICE);
+
+       ctrl = length & TXBUF_FRMLEN_MASK;
+       ctrl |= TXBUF_FRAME_END;
+       if (tx_head == (CFG_MACB_TX_RING_SIZE - 1)) {
+               ctrl |= TXBUF_WRAP;
+               macb->tx_head = 0;
+       } else
+               macb->tx_head++;
+
+       macb->tx_ring[tx_head].ctrl = ctrl;
+       macb->tx_ring[tx_head].addr = paddr;
+       macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART));
+
+       /*
+        * I guess this is necessary because the networking core may
+        * re-use the transmit buffer as soon as we return...
+        */
+       i = 0;
+       while (!(macb->tx_ring[tx_head].ctrl & TXBUF_USED)) {
+               if (i > CFG_MACB_TX_TIMEOUT) {
+                       printf("%s: TX timeout\n", netdev->name);
+                       break;
+               }
+               udelay(1);
+               i++;
+       }
+
+       dma_unmap_single(packet, length, paddr);
+
+       if (i <= CFG_MACB_TX_TIMEOUT) {
+               ctrl = macb->tx_ring[tx_head].ctrl;
+               if (ctrl & TXBUF_UNDERRUN)
+                       printf("%s: TX underrun\n", netdev->name);
+               if (ctrl & TXBUF_EXHAUSTED)
+                       printf("%s: TX buffers exhausted in mid frame\n",
+                              netdev->name);
+       }
+
+       /* No one cares anyway */
+       return 0;
+}
+
+static void reclaim_rx_buffers(struct macb_device *macb,
+                              unsigned int new_tail)
+{
+       unsigned int i;
+
+       i = macb->rx_tail;
+       while (i > new_tail) {
+               macb->rx_ring[i].addr &= ~RXADDR_USED;
+               i++;
+               if (i > CFG_MACB_RX_RING_SIZE)
+                       i = 0;
+       }
+
+       while (i < new_tail) {
+               macb->rx_ring[i].addr &= ~RXADDR_USED;
+               i++;
+       }
+
+       macb->rx_tail = new_tail;
+}
+
+static int macb_recv(struct eth_device *netdev)
+{
+       struct macb_device *macb = to_macb(netdev);
+       unsigned int rx_tail = macb->rx_tail;
+       void *buffer;
+       int length;
+       int wrapped = 0;
+       u32 status;
+
+       for (;;) {
+               if (!(macb->rx_ring[rx_tail].addr & RXADDR_USED))
+                       return -1;
+
+               status = macb->rx_ring[rx_tail].ctrl;
+               if (status & RXBUF_FRAME_START) {
+                       if (rx_tail != macb->rx_tail)
+                               reclaim_rx_buffers(macb, rx_tail);
+                       wrapped = 0;
+               }
+
+               if (status & RXBUF_FRAME_END) {
+                       buffer = macb->rx_buffer + 128 * macb->rx_tail;
+                       length = status & RXBUF_FRMLEN_MASK;
+                       if (wrapped) {
+                               unsigned int headlen, taillen;
+
+                               headlen = 128 * (CFG_MACB_RX_RING_SIZE
+                                                - macb->rx_tail);
+                               taillen = length - headlen;
+                               memcpy((void *)NetRxPackets[0],
+                                      buffer, headlen);
+                               memcpy((void *)NetRxPackets[0] + headlen,
+                                      macb->rx_buffer, taillen);
+                               buffer = (void *)NetRxPackets[0];
+                       }
+
+                       NetReceive(buffer, length);
+                       if (++rx_tail >= CFG_MACB_RX_RING_SIZE)
+                               rx_tail = 0;
+                       reclaim_rx_buffers(macb, rx_tail);
+               } else {
+                       if (++rx_tail >= CFG_MACB_RX_RING_SIZE) {
+                               wrapped = 1;
+                               rx_tail = 0;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int macb_phy_init(struct macb_device *macb)
+{
+       struct eth_device *netdev = &macb->netdev;
+       u32 ncfgr;
+       u16 phy_id, status, adv, lpa;
+       int media, speed, duplex;
+       int i;
+
+       /* Check if the PHY is up to snuff... */
+       phy_id = macb_mdio_read(macb, MII_PHYSID1);
+       if (phy_id == 0xffff) {
+               printf("%s: No PHY present\n", netdev->name);
+               return 0;
+       }
+
+       adv = ADVERTISE_CSMA | ADVERTISE_ALL;
+       macb_mdio_write(macb, MII_ADVERTISE, adv);
+       printf("%s: Starting autonegotiation...\n", netdev->name);
+       macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE
+                                        | BMCR_ANRESTART));
+
+#if 0
+       for (i = 0; i < 9; i++)
+               printf("mii%d: 0x%04x\n", i, macb_mdio_read(macb, i));
+#endif
+
+       for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
+               status = macb_mdio_read(macb, MII_BMSR);
+               if (status & BMSR_ANEGCOMPLETE)
+                       break;
+               udelay(100);
+       }
+
+       if (status & BMSR_ANEGCOMPLETE)
+               printf("%s: Autonegotiation complete\n", netdev->name);
+       else
+               printf("%s: Autonegotiation timed out (status=0x%04x)\n",
+                      netdev->name, status);
+
+       if (!(status & BMSR_LSTATUS)) {
+               for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
+                       udelay(100);
+                       status = macb_mdio_read(macb, MII_BMSR);
+                       if (status & BMSR_LSTATUS)
+                               break;
+               }
+       }
+
+       if (!(status & BMSR_LSTATUS)) {
+               printf("%s: link down (status: 0x%04x)\n",
+                      netdev->name, status);
+               return 0;
+       } else {
+               lpa = macb_mdio_read(macb, MII_LPA);
+               media = mii_nway_result(lpa & adv);
+               speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
+                        ? 1 : 0);
+               duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+               printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n",
+                      netdev->name,
+                      speed ? "100" : "10",
+                      duplex ? "full" : "half",
+                      lpa);
+
+               ncfgr = macb_readl(macb, NCFGR);
+               ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
+               if (speed)
+                       ncfgr |= MACB_BIT(SPD);
+               if (duplex)
+                       ncfgr |= MACB_BIT(FD);
+               macb_writel(macb, NCFGR, ncfgr);
+               return 1;
+       }
+}
+
+static int macb_init(struct eth_device *netdev, bd_t *bd)
+{
+       struct macb_device *macb = to_macb(netdev);
+       unsigned long paddr;
+       u32 hwaddr_bottom;
+       u16 hwaddr_top;
+       int i;
+
+       /*
+        * macb_halt should have been called at some point before now,
+        * so we'll assume the controller is idle.
+        */
+
+       /* initialize DMA descriptors */
+       paddr = macb->rx_buffer_dma;
+       for (i = 0; i < CFG_MACB_RX_RING_SIZE; i++) {
+               if (i == (CFG_MACB_RX_RING_SIZE - 1))
+                       paddr |= RXADDR_WRAP;
+               macb->rx_ring[i].addr = paddr;
+               macb->rx_ring[i].ctrl = 0;
+               paddr += 128;
+       }
+       for (i = 0; i < CFG_MACB_TX_RING_SIZE; i++) {
+               macb->tx_ring[i].addr = 0;
+               if (i == (CFG_MACB_TX_RING_SIZE - 1))
+                       macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP;
+               else
+                       macb->tx_ring[i].ctrl = TXBUF_USED;
+       }
+       macb->rx_tail = macb->tx_head = macb->tx_tail = 0;
+
+       macb_writel(macb, RBQP, macb->rx_ring_dma);
+       macb_writel(macb, TBQP, macb->tx_ring_dma);
+
+       /* set hardware address */
+       hwaddr_bottom = cpu_to_le32(*((u32 *)netdev->enetaddr));
+       macb_writel(macb, SA1B, hwaddr_bottom);
+       hwaddr_top = cpu_to_le16(*((u16 *)(netdev->enetaddr + 4)));
+       macb_writel(macb, SA1T, hwaddr_top);
+
+       /* choose RMII or MII mode. This depends on the board */
+#ifdef CONFIG_RMII
+       macb_writel(macb, USRIO, 0);
+#else
+       macb_writel(macb, USRIO, MACB_BIT(MII));
+#endif
+
+       if (!macb_phy_init(macb))
+               return 0;
+
+       /* Enable TX and RX */
+       macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE));
+
+       return 1;
+}
+
+static void macb_halt(struct eth_device *netdev)
+{
+       struct macb_device *macb = to_macb(netdev);
+       u32 ncr, tsr;
+
+       /* Halt the controller and wait for any ongoing transmission to end. */
+       ncr = macb_readl(macb, NCR);
+       ncr |= MACB_BIT(THALT);
+       macb_writel(macb, NCR, ncr);
+
+       do {
+               tsr = macb_readl(macb, TSR);
+       } while (tsr & MACB_BIT(TGO));
+
+       /* Disable TX and RX, and clear statistics */
+       macb_writel(macb, NCR, MACB_BIT(CLRSTAT));
+}
+
+int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
+{
+       struct macb_device *macb;
+       struct eth_device *netdev;
+       unsigned long macb_hz;
+       u32 ncfgr;
+
+       macb = malloc(sizeof(struct macb_device));
+       if (!macb) {
+               printf("Error: Failed to allocate memory for MACB%d\n", id);
+               return -1;
+       }
+       memset(macb, 0, sizeof(struct macb_device));
+
+       netdev = &macb->netdev;
+
+       macb->rx_buffer = dma_alloc_coherent(CFG_MACB_RX_BUFFER_SIZE,
+                                            &macb->rx_buffer_dma);
+       macb->rx_ring = dma_alloc_coherent(CFG_MACB_RX_RING_SIZE
+                                          * sizeof(struct macb_dma_desc),
+                                          &macb->rx_ring_dma);
+       macb->tx_ring = dma_alloc_coherent(CFG_MACB_TX_RING_SIZE
+                                          * sizeof(struct macb_dma_desc),
+                                          &macb->tx_ring_dma);
+
+       macb->regs = regs;
+       macb->phy_addr = phy_addr;
+
+       sprintf(netdev->name, "macb%d", id);
+       netdev->init = macb_init;
+       netdev->halt = macb_halt;
+       netdev->send = macb_send;
+       netdev->recv = macb_recv;
+
+       /*
+        * Do some basic initialization so that we at least can talk
+        * to the PHY
+        */
+       macb_hz = get_macb_pclk_rate(id);
+       if (macb_hz < 20000000)
+               ncfgr = MACB_BF(CLK, MACB_CLK_DIV8);
+       else if (macb_hz < 40000000)
+               ncfgr = MACB_BF(CLK, MACB_CLK_DIV16);
+       else if (macb_hz < 80000000)
+               ncfgr = MACB_BF(CLK, MACB_CLK_DIV32);
+       else
+               ncfgr = MACB_BF(CLK, MACB_CLK_DIV64);
+
+       macb_writel(macb, NCFGR, ncfgr);
+
+       eth_register(netdev);
+
+       return 0;
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_NET) */
+
+#if (CONFIG_COMMANDS & CFG_CMD_MII)
+
+int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value)
+{
+       unsigned long netctl;
+       unsigned long netstat;
+       unsigned long frame;
+       int iflag;
+
+       iflag = disable_interrupts();
+       netctl = macb_readl(&macb, EMACB_NCR);
+       netctl |= MACB_BIT(MPE);
+       macb_writel(&macb, EMACB_NCR, netctl);
+       if (iflag)
+               enable_interrupts();
+
+       frame = (MACB_BF(SOF, 1)
+                | MACB_BF(RW, 2)
+                | MACB_BF(PHYA, addr)
+                | MACB_BF(REGA, reg)
+                | MACB_BF(CODE, 2));
+       macb_writel(&macb, EMACB_MAN, frame);
+
+       do {
+               netstat = macb_readl(&macb, EMACB_NSR);
+       } while (!(netstat & MACB_BIT(IDLE)));
+
+       frame = macb_readl(&macb, EMACB_MAN);
+       *value = MACB_BFEXT(DATA, frame);
+
+       iflag = disable_interrupts();
+       netctl = macb_readl(&macb, EMACB_NCR);
+       netctl &= ~MACB_BIT(MPE);
+       macb_writel(&macb, EMACB_NCR, netctl);
+       if (iflag)
+               enable_interrupts();
+
+       return 0;
+}
+
+int miiphy_write(unsigned char addr, unsigned char reg, unsigned short value)
+{
+       unsigned long netctl;
+       unsigned long netstat;
+       unsigned long frame;
+       int iflag;
+
+       iflag = disable_interrupts();
+       netctl = macb_readl(&macb, EMACB_NCR);
+       netctl |= MACB_BIT(MPE);
+       macb_writel(&macb, EMACB_NCR, netctl);
+       if (iflag)
+               enable_interrupts();
+
+       frame = (MACB_BF(SOF, 1)
+                | MACB_BF(RW, 1)
+                | MACB_BF(PHYA, addr)
+                | MACB_BF(REGA, reg)
+                | MACB_BF(CODE, 2)
+                | MACB_BF(DATA, value));
+       macb_writel(&macb, EMACB_MAN, frame);
+
+       do {
+               netstat = macb_readl(&macb, EMACB_NSR);
+       } while (!(netstat & MACB_BIT(IDLE)));
+
+       iflag = disable_interrupts();
+       netctl = macb_readl(&macb, EMACB_NCR);
+       netctl &= ~MACB_BIT(MPE);
+       macb_writel(&macb, EMACB_NCR, netctl);
+       if (iflag)
+               enable_interrupts();
+
+       return 0;
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_MII) */
+
+#endif /* CONFIG_MACB */
diff --git a/drivers/macb.h b/drivers/macb.h
new file mode 100644 (file)
index 0000000..c778e4e
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __DRIVERS_MACB_H__
+#define __DRIVERS_MACB_H__
+
+/* MACB register offsets */
+#define MACB_NCR                               0x0000
+#define MACB_NCFGR                             0x0004
+#define MACB_NSR                               0x0008
+#define MACB_TSR                               0x0014
+#define MACB_RBQP                              0x0018
+#define MACB_TBQP                              0x001c
+#define MACB_RSR                               0x0020
+#define MACB_ISR                               0x0024
+#define MACB_IER                               0x0028
+#define MACB_IDR                               0x002c
+#define MACB_IMR                               0x0030
+#define MACB_MAN                               0x0034
+#define MACB_PTR                               0x0038
+#define MACB_PFR                               0x003c
+#define MACB_FTO                               0x0040
+#define MACB_SCF                               0x0044
+#define MACB_MCF                               0x0048
+#define MACB_FRO                               0x004c
+#define MACB_FCSE                              0x0050
+#define MACB_ALE                               0x0054
+#define MACB_DTF                               0x0058
+#define MACB_LCOL                              0x005c
+#define MACB_EXCOL                             0x0060
+#define MACB_TUND                              0x0064
+#define MACB_CSE                               0x0068
+#define MACB_RRE                               0x006c
+#define MACB_ROVR                              0x0070
+#define MACB_RSE                               0x0074
+#define MACB_ELE                               0x0078
+#define MACB_RJA                               0x007c
+#define MACB_USF                               0x0080
+#define MACB_STE                               0x0084
+#define MACB_RLE                               0x0088
+#define MACB_TPF                               0x008c
+#define MACB_HRB                               0x0090
+#define MACB_HRT                               0x0094
+#define MACB_SA1B                              0x0098
+#define MACB_SA1T                              0x009c
+#define MACB_SA2B                              0x00a0
+#define MACB_SA2T                              0x00a4
+#define MACB_SA3B                              0x00a8
+#define MACB_SA3T                              0x00ac
+#define MACB_SA4B                              0x00b0
+#define MACB_SA4T                              0x00b4
+#define MACB_TID                               0x00b8
+#define MACB_TPQ                               0x00bc
+#define MACB_USRIO                             0x00c0
+#define MACB_WOL                               0x00c4
+
+/* Bitfields in NCR */
+#define MACB_LB_OFFSET                         0
+#define MACB_LB_SIZE                           1
+#define MACB_LLB_OFFSET                                1
+#define MACB_LLB_SIZE                          1
+#define MACB_RE_OFFSET                         2
+#define MACB_RE_SIZE                           1
+#define MACB_TE_OFFSET                         3
+#define MACB_TE_SIZE                           1
+#define MACB_MPE_OFFSET                                4
+#define MACB_MPE_SIZE                          1
+#define MACB_CLRSTAT_OFFSET                    5
+#define MACB_CLRSTAT_SIZE                      1
+#define MACB_INCSTAT_OFFSET                    6
+#define MACB_INCSTAT_SIZE                      1
+#define MACB_WESTAT_OFFSET                     7
+#define MACB_WESTAT_SIZE                       1
+#define MACB_BP_OFFSET                         8
+#define MACB_BP_SIZE                           1
+#define MACB_TSTART_OFFSET                     9
+#define MACB_TSTART_SIZE                       1
+#define MACB_THALT_OFFSET                      10
+#define MACB_THALT_SIZE                                1
+#define MACB_NCR_TPF_OFFSET                    11
+#define MACB_NCR_TPF_SIZE                      1
+#define MACB_TZQ_OFFSET                                12
+#define MACB_TZQ_SIZE                          1
+
+/* Bitfields in NCFGR */
+#define MACB_SPD_OFFSET                                0
+#define MACB_SPD_SIZE                          1
+#define MACB_FD_OFFSET                         1
+#define MACB_FD_SIZE                           1
+#define MACB_BIT_RATE_OFFSET                   2
+#define MACB_BIT_RATE_SIZE                     1
+#define MACB_JFRAME_OFFSET                     3
+#define MACB_JFRAME_SIZE                       1
+#define MACB_CAF_OFFSET                                4
+#define MACB_CAF_SIZE                          1
+#define MACB_NBC_OFFSET                                5
+#define MACB_NBC_SIZE                          1
+#define MACB_NCFGR_MTI_OFFSET                  6
+#define MACB_NCFGR_MTI_SIZE                    1
+#define MACB_UNI_OFFSET                                7
+#define MACB_UNI_SIZE                          1
+#define MACB_BIG_OFFSET                                8
+#define MACB_BIG_SIZE                          1
+#define MACB_EAE_OFFSET                                9
+#define MACB_EAE_SIZE                          1
+#define MACB_CLK_OFFSET                                10
+#define MACB_CLK_SIZE                          2
+#define MACB_RTY_OFFSET                                12
+#define MACB_RTY_SIZE                          1
+#define MACB_PAE_OFFSET                                13
+#define MACB_PAE_SIZE                          1
+#define MACB_RBOF_OFFSET                       14
+#define MACB_RBOF_SIZE                         2
+#define MACB_RLCE_OFFSET                       16
+#define MACB_RLCE_SIZE                         1
+#define MACB_DRFCS_OFFSET                      17
+#define MACB_DRFCS_SIZE                                1
+#define MACB_EFRHD_OFFSET                      18
+#define MACB_EFRHD_SIZE                                1
+#define MACB_IRXFCS_OFFSET                     19
+#define MACB_IRXFCS_SIZE                       1
+
+/* Bitfields in NSR */
+#define MACB_NSR_LINK_OFFSET                   0
+#define MACB_NSR_LINK_SIZE                     1
+#define MACB_MDIO_OFFSET                       1
+#define MACB_MDIO_SIZE                         1
+#define MACB_IDLE_OFFSET                       2
+#define MACB_IDLE_SIZE                         1
+
+/* Bitfields in TSR */
+#define MACB_UBR_OFFSET                                0
+#define MACB_UBR_SIZE                          1
+#define MACB_COL_OFFSET                                1
+#define MACB_COL_SIZE                          1
+#define MACB_TSR_RLE_OFFSET                    2
+#define MACB_TSR_RLE_SIZE                      1
+#define MACB_TGO_OFFSET                                3
+#define MACB_TGO_SIZE                          1
+#define MACB_BEX_OFFSET                                4
+#define MACB_BEX_SIZE                          1
+#define MACB_COMP_OFFSET                       5
+#define MACB_COMP_SIZE                         1
+#define MACB_UND_OFFSET                                6
+#define MACB_UND_SIZE                          1
+
+/* Bitfields in RSR */
+#define MACB_BNA_OFFSET                                0
+#define MACB_BNA_SIZE                          1
+#define MACB_REC_OFFSET                                1
+#define MACB_REC_SIZE                          1
+#define MACB_OVR_OFFSET                                2
+#define MACB_OVR_SIZE                          1
+
+/* Bitfields in ISR/IER/IDR/IMR */
+#define MACB_MFD_OFFSET                                0
+#define MACB_MFD_SIZE                          1
+#define MACB_RCOMP_OFFSET                      1
+#define MACB_RCOMP_SIZE                                1
+#define MACB_RXUBR_OFFSET                      2
+#define MACB_RXUBR_SIZE                                1
+#define MACB_TXUBR_OFFSET                      3
+#define MACB_TXUBR_SIZE                                1
+#define MACB_ISR_TUND_OFFSET                   4
+#define MACB_ISR_TUND_SIZE                     1
+#define MACB_ISR_RLE_OFFSET                    5
+#define MACB_ISR_RLE_SIZE                      1
+#define MACB_TXERR_OFFSET                      6
+#define MACB_TXERR_SIZE                                1
+#define MACB_TCOMP_OFFSET                      7
+#define MACB_TCOMP_SIZE                                1
+#define MACB_ISR_LINK_OFFSET                   9
+#define MACB_ISR_LINK_SIZE                     1
+#define MACB_ISR_ROVR_OFFSET                   10
+#define MACB_ISR_ROVR_SIZE                     1
+#define MACB_HRESP_OFFSET                      11
+#define MACB_HRESP_SIZE                                1
+#define MACB_PFR_OFFSET                                12
+#define MACB_PFR_SIZE                          1
+#define MACB_PTZ_OFFSET                                13
+#define MACB_PTZ_SIZE                          1
+
+/* Bitfields in MAN */
+#define MACB_DATA_OFFSET                       0
+#define MACB_DATA_SIZE                         16
+#define MACB_CODE_OFFSET                       16
+#define MACB_CODE_SIZE                         2
+#define MACB_REGA_OFFSET                       18
+#define MACB_REGA_SIZE                         5
+#define MACB_PHYA_OFFSET                       23
+#define MACB_PHYA_SIZE                         5
+#define MACB_RW_OFFSET                         28
+#define MACB_RW_SIZE                           2
+#define MACB_SOF_OFFSET                                30
+#define MACB_SOF_SIZE                          2
+
+/* Bitfields in USRIO */
+#define MACB_MII_OFFSET                                0
+#define MACB_MII_SIZE                          1
+#define MACB_EAM_OFFSET                                1
+#define MACB_EAM_SIZE                          1
+#define MACB_TX_PAUSE_OFFSET                   2
+#define MACB_TX_PAUSE_SIZE                     1
+#define MACB_TX_PAUSE_ZERO_OFFSET              3
+#define MACB_TX_PAUSE_ZERO_SIZE                        1
+
+/* Bitfields in WOL */
+#define MACB_IP_OFFSET                         0
+#define MACB_IP_SIZE                           16
+#define MACB_MAG_OFFSET                                16
+#define MACB_MAG_SIZE                          1
+#define MACB_ARP_OFFSET                                17
+#define MACB_ARP_SIZE                          1
+#define MACB_SA1_OFFSET                                18
+#define MACB_SA1_SIZE                          1
+#define MACB_WOL_MTI_OFFSET                    19
+#define MACB_WOL_MTI_SIZE                      1
+
+/* Constants for CLK */
+#define MACB_CLK_DIV8                          0
+#define MACB_CLK_DIV16                         1
+#define MACB_CLK_DIV32                         2
+#define MACB_CLK_DIV64                         3
+
+/* Constants for MAN register */
+#define MACB_MAN_SOF                           1
+#define MACB_MAN_WRITE                         1
+#define MACB_MAN_READ                          2
+#define MACB_MAN_CODE                          2
+
+/* Bit manipulation macros */
+#define MACB_BIT(name)                                 \
+       (1 << MACB_##name##_OFFSET)
+#define MACB_BF(name,value)                            \
+       (((value) & ((1 << MACB_##name##_SIZE) - 1))    \
+        << MACB_##name##_OFFSET)
+#define MACB_BFEXT(name,value)\
+       (((value) >> MACB_##name##_OFFSET)              \
+        & ((1 << MACB_##name##_SIZE) - 1))
+#define MACB_BFINS(name,value,old)                     \
+       (((old) & ~(((1 << MACB_##name##_SIZE) - 1)     \
+                   << MACB_##name##_OFFSET))           \
+        | MACB_BF(name,value))
+
+/* Register access macros */
+#define macb_readl(port,reg)                           \
+       readl((port)->regs + MACB_##reg)
+#define macb_writel(port,reg,value)                    \
+       writel((value), (port)->regs + MACB_##reg)
+
+#endif /* __DRIVERS_MACB_H__ */