]> git.sur5r.net Git - u-boot/commitdiff
net: Rename and cleanup sunxi (Allwinner) emac driver
authorStefan Roese <sr@denx.de>
Mon, 9 Jun 2014 09:36:59 +0000 (11:36 +0200)
committerIan Campbell <ijc@hellion.org.uk>
Sun, 6 Jul 2014 19:12:44 +0000 (20:12 +0100)
There have been 3 versions of the sunxi_emac support patch during its
development. Somehow version 2 ended up in upstream u-boot where as
the u-boot-sunxi git repo got version 3.

This bumps the version in upstream u-boot to version 3 of the patch:
- Initialize MII clock earlier so mii access to allow independent use
- Name change from WEMAC to EMAC to match mainline kernel & chip manual
- Cosmetic code cleanup

Signed-off-by: Stefan Roese <sr@denx.de>
Signed-off-by: Henrik Nordstrom <henrik@henriknordstrom.net>
Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Ian Campbell <ijc@hellion.org.uk>
drivers/net/Makefile
drivers/net/sunxi_emac.c [new file with mode: 0644]
drivers/net/sunxi_wemac.c [deleted file]
include/netdev.h

index 6226cb259f8d7a92a73830b1c50889768fb2455b..7cc6b6fc0861a8efcf6318a1e7c3b8041bf49f0e 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_DNET) += dnet.o
 obj-$(CONFIG_E1000) += e1000.o
 obj-$(CONFIG_E1000_SPI) += e1000_spi.o
 obj-$(CONFIG_EEPRO100) += eepro100.o
+obj-$(CONFIG_SUNXI_EMAC) += sunxi_emac.o
 obj-$(CONFIG_ENC28J60) += enc28j60.o
 obj-$(CONFIG_EP93XX) += ep93xx_eth.o
 obj-$(CONFIG_ETHOC) += ethoc.o
@@ -51,7 +52,6 @@ obj-$(CONFIG_RTL8169) += rtl8169.o
 obj-$(CONFIG_SH_ETHER) += sh_eth.o
 obj-$(CONFIG_SMC91111) += smc91111.o
 obj-$(CONFIG_SMC911X) += smc911x.o
-obj-$(CONFIG_SUNXI_WEMAC) += sunxi_wemac.o
 obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
 obj-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o
 obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o
diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c
new file mode 100644 (file)
index 0000000..5a06d68
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * sunxi_emac.c -- Allwinner A10 ethernet driver
+ *
+ * (C) Copyright 2012, Stefan Roese <sr@denx.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <net.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+
+/* EMAC register  */
+struct emac_regs {
+       u32 ctl;        /* 0x00 */
+       u32 tx_mode;    /* 0x04 */
+       u32 tx_flow;    /* 0x08 */
+       u32 tx_ctl0;    /* 0x0c */
+       u32 tx_ctl1;    /* 0x10 */
+       u32 tx_ins;     /* 0x14 */
+       u32 tx_pl0;     /* 0x18 */
+       u32 tx_pl1;     /* 0x1c */
+       u32 tx_sta;     /* 0x20 */
+       u32 tx_io_data; /* 0x24 */
+       u32 tx_io_data1;/* 0x28 */
+       u32 tx_tsvl0;   /* 0x2c */
+       u32 tx_tsvh0;   /* 0x30 */
+       u32 tx_tsvl1;   /* 0x34 */
+       u32 tx_tsvh1;   /* 0x38 */
+       u32 rx_ctl;     /* 0x3c */
+       u32 rx_hash0;   /* 0x40 */
+       u32 rx_hash1;   /* 0x44 */
+       u32 rx_sta;     /* 0x48 */
+       u32 rx_io_data; /* 0x4c */
+       u32 rx_fbc;     /* 0x50 */
+       u32 int_ctl;    /* 0x54 */
+       u32 int_sta;    /* 0x58 */
+       u32 mac_ctl0;   /* 0x5c */
+       u32 mac_ctl1;   /* 0x60 */
+       u32 mac_ipgt;   /* 0x64 */
+       u32 mac_ipgr;   /* 0x68 */
+       u32 mac_clrt;   /* 0x6c */
+       u32 mac_maxf;   /* 0x70 */
+       u32 mac_supp;   /* 0x74 */
+       u32 mac_test;   /* 0x78 */
+       u32 mac_mcfg;   /* 0x7c */
+       u32 mac_mcmd;   /* 0x80 */
+       u32 mac_madr;   /* 0x84 */
+       u32 mac_mwtd;   /* 0x88 */
+       u32 mac_mrdd;   /* 0x8c */
+       u32 mac_mind;   /* 0x90 */
+       u32 mac_ssrr;   /* 0x94 */
+       u32 mac_a0;     /* 0x98 */
+       u32 mac_a1;     /* 0x9c */
+};
+
+/* SRAMC register  */
+struct sunxi_sramc_regs {
+       u32 ctrl0;
+       u32 ctrl1;
+};
+
+/* 0: Disable       1: Aborted frame enable(default) */
+#define EMAC_TX_AB_M           (0x1 << 0)
+/* 0: CPU           1: DMA(default) */
+#define EMAC_TX_TM             (0x1 << 1)
+
+#define EMAC_TX_SETUP          (0)
+
+/* 0: DRQ asserted  1: DRQ automatically(default) */
+#define EMAC_RX_DRQ_MODE       (0x1 << 1)
+/* 0: CPU           1: DMA(default) */
+#define EMAC_RX_TM             (0x1 << 2)
+/* 0: Normal(default)        1: Pass all Frames */
+#define EMAC_RX_PA             (0x1 << 4)
+/* 0: Normal(default)        1: Pass Control Frames */
+#define EMAC_RX_PCF            (0x1 << 5)
+/* 0: Normal(default)        1: Pass Frames with CRC Error */
+#define EMAC_RX_PCRCE          (0x1 << 6)
+/* 0: Normal(default)        1: Pass Frames with Length Error */
+#define EMAC_RX_PLE            (0x1 << 7)
+/* 0: Normal                 1: Pass Frames length out of range(default) */
+#define EMAC_RX_POR            (0x1 << 8)
+/* 0: Not accept             1: Accept unicast Packets(default) */
+#define EMAC_RX_UCAD           (0x1 << 16)
+/* 0: Normal(default)        1: DA Filtering */
+#define EMAC_RX_DAF            (0x1 << 17)
+/* 0: Not accept             1: Accept multicast Packets(default) */
+#define EMAC_RX_MCO            (0x1 << 20)
+/* 0: Disable(default)       1: Enable Hash filter */
+#define EMAC_RX_MHF            (0x1 << 21)
+/* 0: Not accept             1: Accept Broadcast Packets(default) */
+#define EMAC_RX_BCO            (0x1 << 22)
+/* 0: Disable(default)       1: Enable SA Filtering */
+#define EMAC_RX_SAF            (0x1 << 24)
+/* 0: Normal(default)        1: Inverse Filtering */
+#define EMAC_RX_SAIF           (0x1 << 25)
+
+#define EMAC_RX_SETUP          (EMAC_RX_POR | EMAC_RX_UCAD | EMAC_RX_DAF | \
+                                EMAC_RX_MCO | EMAC_RX_BCO)
+
+/* 0: Disable                1: Enable Receive Flow Control(default) */
+#define EMAC_MAC_CTL0_RFC      (0x1 << 2)
+/* 0: Disable                1: Enable Transmit Flow Control(default) */
+#define EMAC_MAC_CTL0_TFC      (0x1 << 3)
+
+#define EMAC_MAC_CTL0_SETUP    (EMAC_MAC_CTL0_RFC | EMAC_MAC_CTL0_TFC)
+
+/* 0: Disable                1: Enable MAC Frame Length Checking(default) */
+#define EMAC_MAC_CTL1_FLC      (0x1 << 1)
+/* 0: Disable(default)       1: Enable Huge Frame */
+#define EMAC_MAC_CTL1_HF       (0x1 << 2)
+/* 0: Disable(default)       1: Enable MAC Delayed CRC */
+#define EMAC_MAC_CTL1_DCRC     (0x1 << 3)
+/* 0: Disable                1: Enable MAC CRC(default) */
+#define EMAC_MAC_CTL1_CRC      (0x1 << 4)
+/* 0: Disable                1: Enable MAC PAD Short frames(default) */
+#define EMAC_MAC_CTL1_PC       (0x1 << 5)
+/* 0: Disable(default)       1: Enable MAC PAD Short frames and append CRC */
+#define EMAC_MAC_CTL1_VC       (0x1 << 6)
+/* 0: Disable(default)       1: Enable MAC auto detect Short frames */
+#define EMAC_MAC_CTL1_ADP      (0x1 << 7)
+/* 0: Disable(default)       1: Enable */
+#define EMAC_MAC_CTL1_PRE      (0x1 << 8)
+/* 0: Disable(default)       1: Enable */
+#define EMAC_MAC_CTL1_LPE      (0x1 << 9)
+/* 0: Disable(default)       1: Enable no back off */
+#define EMAC_MAC_CTL1_NB       (0x1 << 12)
+/* 0: Disable(default)       1: Enable */
+#define EMAC_MAC_CTL1_BNB      (0x1 << 13)
+/* 0: Disable(default)       1: Enable */
+#define EMAC_MAC_CTL1_ED       (0x1 << 14)
+
+#define EMAC_MAC_CTL1_SETUP    (EMAC_MAC_CTL1_FLC | EMAC_MAC_CTL1_CRC | \
+                                EMAC_MAC_CTL1_PC)
+
+#define EMAC_MAC_IPGT          0x15
+
+#define EMAC_MAC_NBTB_IPG1     0xc
+#define EMAC_MAC_NBTB_IPG2     0x12
+
+#define EMAC_MAC_CW            0x37
+#define EMAC_MAC_RM            0xf
+
+#define EMAC_MAC_MFL           0x0600
+
+/* Receive status */
+#define EMAC_CRCERR            (0x1 << 4)
+#define EMAC_LENERR            (0x3 << 5)
+
+#define DMA_CPU_TRRESHOLD      2000
+
+struct emac_eth_dev {
+       u32 speed;
+       u32 duplex;
+       u32 phy_configured;
+       int link_printed;
+};
+
+struct emac_rxhdr {
+       s16 rx_len;
+       u16 rx_status;
+};
+
+static void emac_inblk_32bit(void *reg, void *data, int count)
+{
+       int cnt = (count + 3) >> 2;
+
+       if (cnt) {
+               u32 *buf = data;
+
+               do {
+                       u32 x = readl(reg);
+                       *buf++ = x;
+               } while (--cnt);
+       }
+}
+
+static void emac_outblk_32bit(void *reg, void *data, int count)
+{
+       int cnt = (count + 3) >> 2;
+
+       if (cnt) {
+               const u32 *buf = data;
+
+               do {
+                       writel(*buf++, reg);
+               } while (--cnt);
+       }
+}
+
+/* Read a word from phyxcer */
+static int emac_phy_read(const char *devname, unsigned char addr,
+                         unsigned char reg, unsigned short *value)
+{
+       struct eth_device *dev = eth_get_dev_by_name(devname);
+       struct emac_regs *regs = (struct emac_regs *)dev->iobase;
+
+       /* issue the phy address and reg */
+       writel(addr << 8 | reg, &regs->mac_madr);
+
+       /* pull up the phy io line */
+       writel(0x1, &regs->mac_mcmd);
+
+       /* Wait read complete */
+       mdelay(1);
+
+       /* push down the phy io line */
+       writel(0x0, &regs->mac_mcmd);
+
+       /* and write data */
+       *value = readl(&regs->mac_mrdd);
+
+       return 0;
+}
+
+/* Write a word to phyxcer */
+static int emac_phy_write(const char *devname, unsigned char addr,
+                          unsigned char reg, unsigned short value)
+{
+       struct eth_device *dev = eth_get_dev_by_name(devname);
+       struct emac_regs *regs = (struct emac_regs *)dev->iobase;
+
+       /* issue the phy address and reg */
+       writel(addr << 8 | reg, &regs->mac_madr);
+
+       /* pull up the phy io line */
+       writel(0x1, &regs->mac_mcmd);
+
+       /* Wait write complete */
+       mdelay(1);
+
+       /* push down the phy io line */
+       writel(0x0, &regs->mac_mcmd);
+
+       /* and write data */
+       writel(value, &regs->mac_mwtd);
+
+       return 0;
+}
+
+static void emac_setup(struct eth_device *dev)
+{
+       struct emac_regs *regs = (struct emac_regs *)dev->iobase;
+       u32 reg_val;
+       u16 phy_val;
+       u32 duplex_flag;
+
+       /* Set up TX */
+       writel(EMAC_TX_SETUP, &regs->tx_mode);
+
+       /* Set up RX */
+       writel(EMAC_RX_SETUP, &regs->rx_ctl);
+
+       /* Set MAC */
+       /* Set MAC CTL0 */
+       writel(EMAC_MAC_CTL0_SETUP, &regs->mac_ctl0);
+
+       /* Set MAC CTL1 */
+       emac_phy_read(dev->name, 1, 0, &phy_val);
+       debug("PHY SETUP, reg 0 value: %x\n", phy_val);
+       duplex_flag = !!(phy_val & (1 << 8));
+
+       reg_val = 0;
+       if (duplex_flag)
+               reg_val = (0x1 << 0);
+       writel(EMAC_MAC_CTL1_SETUP | reg_val, &regs->mac_ctl1);
+
+       /* Set up IPGT */
+       writel(EMAC_MAC_IPGT, &regs->mac_ipgt);
+
+       /* Set up IPGR */
+       writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), &regs->mac_ipgr);
+
+       /* Set up Collison window */
+       writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), &regs->mac_clrt);
+
+       /* Set up Max Frame Length */
+       writel(EMAC_MAC_MFL, &regs->mac_maxf);
+}
+
+static void emac_reset(struct eth_device *dev)
+{
+       struct emac_regs *regs = (struct emac_regs *)dev->iobase;
+
+       debug("resetting device\n");
+
+       /* RESET device */
+       writel(0, &regs->ctl);
+       udelay(200);
+
+       writel(1, &regs->ctl);
+       udelay(200);
+}
+
+static int sunxi_emac_eth_init(struct eth_device *dev, bd_t *bd)
+{
+       struct emac_regs *regs = (struct emac_regs *)dev->iobase;
+       struct emac_eth_dev *priv = dev->priv;
+       u16 phy_reg;
+
+       /* Init EMAC */
+
+       /* Flush RX FIFO */
+       setbits_le32(&regs->rx_ctl, 0x8);
+       udelay(1);
+
+       /* Init MAC */
+
+       /* Soft reset MAC */
+       clrbits_le32(&regs->mac_ctl0, 0x1 << 15);
+
+       /* Clear RX counter */
+       writel(0x0, &regs->rx_fbc);
+       udelay(1);
+
+       /* Set up EMAC */
+       emac_setup(dev);
+
+       writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 |
+              dev->enetaddr[2], &regs->mac_a1);
+       writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 |
+              dev->enetaddr[5], &regs->mac_a0);
+
+       mdelay(1);
+
+       emac_reset(dev);
+
+       /* PHY POWER UP */
+       emac_phy_read(dev->name, 1, 0, &phy_reg);
+       emac_phy_write(dev->name, 1, 0, phy_reg & (~(0x1 << 11)));
+       mdelay(1);
+
+       emac_phy_read(dev->name, 1, 0, &phy_reg);
+
+       priv->speed = miiphy_speed(dev->name, 0);
+       priv->duplex = miiphy_duplex(dev->name, 0);
+
+       /* Print link status only once */
+       if (!priv->link_printed) {
+               printf("ENET Speed is %d Mbps - %s duplex connection\n",
+                      priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL");
+               priv->link_printed = 1;
+       }
+
+       /* Set EMAC SPEED depend on PHY */
+       clrsetbits_le32(&regs->mac_supp, 1 << 8,
+                       ((phy_reg & (0x1 << 13)) >> 13) << 8);
+
+       /* Set duplex depend on phy */
+       clrsetbits_le32(&regs->mac_ctl1, 1 << 0,
+                       ((phy_reg & (0x1 << 8)) >> 8) << 0);
+
+       /* Enable RX/TX */
+       setbits_le32(&regs->ctl, 0x7);
+
+       return 0;
+}
+
+static void sunxi_emac_eth_halt(struct eth_device *dev)
+{
+       /* Nothing to do here */
+}
+
+static int sunxi_emac_eth_recv(struct eth_device *dev)
+{
+       struct emac_regs *regs = (struct emac_regs *)dev->iobase;
+       struct emac_rxhdr rxhdr;
+       u32 rxcount;
+       u32 reg_val;
+       int rx_len;
+       int rx_status;
+       int good_packet;
+
+       /* Check packet ready or not */
+
+       /* Race warning: The first packet might arrive with
+        * the interrupts disabled, but the second will fix
+        */
+       rxcount = readl(&regs->rx_fbc);
+       if (!rxcount) {
+               /* Had one stuck? */
+               rxcount = readl(&regs->rx_fbc);
+               if (!rxcount)
+                       return 0;
+       }
+
+       reg_val = readl(&regs->rx_io_data);
+       if (reg_val != 0x0143414d) {
+               /* Disable RX */
+               clrbits_le32(&regs->ctl, 0x1 << 2);
+
+               /* Flush RX FIFO */
+               setbits_le32(&regs->rx_ctl, 0x1 << 3);
+               while (readl(&regs->rx_ctl) & (0x1 << 3))
+                       ;
+
+               /* Enable RX */
+               setbits_le32(&regs->ctl, 0x1 << 2);
+
+               return 0;
+       }
+
+       /* A packet ready now
+        * Get status/length
+        */
+       good_packet = 1;
+
+       emac_inblk_32bit(&regs->rx_io_data, &rxhdr, sizeof(rxhdr));
+
+       rx_len = rxhdr.rx_len;
+       rx_status = rxhdr.rx_status;
+
+       /* Packet Status check */
+       if (rx_len < 0x40) {
+               good_packet = 0;
+               debug("RX: Bad Packet (runt)\n");
+       }
+
+       /* rx_status is identical to RSR register. */
+       if (0 & rx_status & (EMAC_CRCERR | EMAC_LENERR)) {
+               good_packet = 0;
+               if (rx_status & EMAC_CRCERR)
+                       printf("crc error\n");
+               if (rx_status & EMAC_LENERR)
+                       printf("length error\n");
+       }
+
+       /* Move data from EMAC */
+       if (good_packet) {
+               if (rx_len > DMA_CPU_TRRESHOLD) {
+                       printf("Received packet is too big (len=%d)\n", rx_len);
+               } else {
+                       emac_inblk_32bit((void *)&regs->rx_io_data,
+                                        NetRxPackets[0], rx_len);
+
+                       /* Pass to upper layer */
+                       NetReceive(NetRxPackets[0], rx_len);
+                       return rx_len;
+               }
+       }
+
+       return 0;
+}
+
+static int sunxi_emac_eth_send(struct eth_device *dev, void *packet, int len)
+{
+       struct emac_regs *regs = (struct emac_regs *)dev->iobase;
+
+       /* Select channel 0 */
+       writel(0, &regs->tx_ins);
+
+       /* Write packet */
+       emac_outblk_32bit((void *)&regs->tx_io_data, packet, len);
+
+       /* Set TX len */
+       writel(len, &regs->tx_pl0);
+
+       /* Start translate from fifo to phy */
+       setbits_le32(&regs->tx_ctl0, 1);
+
+       return 0;
+}
+
+int sunxi_emac_initialize(void)
+{
+       struct sunxi_ccm_reg *const ccm =
+               (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+       struct sunxi_sramc_regs *sram =
+               (struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE;
+       struct emac_regs *regs =
+               (struct emac_regs *)SUNXI_EMAC_BASE;
+       struct eth_device *dev;
+       struct emac_eth_dev *priv;
+       int pin;
+
+       dev = malloc(sizeof(*dev));
+       if (dev == NULL)
+               return -ENOMEM;
+
+       priv = (struct emac_eth_dev *)malloc(sizeof(struct emac_eth_dev));
+       if (!priv) {
+               free(dev);
+               return -ENOMEM;
+       }
+
+       memset(dev, 0, sizeof(*dev));
+       memset(priv, 0, sizeof(struct emac_eth_dev));
+
+       /* Map SRAM to EMAC */
+       setbits_le32(&sram->ctrl1, 0x5 << 2);
+
+       /* Configure pin mux settings for MII Ethernet */
+       for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++)
+               sunxi_gpio_set_cfgpin(pin, SUNXI_GPA0_EMAC);
+
+       /* Set up clock gating */
+       setbits_le32(&ccm->ahb_gate0, 0x1 << AHB_GATE_OFFSET_EMAC);
+
+       /* Set MII clock */
+       clrsetbits_le32(&regs->mac_mcfg, 0xf << 2, 0xd << 2);
+
+       dev->iobase = (int)regs;
+       dev->priv = priv;
+       dev->init = sunxi_emac_eth_init;
+       dev->halt = sunxi_emac_eth_halt;
+       dev->send = sunxi_emac_eth_send;
+       dev->recv = sunxi_emac_eth_recv;
+       strcpy(dev->name, "emac");
+
+       eth_register(dev);
+
+       miiphy_register(dev->name, emac_phy_read, emac_phy_write);
+
+       return 0;
+}
diff --git a/drivers/net/sunxi_wemac.c b/drivers/net/sunxi_wemac.c
deleted file mode 100644 (file)
index 699a381..0000000
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * sunxi_wemac.c -- Allwinner A10 ethernet driver
- *
- * (C) Copyright 2012, Stefan Roese <sr@denx.de>
- *
- * SPDX-License-Identifier:    GPL-2.0+
- */
-
-#include <common.h>
-#include <malloc.h>
-#include <net.h>
-#include <miiphy.h>
-#include <linux/err.h>
-#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/gpio.h>
-
-/* EMAC register  */
-struct wemac_regs {
-       u32 ctl;        /* 0x00 */
-       u32 tx_mode;    /* 0x04 */
-       u32 tx_flow;    /* 0x08 */
-       u32 tx_ctl0;    /* 0x0c */
-       u32 tx_ctl1;    /* 0x10 */
-       u32 tx_ins;     /* 0x14 */
-       u32 tx_pl0;     /* 0x18 */
-       u32 tx_pl1;     /* 0x1c */
-       u32 tx_sta;     /* 0x20 */
-       u32 tx_io_data; /* 0x24 */
-       u32 tx_io_data1; /* 0x28 */
-       u32 tx_tsvl0;   /* 0x2c */
-       u32 tx_tsvh0;   /* 0x30 */
-       u32 tx_tsvl1;   /* 0x34 */
-       u32 tx_tsvh1;   /* 0x38 */
-       u32 rx_ctl;     /* 0x3c */
-       u32 rx_hash0;   /* 0x40 */
-       u32 rx_hash1;   /* 0x44 */
-       u32 rx_sta;     /* 0x48 */
-       u32 rx_io_data; /* 0x4c */
-       u32 rx_fbc;     /* 0x50 */
-       u32 int_ctl;    /* 0x54 */
-       u32 int_sta;    /* 0x58 */
-       u32 mac_ctl0;   /* 0x5c */
-       u32 mac_ctl1;   /* 0x60 */
-       u32 mac_ipgt;   /* 0x64 */
-       u32 mac_ipgr;   /* 0x68 */
-       u32 mac_clrt;   /* 0x6c */
-       u32 mac_maxf;   /* 0x70 */
-       u32 mac_supp;   /* 0x74 */
-       u32 mac_test;   /* 0x78 */
-       u32 mac_mcfg;   /* 0x7c */
-       u32 mac_mcmd;   /* 0x80 */
-       u32 mac_madr;   /* 0x84 */
-       u32 mac_mwtd;   /* 0x88 */
-       u32 mac_mrdd;   /* 0x8c */
-       u32 mac_mind;   /* 0x90 */
-       u32 mac_ssrr;   /* 0x94 */
-       u32 mac_a0;     /* 0x98 */
-       u32 mac_a1;     /* 0x9c */
-};
-
-/* SRAMC register  */
-struct sunxi_sramc_regs {
-       u32 ctrl0;
-       u32 ctrl1;
-};
-
-/* 0: Disable       1: Aborted frame enable(default) */
-#define EMAC_TX_AB_M           (0x1 << 0)
-/* 0: CPU           1: DMA(default) */
-#define EMAC_TX_TM             (0x1 << 1)
-
-#define EMAC_TX_SETUP          (0)
-
-/* 0: DRQ asserted  1: DRQ automatically(default) */
-#define EMAC_RX_DRQ_MODE       (0x1 << 1)
-/* 0: CPU           1: DMA(default) */
-#define EMAC_RX_TM             (0x1 << 2)
-/* 0: Normal(default)        1: Pass all Frames */
-#define EMAC_RX_PA             (0x1 << 4)
-/* 0: Normal(default)        1: Pass Control Frames */
-#define EMAC_RX_PCF            (0x1 << 5)
-/* 0: Normal(default)        1: Pass Frames with CRC Error */
-#define EMAC_RX_PCRCE          (0x1 << 6)
-/* 0: Normal(default)        1: Pass Frames with Length Error */
-#define EMAC_RX_PLE            (0x1 << 7)
-/* 0: Normal                 1: Pass Frames length out of range(default) */
-#define EMAC_RX_POR            (0x1 << 8)
-/* 0: Not accept             1: Accept unicast Packets(default) */
-#define EMAC_RX_UCAD           (0x1 << 16)
-/* 0: Normal(default)        1: DA Filtering */
-#define EMAC_RX_DAF            (0x1 << 17)
-/* 0: Not accept             1: Accept multicast Packets(default) */
-#define EMAC_RX_MCO            (0x1 << 20)
-/* 0: Disable(default)       1: Enable Hash filter */
-#define EMAC_RX_MHF            (0x1 << 21)
-/* 0: Not accept             1: Accept Broadcast Packets(default) */
-#define EMAC_RX_BCO            (0x1 << 22)
-/* 0: Disable(default)       1: Enable SA Filtering */
-#define EMAC_RX_SAF            (0x1 << 24)
-/* 0: Normal(default)        1: Inverse Filtering */
-#define EMAC_RX_SAIF           (0x1 << 25)
-
-#define EMAC_RX_SETUP          (EMAC_RX_POR | EMAC_RX_UCAD | EMAC_RX_DAF | \
-                                EMAC_RX_MCO | EMAC_RX_BCO)
-
-/* 0: Disable                1: Enable Receive Flow Control(default) */
-#define EMAC_MAC_CTL0_RFC      (0x1 << 2)
-/* 0: Disable                1: Enable Transmit Flow Control(default) */
-#define EMAC_MAC_CTL0_TFC      (0x1 << 3)
-
-#define EMAC_MAC_CTL0_SETUP    (EMAC_MAC_CTL0_RFC | EMAC_MAC_CTL0_TFC)
-
-/* 0: Disable                1: Enable MAC Frame Length Checking(default) */
-#define EMAC_MAC_CTL1_FLC      (0x1 << 1)
-/* 0: Disable(default)       1: Enable Huge Frame */
-#define EMAC_MAC_CTL1_HF       (0x1 << 2)
-/* 0: Disable(default)       1: Enable MAC Delayed CRC */
-#define EMAC_MAC_CTL1_DCRC     (0x1 << 3)
-/* 0: Disable                1: Enable MAC CRC(default) */
-#define EMAC_MAC_CTL1_CRC      (0x1 << 4)
-/* 0: Disable                1: Enable MAC PAD Short frames(default) */
-#define EMAC_MAC_CTL1_PC       (0x1 << 5)
-/* 0: Disable(default)       1: Enable MAC PAD Short frames and append CRC */
-#define EMAC_MAC_CTL1_VC       (0x1 << 6)
-/* 0: Disable(default)       1: Enable MAC auto detect Short frames */
-#define EMAC_MAC_CTL1_ADP      (0x1 << 7)
-/* 0: Disable(default)       1: Enable */
-#define EMAC_MAC_CTL1_PRE      (0x1 << 8)
-/* 0: Disable(default)       1: Enable */
-#define EMAC_MAC_CTL1_LPE      (0x1 << 9)
-/* 0: Disable(default)       1: Enable no back off */
-#define EMAC_MAC_CTL1_NB       (0x1 << 12)
-/* 0: Disable(default)       1: Enable */
-#define EMAC_MAC_CTL1_BNB      (0x1 << 13)
-/* 0: Disable(default)       1: Enable */
-#define EMAC_MAC_CTL1_ED       (0x1 << 14)
-
-#define EMAC_MAC_CTL1_SETUP    (EMAC_MAC_CTL1_FLC | EMAC_MAC_CTL1_CRC | \
-                                EMAC_MAC_CTL1_PC)
-
-#define EMAC_MAC_IPGT          0x15
-
-#define EMAC_MAC_NBTB_IPG1     0xC
-#define EMAC_MAC_NBTB_IPG2     0x12
-
-#define EMAC_MAC_CW            0x37
-#define EMAC_MAC_RM            0xF
-
-#define EMAC_MAC_MFL           0x0600
-
-/* Receive status */
-#define EMAC_CRCERR            (1 << 4)
-#define EMAC_LENERR            (3 << 5)
-
-#define DMA_CPU_TRRESHOLD      2000
-
-struct wemac_eth_dev {
-       u32 speed;
-       u32 duplex;
-       u32 phy_configured;
-       int link_printed;
-};
-
-struct wemac_rxhdr {
-       s16 rx_len;
-       u16 rx_status;
-};
-
-static void wemac_inblk_32bit(void *reg, void *data, int count)
-{
-       int cnt = (count + 3) >> 2;
-
-       if (cnt) {
-               u32 *buf = data;
-
-               do {
-                       u32 x = readl(reg);
-                       *buf++ = x;
-               } while (--cnt);
-       }
-}
-
-static void wemac_outblk_32bit(void *reg, void *data, int count)
-{
-       int cnt = (count + 3) >> 2;
-
-       if (cnt) {
-               const u32 *buf = data;
-
-               do {
-                       writel(*buf++, reg);
-               } while (--cnt);
-       }
-}
-
-/*
- * Read a word from phyxcer
- */
-static int wemac_phy_read(const char *devname, unsigned char addr,
-                         unsigned char reg, unsigned short *value)
-{
-       struct eth_device *dev = eth_get_dev_by_name(devname);
-       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
-
-       /* issue the phy address and reg */
-       writel(addr << 8 | reg, &regs->mac_madr);
-
-       /* pull up the phy io line */
-       writel(0x1, &regs->mac_mcmd);
-
-       /* Wait read complete */
-       mdelay(1);
-
-       /* push down the phy io line */
-       writel(0x0, &regs->mac_mcmd);
-
-       /* and write data */
-       *value = readl(&regs->mac_mrdd);
-
-       return 0;
-}
-
-/*
- * Write a word to phyxcer
- */
-static int wemac_phy_write(const char *devname, unsigned char addr,
-                          unsigned char reg, unsigned short value)
-{
-       struct eth_device *dev = eth_get_dev_by_name(devname);
-       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
-
-       /* issue the phy address and reg */
-       writel(addr << 8 | reg, &regs->mac_madr);
-
-       /* pull up the phy io line */
-       writel(0x1, &regs->mac_mcmd);
-
-       /* Wait write complete */
-       mdelay(1);
-
-       /* push down the phy io line */
-       writel(0x0, &regs->mac_mcmd);
-
-       /* and write data */
-       writel(value, &regs->mac_mwtd);
-
-       return 0;
-}
-
-static void emac_setup(struct eth_device *dev)
-{
-       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
-       u32 reg_val;
-       u16 phy_val;
-       u32 duplex_flag;
-
-       /* Set up TX */
-       writel(EMAC_TX_SETUP, &regs->tx_mode);
-
-       /* Set up RX */
-       writel(EMAC_RX_SETUP, &regs->rx_ctl);
-
-       /* Set MAC */
-       /* Set MAC CTL0 */
-       writel(EMAC_MAC_CTL0_SETUP, &regs->mac_ctl0);
-
-       /* Set MAC CTL1 */
-       wemac_phy_read(dev->name, 1, 0, &phy_val);
-       debug("PHY SETUP, reg 0 value: %x\n", phy_val);
-       duplex_flag = !!(phy_val & (1 << 8));
-
-       reg_val = 0;
-       if (duplex_flag)
-               reg_val = (0x1 << 0);
-       writel(EMAC_MAC_CTL1_SETUP | reg_val, &regs->mac_ctl1);
-
-       /* Set up IPGT */
-       writel(EMAC_MAC_IPGT, &regs->mac_ipgt);
-
-       /* Set up IPGR */
-       writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), &regs->mac_ipgr);
-
-       /* Set up Collison window */
-       writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), &regs->mac_clrt);
-
-       /* Set up Max Frame Length */
-       writel(EMAC_MAC_MFL, &regs->mac_maxf);
-}
-
-static void wemac_reset(struct eth_device *dev)
-{
-       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
-
-       debug("resetting device\n");
-
-       /* RESET device */
-       writel(0, &regs->ctl);
-       udelay(200);
-
-       writel(1, &regs->ctl);
-       udelay(200);
-}
-
-static int sunxi_wemac_eth_init(struct eth_device *dev, bd_t *bd)
-{
-       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
-       struct wemac_eth_dev *priv = dev->priv;
-       u16 phy_reg;
-
-       /* Init EMAC */
-
-       /* Flush RX FIFO */
-       setbits_le32(&regs->rx_ctl, 0x8);
-       udelay(1);
-
-       /* Init MAC */
-
-       /* Soft reset MAC */
-       clrbits_le32(&regs->mac_ctl0, 1 << 15);
-
-       /* Set MII clock */
-       clrsetbits_le32(&regs->mac_mcfg, 0xf << 2, 0xd << 2);
-
-       /* Clear RX counter */
-       writel(0x0, &regs->rx_fbc);
-       udelay(1);
-
-       /* Set up EMAC */
-       emac_setup(dev);
-
-       writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 |
-              dev->enetaddr[2], &regs->mac_a1);
-       writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 |
-              dev->enetaddr[5], &regs->mac_a0);
-
-       mdelay(1);
-
-       wemac_reset(dev);
-
-       /* PHY POWER UP */
-       wemac_phy_read(dev->name, 1, 0, &phy_reg);
-       wemac_phy_write(dev->name, 1, 0, phy_reg & (~(1 << 11)));
-       mdelay(1);
-
-       wemac_phy_read(dev->name, 1, 0, &phy_reg);
-
-       priv->speed = miiphy_speed(dev->name, 0);
-       priv->duplex = miiphy_duplex(dev->name, 0);
-
-       /* Print link status only once */
-       if (!priv->link_printed) {
-               printf("ENET Speed is %d Mbps - %s duplex connection\n",
-                      priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL");
-               priv->link_printed = 1;
-       }
-
-       /* Set EMAC SPEED depend on PHY */
-       clrsetbits_le32(&regs->mac_supp, 1 << 8,
-                       ((phy_reg & (1 << 13)) >> 13) << 8);
-
-       /* Set duplex depend on phy */
-       clrsetbits_le32(&regs->mac_ctl1, 1 << 0,
-                       ((phy_reg & (1 << 8)) >> 8) << 0);
-
-       /* Enable RX/TX */
-       setbits_le32(&regs->ctl, 0x7);
-
-       return 0;
-}
-
-static void sunxi_wemac_eth_halt(struct eth_device *dev)
-{
-       /* Nothing to do here */
-}
-
-static int sunxi_wemac_eth_recv(struct eth_device *dev)
-{
-       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
-       struct wemac_rxhdr rxhdr;
-       u32 rxcount;
-       u32 reg_val;
-       int rx_len;
-       int rx_status;
-       int good_packet;
-
-       /* Check packet ready or not */
-
-       /*
-        * Race warning: The first packet might arrive with
-        * the interrupts disabled, but the second will fix
-        */
-       rxcount = readl(&regs->rx_fbc);
-       if (!rxcount) {
-               /* Had one stuck? */
-               rxcount = readl(&regs->rx_fbc);
-               if (!rxcount)
-                       return 0;
-       }
-
-       reg_val = readl(&regs->rx_io_data);
-       if (reg_val != 0x0143414d) {
-               /* Disable RX */
-               clrbits_le32(&regs->ctl, 1 << 2);
-
-               /* Flush RX FIFO */
-               setbits_le32(&regs->rx_ctl, 1 << 3);
-               while (readl(&regs->rx_ctl) & (1 << 3))
-                       ;
-
-               /* Enable RX */
-               setbits_le32(&regs->ctl, 1 << 2);
-
-               return 0;
-       }
-
-       /*
-        * A packet ready now
-        * Get status/length
-        */
-       good_packet = 1;
-
-       wemac_inblk_32bit(&regs->rx_io_data, &rxhdr, sizeof(rxhdr));
-
-       rx_len = rxhdr.rx_len;
-       rx_status = rxhdr.rx_status;
-
-       /* Packet Status check */
-       if (rx_len < 0x40) {
-               good_packet = 0;
-               debug("RX: Bad Packet (runt)\n");
-       }
-
-       /* rx_status is identical to RSR register. */
-       if (0 & rx_status & (EMAC_CRCERR | EMAC_LENERR)) {
-               good_packet = 0;
-               if (rx_status & EMAC_CRCERR)
-                       printf("crc error\n");
-               if (rx_status & EMAC_LENERR)
-                       printf("length error\n");
-       }
-
-       /* Move data from WEMAC */
-       if (good_packet) {
-               if (rx_len > DMA_CPU_TRRESHOLD) {
-                       printf("Received packet is too big (len=%d)\n", rx_len);
-               } else {
-                       wemac_inblk_32bit((void *)&regs->rx_io_data,
-                                         NetRxPackets[0], rx_len);
-
-                       /* Pass to upper layer */
-                       NetReceive(NetRxPackets[0], rx_len);
-                       return rx_len;
-               }
-       }
-
-       return 0;
-}
-
-static int sunxi_wemac_eth_send(struct eth_device *dev, void *packet, int len)
-{
-       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
-
-       /* Select channel 0 */
-       writel(0, &regs->tx_ins);
-
-       /* Write packet */
-       wemac_outblk_32bit((void *)&regs->tx_io_data, packet, len);
-
-       /* Set TX len */
-       writel(len, &regs->tx_pl0);
-
-       /* Start translate from fifo to phy */
-       setbits_le32(&regs->tx_ctl0, 1);
-
-       return 0;
-}
-
-int sunxi_wemac_initialize(void)
-{
-       struct sunxi_ccm_reg *const ccm =
-               (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
-       struct sunxi_sramc_regs *sram =
-               (struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE;
-       struct eth_device *dev;
-       struct wemac_eth_dev *priv;
-       int pin;
-
-       dev = malloc(sizeof(*dev));
-       if (dev == NULL)
-               return -ENOMEM;
-
-       priv = (struct wemac_eth_dev *)malloc(sizeof(struct wemac_eth_dev));
-       if (!priv) {
-               free(dev);
-               return -ENOMEM;
-       }
-
-       memset(dev, 0, sizeof(*dev));
-       memset(priv, 0, sizeof(struct wemac_eth_dev));
-
-       /* Map SRAM to EMAC */
-       setbits_le32(&sram->ctrl1, 0x5 << 2);
-
-       /* Configure pin mux settings for MII Ethernet */
-       for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++)
-               sunxi_gpio_set_cfgpin(pin, 2);
-
-       /* Set up clock gating */
-       setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_EMAC);
-
-       dev->iobase = SUNXI_EMAC_BASE;
-       dev->priv = priv;
-       dev->init = sunxi_wemac_eth_init;
-       dev->halt = sunxi_wemac_eth_halt;
-       dev->send = sunxi_wemac_eth_send;
-       dev->recv = sunxi_wemac_eth_recv;
-       strcpy(dev->name, "wemac");
-
-       eth_register(dev);
-
-       miiphy_register(dev->name, wemac_phy_read, wemac_phy_write);
-
-       return 0;
-}
index 63481eca22688080f5b26e7da99013af88f06c1d..e45dd7abec3e168d74149b4ce06164563c516001 100644 (file)
@@ -78,8 +78,8 @@ int sh_eth_initialize(bd_t *bis);
 int skge_initialize(bd_t *bis);
 int smc91111_initialize(u8 dev_num, int base_addr);
 int smc911x_initialize(u8 dev_num, int base_addr);
+int sunxi_emac_initialize(bd_t *bis);
 int sunxi_gmac_initialize(bd_t *bis);
-int sunxi_wemac_initialize(bd_t *bis);
 int tsi108_eth_initialize(bd_t *bis);
 int uec_standard_init(bd_t *bis);
 int uli526x_initialize(bd_t *bis);