[U-Boot] [PATCH] ftgmac100: support of gigabit eth ftgmac100

Add Faraday's ftgmac100 (gigabit ethernet) MAC controller's driver.
Sub configuration in this driver:
CONFIG_FTGMAC100_EGIGA: Support GE link update with gigabit PHY.
Enable CONFIG_FTGMAC100_EGIGA if FTGMAC100 is connected to gigabit PHY.
If this item was enabled in your system with 10/100 PHY may not have wrong behavior with your 10/100 PHY. Because PHY usually return timeout or useless data when polling gigabit status and gigabit control registers. This behavior which won't affect the correctness of 10/100 link speed update.
Signed-off-by: Macpaul Lin macpaul@andestech.com --- drivers/net/Makefile | 1 + drivers/net/ftgmac100.c | 598 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ftgmac100.h | 303 ++++++++++++++++++++++++ include/netdev.h | 1 + 4 files changed, 903 insertions(+), 0 deletions(-) create mode 100644 drivers/net/ftgmac100.c create mode 100644 drivers/net/ftgmac100.h
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index b605eea..faeab32 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -48,6 +48,7 @@ COBJS-$(CONFIG_ETHOC) += ethoc.o COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o COBJS-$(CONFIG_FTMAC100) += ftmac100.o +COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o COBJS-$(CONFIG_GRETH) += greth.o COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c new file mode 100644 index 0000000..7616fcd --- /dev/null +++ b/drivers/net/ftgmac100.c @@ -0,0 +1,598 @@ +/* + * Faraday FTGMAC100 Ethernet + * + * (C) Copyright 2009 Faraday Technology + * Po-Yu Chuang ratbert@faraday-tech.com + * + * (C) Copyright 2010 Andes Technology + * Macpaul Lin macpaul@andestech.com + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <config.h> +#include <common.h> +#include <malloc.h> +#include <net.h> +#include <asm/io.h> +#include <linux/mii.h> + +#include "ftgmac100.h" + +#define ETH_ZLEN 60 + +#define mdelay(n) ({unsigned long msec = (n); while (msec--) udelay(1000); }) + +#define RBSR_DEFAULT_VALUE 0x640 /* hw default init value is also 0x640 */ + +#define PKTBUFSTX 4 /* must be power of 2 */ + +struct ftgmac100_data { + volatile struct ftgmac100_txdes txdes[PKTBUFSTX]; /* must be power of 2 */ + volatile struct ftgmac100_rxdes rxdes[PKTBUFSRX]; /* must be power of 2 */ + int tx_index; + int rx_index; + int phy_addr; +}; + + +/****************************************************************************** + * struct mii_bus functions + *****************************************************************************/ +static int ftgmac100_mdiobus_read(struct eth_device *dev, int phy_addr, int regnum) +{ + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; + int phycr; + int i; + + phycr = readl(&ftgmac100->phycr); + + /* preserve MDC cycle threshold */ + phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK; + + phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) + | FTGMAC100_PHYCR_REGAD(regnum) + | FTGMAC100_PHYCR_MIIRD; + + writel (phycr, &ftgmac100->phycr); + + for (i = 0; i < 10; i++) { + phycr = readl(&ftgmac100->phycr); + + if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) { + int data; + + data = readl(&ftgmac100->phydata); + return FTGMAC100_PHYDATA_MIIRDATA(data); + } + + mdelay(10); + } + + debug("mdio read timed out\n"); + return -1; +} + +static int ftgmac100_mdiobus_write(struct eth_device *dev, int phy_addr, + int regnum, u16 value) +{ + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; + int phycr; + int data; + int i; + + phycr = readl(&ftgmac100->phycr); + + /* preserve MDC cycle threshold */ + phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK; + + phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) + | FTGMAC100_PHYCR_REGAD(regnum) + | FTGMAC100_PHYCR_MIIWR; + + data = FTGMAC100_PHYDATA_MIIWDATA(value); + + writel(data, &ftgmac100->phydata); + writel(phycr, &ftgmac100->phycr); + + for (i = 0; i < 10; i++) { + phycr = readl(&ftgmac100->phycr); + + if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) { + debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: phy_addr: %x\n", phy_addr); + return 0; + } + + mdelay(1); + } + + debug("mdio write timed out\n"); + return -1; +} + +static int ftgmac100_mdiobus_reset(struct eth_device *dev) +{ + return 0; +} + +int ftgmac100_phy_read(struct eth_device *dev, int addr, + int reg, u16 *value) +{ + *value = ftgmac100_mdiobus_read(dev , addr, reg); + return 0; +} + +int ftgmac100_phy_write(struct eth_device *dev, int addr, + int reg, u16 value) +{ + ftgmac100_mdiobus_write(dev, addr, reg, value); + return 0; +} + +static int ftgmac100_phy_reset(struct eth_device *dev) +{ + struct ftgmac100_data *priv = dev->priv; + int i; + u16 status, adv; + + adv = ADVERTISE_CSMA | ADVERTISE_ALL; + + ftgmac100_phy_write(dev, priv->phy_addr, + MII_ADVERTISE, adv); + printf("%s: Starting autonegotiation...\n", dev->name); + + ftgmac100_phy_write(dev, priv->phy_addr, + MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)); + + for (i = 0; i < 100000 / 100; i++) { + ftgmac100_phy_read(dev, priv->phy_addr, + MII_BMSR, &status); + if (status & BMSR_ANEGCOMPLETE) + break; + udelay(100); + } + + if (status & BMSR_ANEGCOMPLETE) { + printf("%s: Autonegotiation complete\n", dev->name); + } else { + printf("%s: Autonegotiation timed out (status=0x%04x)\n", + dev->name, status); + return 1; + } + return 0; +} + +static int ftgmac100_phy_init(struct eth_device *dev) +{ + struct ftgmac100_data *priv = dev->priv; + + int phy_addr; + u16 phy_id, status, adv, lpa, stat_ge; + int media, speed, duplex; + int i; + + /* Check if the PHY is up to snuff... */ + + for (phy_addr=0; phy_addr < CONFIG_PHY_MAX_ADDR; phy_addr++) { + ftgmac100_phy_read(dev, phy_addr, + MII_PHYSID1, &phy_id); + + /* When it is unable to found PHY, the interface usually return 0xffff or 0x0000 */ + if (phy_id != 0xffff && phy_id != 0x0) { + printf("%s: found PHY at 0x%02x\n", dev->name, phy_addr); + priv->phy_addr = phy_addr; + break; + } + } + + if (phy_id == 0xffff || phy_id == 0x0) { + printf("%s: no PHY present\n", dev->name); + return -1; + } + + ftgmac100_phy_read(dev, priv->phy_addr, + MII_BMSR, &status); + if (!(status & BMSR_LSTATUS)) { + /* Try to re-negotiate if we don't have link already. */ + if (ftgmac100_phy_reset(dev)) + return 2; + + for (i = 0; i < 100000 / 100; i++) { + ftgmac100_phy_read(dev, priv->phy_addr, + MII_BMSR, &status); + if (status & BMSR_LSTATUS) + break; + udelay(100); + } + } + if (!(status & BMSR_LSTATUS)) { + printf("%s: link down\n", dev->name); + return 3; + } else { + +#ifdef CONFIG_FTGMAC100_EGIGA + ftgmac100_phy_read(dev, priv->phy_addr, + MII_STAT1000, &stat_ge); /* 1000 Base-T Status Register */ + + speed = (stat_ge & (LPA_1000FULL | LPA_1000HALF) + ? 1 : 0); + + duplex = ((stat_ge & LPA_1000FULL) + ? 1 : 0); + + if (speed) { /* Speed is 1000 */ + printf("%s: link up, %sMbps %s-duplex\n", + dev->name, + speed ? "1000" : "10/100", + duplex ? "full" : "half"); + return 0; + } +#endif + + ftgmac100_phy_read(dev, priv->phy_addr, + MII_ADVERTISE, &adv); + ftgmac100_phy_read(dev, priv->phy_addr, + MII_LPA, &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\n", + dev->name, + speed ? "100" : "10", + duplex ? "full" : "half"); + } + return 0; +} + +int ftgmac100_update_link_speed(struct eth_device *dev) +{ + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; + struct ftgmac100_data *priv = dev->priv; + + unsigned short stat_fe; + unsigned short stat_ge; + +#ifdef CONFIG_FTGMAC100_EGIGA + ftgmac100_phy_read(dev, priv->phy_addr, + MII_STAT1000, &stat_ge); /* 1000 Base-T Status Register */ +#endif + + ftgmac100_phy_read(dev, priv->phy_addr, + MII_BMSR, &stat_fe); + + if (!(stat_fe & BMSR_LSTATUS)) /* link status up? */ + return 1; + +#ifdef CONFIG_FTGMAC100_EGIGA + if (stat_ge & LPA_1000FULL) { + /*set Emac for 1000BaseTX and Full Duplex */ + writel((readl(&ftgmac100->maccr) & + ~(FTGMAC100_MACCR_GIGA_MODE | + FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP) + ) | FTGMAC100_MACCR_GIGA_MODE | FTGMAC100_MACCR_FULLDUP, + &ftgmac100->maccr); + return 0; + } + + if (stat_ge & LPA_1000HALF) { + /*set Emac for 1000BaseTX and Half Duplex */ + writel((readl(&ftgmac100->maccr) & + ~(FTGMAC100_MACCR_GIGA_MODE | + FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP) + ) | FTGMAC100_MACCR_GIGA_MODE, + &ftgmac100->maccr); + return 0; + } +#endif + + if (stat_fe & BMSR_100FULL) { + /*set Emac for 100BaseTX and Full Duplex */ + writel((readl(&ftgmac100->maccr) & + ~(FTGMAC100_MACCR_GIGA_MODE | + FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP) + ) | FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP, + &ftgmac100->maccr); + return 0; + } + + if (stat_fe & BMSR_10FULL) { + /*set MII for 10BaseT and Full Duplex */ + writel((readl(&ftgmac100->maccr) & + ~(FTGMAC100_MACCR_GIGA_MODE | + FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP) + ) | FTGMAC100_MACCR_FULLDUP, + &ftgmac100->maccr); + return 0; + } + + if (stat_fe & BMSR_100HALF) { + /*set MII for 100BaseTX and Half Duplex */ + writel((readl(&ftgmac100->maccr) & + ~(FTGMAC100_MACCR_GIGA_MODE | + FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP) + ) | FTGMAC100_MACCR_FAST_MODE, + &ftgmac100->maccr); + return 0; + } + + if (stat_fe & BMSR_10HALF) { + /*set MII for 10BaseT and Half Duplex */ + writel((readl(&ftgmac100->maccr) & + ~(FTGMAC100_MACCR_GIGA_MODE | + FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)), + &ftgmac100->maccr); + return 0; + } + return 1; +} + +/* + * Reset MAC + */ +static void ftgmac100_reset (struct eth_device *dev) +{ + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; + + debug ("%s()\n", __func__); + + writel (FTGMAC100_MACCR_SW_RST, &ftgmac100->maccr); + + while (readl (&ftgmac100->maccr) & FTGMAC100_MACCR_SW_RST) + ; +} + +/* + * Set MAC address + */ +static void ftgmac100_set_mac (struct eth_device *dev, const unsigned char *mac) +{ + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; + unsigned int maddr = mac[0] << 8 | mac[1]; + unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; + + debug ("%s(%x %x)\n", __func__, maddr, laddr); + + writel (maddr, &ftgmac100->mac_madr); + writel (laddr, &ftgmac100->mac_ladr); +} + +static void ftgmac100_set_mac_from_env (struct eth_device *dev) +{ + eth_getenv_enetaddr ("ethaddr", dev->enetaddr); + + ftgmac100_set_mac (dev, dev->enetaddr); +} + +/* + * disable transmitter, receiver + */ +static void ftgmac100_halt (struct eth_device *dev) +{ + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; + + debug ("%s()\n", __func__); + + writel (0, &ftgmac100->maccr); +} + +static int ftgmac100_init (struct eth_device *dev, bd_t *bd) +{ + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; + struct ftgmac100_data *priv = dev->priv; + volatile struct ftgmac100_txdes *txdes = priv->txdes; + volatile struct ftgmac100_rxdes *rxdes = priv->rxdes; + unsigned int maccr; + int i; + + debug ("%s()\n", __func__); + + ftgmac100_reset (dev); + + /* set the ethernet address */ + + ftgmac100_set_mac_from_env (dev); + + /* disable all interrupts */ + + writel (0, &ftgmac100->ier); + + /* initialize descriptors */ + + priv->tx_index = 0; + priv->rx_index = 0; + + txdes[PKTBUFSTX - 1].txdes0 = FTGMAC100_TXDES0_EDOTR; + rxdes[PKTBUFSRX - 1].rxdes0 = FTGMAC100_RXDES0_EDORR; + + for (i = 0; i < PKTBUFSTX; i++) { + /* TXBUF_BADR */ + txdes[i].txdes3 = 0; + txdes[i].txdes1 = 0; + } + + for (i = 0; i < PKTBUFSRX; i++) { + /* RXBUF_BADR */ + rxdes[i].rxdes3 = (unsigned int)NetRxPackets[i]; + rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY; + } + + /* transmit ring */ + + writel ((unsigned int)txdes, &ftgmac100->txr_badr); + + /* receive ring */ + + writel ((unsigned int)rxdes, &ftgmac100->rxr_badr); + + /* poll receive descriptor automatically */ + + writel (FTGMAC100_APTC_RXPOLL_CNT (1), &ftgmac100->aptc); + + /* config receive buffer size register */ + + writel (FTGMAC100_RBSR_SIZE (RBSR_DEFAULT_VALUE), &ftgmac100->rbsr); + + /* enable transmitter, receiver */ + + maccr = FTGMAC100_MACCR_TXMAC_EN | + FTGMAC100_MACCR_RXMAC_EN | + FTGMAC100_MACCR_TXDMA_EN | + FTGMAC100_MACCR_RXDMA_EN | + FTGMAC100_MACCR_CRC_APD | + FTGMAC100_MACCR_FULLDUP | + FTGMAC100_MACCR_RX_RUNT | + FTGMAC100_MACCR_RX_BROADPKT; + + writel (maccr, &ftgmac100->maccr); + + if (!ftgmac100_phy_init(dev)) { + ftgmac100_update_link_speed(dev); + return 0; + } + + return 0; +} + +/* + * Get a data block via Ethernet + */ +static int ftgmac100_recv (struct eth_device *dev) +{ + struct ftgmac100_data *priv = dev->priv; + volatile struct ftgmac100_rxdes *curr_des; + unsigned short rxlen; + + curr_des = &priv->rxdes[priv->rx_index]; + + if (!(curr_des->rxdes0 & FTGMAC100_RXDES0_RXPKT_RDY)) + return -1; + + if (curr_des->rxdes0 & (FTGMAC100_RXDES0_RX_ERR | + FTGMAC100_RXDES0_CRC_ERR | + FTGMAC100_RXDES0_FTL | + FTGMAC100_RXDES0_RUNT | + FTGMAC100_RXDES0_RX_ODD_NB)) { + return -1; + } + + rxlen = FTGMAC100_RXDES0_VDBC (curr_des->rxdes0); + + debug ("%s(): RX buffer %d, %x received\n", + __func__, priv->rx_index, rxlen); + + /* pass the packet up to the protocol layers. */ + + NetReceive ((void *)curr_des->rxdes3, rxlen); + + /* release buffer to DMA */ + + curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY; + + priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX; + + return 0; +} + +/* + * Send a data block via Ethernet + */ +static int +ftgmac100_send (struct eth_device *dev, volatile void *packet, int length) +{ + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; + struct ftgmac100_data *priv = dev->priv; + volatile struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index]; + int tmo; + + if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) { + debug ("%s(): no TX descriptor available\n", __func__); + return -1; + } + + debug ("%s(%x, %x)\n", __func__, (int)packet, length); + + length = (length < ETH_ZLEN) ? ETH_ZLEN : length; + + /* initiate a transmit sequence */ + + curr_des->txdes3 = (unsigned int)packet; /* TXBUF_BADR */ + + curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR; /* only one descriptor on TXBUF */ + curr_des->txdes0 |= FTGMAC100_TXDES0_FTS | + FTGMAC100_TXDES0_LTS | + FTGMAC100_TXDES0_TXBUF_SIZE (length) | + FTGMAC100_TXDES0_TXDMA_OWN ; + + /* start transmit */ + + writel (1, &ftgmac100->txpd); + + /* wait for transfer to succeed */ + + tmo = get_timer (0) + 5 * CONFIG_SYS_HZ; + while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) { + if (get_timer (0) >= tmo) { + debug ("%s(): timed out\n", __func__); + return -1; + } + } + + debug ("%s(): packet sent\n", __func__); + + priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX; + + return 0; +} + +int ftgmac100_initialize (bd_t *bd) +{ + struct eth_device *dev; + struct ftgmac100_data *priv; + + dev = malloc (sizeof *dev); + if (!dev) { + printf ("%s(): failed to allocate dev\n", __func__); + goto out; + } + + /* Transmit and receive descriptors should align to 16 bytes */ + + priv = memalign (16, sizeof (struct ftgmac100_data)); + if (!priv) { + printf ("%s(): failed to allocate priv\n", __func__); + goto free_dev; + } + + memset (dev, 0, sizeof (*dev)); + memset (priv, 0, sizeof (*priv)); + + sprintf (dev->name, "FTGMAC100"); + dev->iobase = CONFIG_FTGMAC100_BASE; + dev->init = ftgmac100_init; + dev->halt = ftgmac100_halt; + dev->send = ftgmac100_send; + dev->recv = ftgmac100_recv; + dev->priv = priv; + + eth_register (dev); + + return 1; + +free_dev: + free (dev); +out: + return 0; +} diff --git a/drivers/net/ftgmac100.h b/drivers/net/ftgmac100.h new file mode 100644 index 0000000..6549943 --- /dev/null +++ b/drivers/net/ftgmac100.h @@ -0,0 +1,303 @@ +/* + * Faraday FTGMAC100 Ethernet + * + * (C) Copyright 2010 Faraday Technology + * Po-Yu Chuang ratbert@faraday-tech.com + * + * (C) Copyright 2010 Andes Technology + * Macpaul Lin macpaul@andestech.com + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __FTGMAC100_H +#define __FTGMAC100_H + +#define FTGMAC100_OFFSET_ISR 0x00 +#define FTGMAC100_OFFSET_IER 0x04 +#define FTGMAC100_OFFSET_MAC_MADR 0x08 +#define FTGMAC100_OFFSET_MAC_LADR 0x0c +#define FTGMAC100_OFFSET_MAHT0 0x10 +#define FTGMAC100_OFFSET_MAHT1 0x14 +#define FTGMAC100_OFFSET_NPTXPD 0x18 +#define FTGMAC100_OFFSET_RXPD 0x1c +#define FTGMAC100_OFFSET_NPTXR_BADR 0x20 +#define FTGMAC100_OFFSET_RXR_BADR 0x24 +#define FTGMAC100_OFFSET_HPTXPD 0x28 +#define FTGMAC100_OFFSET_HPTXR_BADR 0x2c +#define FTGMAC100_OFFSET_ITC 0x30 +#define FTGMAC100_OFFSET_APTC 0x34 +#define FTGMAC100_OFFSET_DBLAC 0x38 +#define FTGMAC100_OFFSET_DMAFIFOS 0x3c +#define FTGMAC100_OFFSET_REVR 0x40 +#define FTGMAC100_OFFSET_FEAR 0x44 +#define FTGMAC100_OFFSET_TPAFCR 0x48 +#define FTGMAC100_OFFSET_RBSR 0x4c +#define FTGMAC100_OFFSET_MACCR 0x50 +#define FTGMAC100_OFFSET_MACSR 0x54 +#define FTGMAC100_OFFSET_TM 0x58 +#define FTGMAC100_OFFSET_PHYCR 0x60 +#define FTGMAC100_OFFSET_PHYDATA 0x64 +#define FTGMAC100_OFFSET_FCR 0x68 +#define FTGMAC100_OFFSET_BPR 0x6c +#define FTGMAC100_OFFSET_WOLCR 0x70 +#define FTGMAC100_OFFSET_WOLSR 0x74 +#define FTGMAC100_OFFSET_WFCRC 0x78 +#define FTGMAC100_OFFSET_WFBM1 0x80 +#define FTGMAC100_OFFSET_WFBM2 0x84 +#define FTGMAC100_OFFSET_WFBM3 0x88 +#define FTGMAC100_OFFSET_WFBM4 0x8c +#define FTGMAC100_OFFSET_NPTXR_PTR 0x90 +#define FTGMAC100_OFFSET_HPTXR_PTR 0x94 +#define FTGMAC100_OFFSET_RXR_PTR 0x98 +#define FTGMAC100_OFFSET_TX 0xa0 +#define FTGMAC100_OFFSET_TX_MCOL_SCOL 0xa4 +#define FTGMAC100_OFFSET_TX_ECOL_FAIL 0xa8 +#define FTGMAC100_OFFSET_TX_LCOL_UND 0xac +#define FTGMAC100_OFFSET_RX 0xb0 +#define FTGMAC100_OFFSET_RX_BC 0xb4 +#define FTGMAC100_OFFSET_RX_MC 0xb8 +#define FTGMAC100_OFFSET_RX_PF_AEP 0xbc +#define FTGMAC100_OFFSET_RX_RUNT 0xc0 +#define FTGMAC100_OFFSET_RX_CRCER_FTL 0xc4 +#define FTGMAC100_OFFSET_RX_COL_LOST 0xc8 + +struct ftgmac100 { + unsigned int isr; /* 0x00 */ + unsigned int ier; /* 0x04 */ + unsigned int mac_madr; /* 0x08 */ + unsigned int mac_ladr; /* 0x0c */ + unsigned int maht0; /* 0x10 */ + unsigned int maht1; /* 0x14 */ + unsigned int txpd; /* 0x18 */ + unsigned int rxpd; /* 0x1c */ + unsigned int txr_badr; /* 0x20 */ + unsigned int rxr_badr; /* 0x24 */ + unsigned int hptxpd; /* 0x28 */ + unsigned int hptxpd_badr; /* 0x2c */ + unsigned int itc; /* 0x30 */ + unsigned int aptc; /* 0x34 */ + unsigned int dblac; /* 0x38 */ + unsigned int dmafifos; /* 0x3c */ + unsigned int revr; /* 0x40 */ + unsigned int fear; /* 0x44 */ + unsigned int tpafcr; /* 0x48 */ + unsigned int rbsr; /* 0x4c */ + unsigned int maccr; /* 0x50 */ + unsigned int macsr; /* 0x54 */ + unsigned int tm; /* 0x58 */ + unsigned int resv1; /* 0x5c */ /* not defined in spec */ + unsigned int phycr; /* 0x60 */ + unsigned int phydata; /* 0x64 */ + unsigned int fcr; /* 0x68 */ + unsigned int bpr; /* 0x6c */ + unsigned int wolcr; /* 0x70 */ + unsigned int wolsr; /* 0x74 */ + unsigned int wfcrc; /* 0x78 */ + unsigned int resv2; /* 0x7c */ /* not defined in spec */ + unsigned int wfbm1; /* 0x80 */ + unsigned int wfbm2; /* 0x84 */ + unsigned int wfbm3; /* 0x88 */ + unsigned int wfbm4; /* 0x8c */ + unsigned int nptxr_ptr; /* 0x90 */ + unsigned int hptxr_ptr; /* 0x94 */ + unsigned int rxr_ptr; /* 0x98 */ + unsigned int resv3; /* 0x9c */ /* not defined in spec */ + unsigned int tx; /* 0xa0 */ + unsigned int tx_mcol_scol; /* 0xa4 */ + unsigned int tx_ecol_fail; /* 0xa8 */ + unsigned int tx_lcol_und; /* 0xac */ + unsigned int rx; /* 0xb0 */ + unsigned int rx_bc; /* 0xb4 */ + unsigned int rx_mc; /* 0xb8 */ + unsigned int rx_pf_aep; /* 0xbc */ + unsigned int rx_runt; /* 0xc0 */ + unsigned int rx_crcer_ftl; /* 0xc4 */ + unsigned int rx_col_lost; /* 0xc8 */ +}; + +/* + * Interrupt status register & interrupt enable register + */ +#define FTGMAC100_INT_RPKT_BUF (1 << 0) +#define FTGMAC100_INT_RPKT_FIFO (1 << 1) +#define FTGMAC100_INT_NO_RXBUF (1 << 2) +#define FTGMAC100_INT_RPKT_LOST (1 << 3) +#define FTGMAC100_INT_XPKT_ETH (1 << 4) +#define FTGMAC100_INT_XPKT_FIFO (1 << 5) +#define FTGMAC100_INT_NO_NPTXBUF (1 << 6) +#define FTGMAC100_INT_XPKT_LOST (1 << 7) +#define FTGMAC100_INT_AHB_ERR (1 << 8) +#define FTGMAC100_INT_PHYSTS_CHG (1 << 9) +#define FTGMAC100_INT_NO_HPTXBUF (1 << 10) + +/* + * Interrupt timer control register + */ +#define FTGMAC100_ITC_RXINT_CNT(x) (((x) & 0xf) << 0) +#define FTGMAC100_ITC_RXINT_THR(x) (((x) & 0x7) << 4) +#define FTGMAC100_ITC_RXINT_TIME_SEL (1 << 7) +#define FTGMAC100_ITC_TXINT_CNT(x) (((x) & 0xf) << 8) +#define FTGMAC100_ITC_TXINT_THR(x) (((x) & 0x7) << 12) +#define FTGMAC100_ITC_TXINT_TIME_SEL (1 << 15) + +/* + * Automatic polling timer control register + */ +#define FTGMAC100_APTC_RXPOLL_CNT(x) (((x) & 0xf) << 0) +#define FTGMAC100_APTC_RXPOLL_TIME_SEL (1 << 4) +#define FTGMAC100_APTC_TXPOLL_CNT(x) (((x) & 0xf) << 8) +#define FTGMAC100_APTC_TXPOLL_TIME_SEL (1 << 12) + +/* + * DMA burst length and arbitration control register + */ +#define FTGMAC100_DBLAC_RXFIFO_LTHR(x) (((x) & 0x7) << 0) +#define FTGMAC100_DBLAC_RXFIFO_HTHR(x) (((x) & 0x7) << 3) +#define FTGMAC100_DBLAC_RX_THR_EN (1 << 6) +#define FTGMAC100_DBLAC_RXBURST_SIZE(x) (((x) & 0x3) << 8) +#define FTGMAC100_DBLAC_TXBURST_SIZE(x) (((x) & 0x3) << 10) +#define FTGMAC100_DBLAC_RXDES_SIZE(x) (((x) & 0xf) << 12) +#define FTGMAC100_DBLAC_TXDES_SIZE(x) (((x) & 0xf) << 16) +#define FTGMAC100_DBLAC_IFG_CNT(x) (((x) & 0x7) << 20) +#define FTGMAC100_DBLAC_IFG_INC (1 << 23) + +/* + * DMA FIFO status register + */ +#define FTGMAC100_DMAFIFOS_RXDMA1_SM(dmafifos) ((dmafifos) & 0xf) +#define FTGMAC100_DMAFIFOS_RXDMA2_SM(dmafifos) (((dmafifos) >> 4) & 0xf) +#define FTGMAC100_DMAFIFOS_RXDMA3_SM(dmafifos) (((dmafifos) >> 8) & 0x7) +#define FTGMAC100_DMAFIFOS_TXDMA1_SM(dmafifos) (((dmafifos) >> 12) & 0xf) +#define FTGMAC100_DMAFIFOS_TXDMA2_SM(dmafifos) (((dmafifos) >> 16) & 0x3) +#define FTGMAC100_DMAFIFOS_TXDMA3_SM(dmafifos) (((dmafifos) >> 18) & 0xf) +#define FTGMAC100_DMAFIFOS_RXFIFO_EMPTY (1 << 26) +#define FTGMAC100_DMAFIFOS_TXFIFO_EMPTY (1 << 27) +#define FTGMAC100_DMAFIFOS_RXDMA_GRANT (1 << 28) +#define FTGMAC100_DMAFIFOS_TXDMA_GRANT (1 << 29) +#define FTGMAC100_DMAFIFOS_RXDMA_REQ (1 << 30) +#define FTGMAC100_DMAFIFOS_TXDMA_REQ (1 << 31) + +/* + * Receive buffer size register + */ +#define FTGMAC100_RBSR_SIZE(x) ((x) & 0x3fff) + +/* + * MAC control register + */ +#define FTGMAC100_MACCR_TXDMA_EN (1 << 0) +#define FTGMAC100_MACCR_RXDMA_EN (1 << 1) +#define FTGMAC100_MACCR_TXMAC_EN (1 << 2) +#define FTGMAC100_MACCR_RXMAC_EN (1 << 3) +#define FTGMAC100_MACCR_RM_VLAN (1 << 4) +#define FTGMAC100_MACCR_HPTXR_EN (1 << 5) +#define FTGMAC100_MACCR_LOOP_EN (1 << 6) +#define FTGMAC100_MACCR_ENRX_IN_HALFTX (1 << 7) +#define FTGMAC100_MACCR_FULLDUP (1 << 8) +#define FTGMAC100_MACCR_GIGA_MODE (1 << 9) +#define FTGMAC100_MACCR_CRC_APD (1 << 10) +#define FTGMAC100_MACCR_RX_RUNT (1 << 12) +#define FTGMAC100_MACCR_JUMBO_LF (1 << 13) +#define FTGMAC100_MACCR_RX_ALL (1 << 14) +#define FTGMAC100_MACCR_HT_MULTI_EN (1 << 15) +#define FTGMAC100_MACCR_RX_MULTIPKT (1 << 16) +#define FTGMAC100_MACCR_RX_BROADPKT (1 << 17) +#define FTGMAC100_MACCR_DISCARD_CRCERR (1 << 18) +#define FTGMAC100_MACCR_FAST_MODE (1 << 19) +#define FTGMAC100_MACCR_SW_RST (1 << 31) + +/* + * PHY control register + */ +#define FTGMAC100_PHYCR_MDC_CYCTHR_MASK 0x3f +#define FTGMAC100_PHYCR_MDC_CYCTHR(x) ((x) & 0x3f) +#define FTGMAC100_PHYCR_PHYAD(x) (((x) & 0x1f) << 16) +#define FTGMAC100_PHYCR_REGAD(x) (((x) & 0x1f) << 21) +#define FTGMAC100_PHYCR_MIIRD (1 << 26) +#define FTGMAC100_PHYCR_MIIWR (1 << 27) + +/* + * PHY data register + */ +#define FTGMAC100_PHYDATA_MIIWDATA(x) ((x) & 0xffff) +#define FTGMAC100_PHYDATA_MIIRDATA(phydata) (((phydata) >> 16) & 0xffff) + +/* + * Transmit descriptor, aligned to 16 bytes + */ +struct ftgmac100_txdes { + unsigned int txdes0; + unsigned int txdes1; + unsigned int txdes2; /* not used by HW */ + unsigned int txdes3; /* TXBUF_BADR */ +} __attribute__ ((aligned(16))); + +#define FTGMAC100_TXDES0_TXBUF_SIZE(x) ((x) & 0x3fff) +#define FTGMAC100_TXDES0_EDOTR (1 << 15) +#define FTGMAC100_TXDES0_CRC_ERR (1 << 19) +#define FTGMAC100_TXDES0_LTS (1 << 28) +#define FTGMAC100_TXDES0_FTS (1 << 29) +#define FTGMAC100_TXDES0_TXDMA_OWN (1 << 31) + +#define FTGMAC100_TXDES1_VLANTAG_CI(x) ((x) & 0xffff) +#define FTGMAC100_TXDES1_INS_VLANTAG (1 << 16) +#define FTGMAC100_TXDES1_TCP_CHKSUM (1 << 17) +#define FTGMAC100_TXDES1_UDP_CHKSUM (1 << 18) +#define FTGMAC100_TXDES1_IP_CHKSUM (1 << 19) +#define FTGMAC100_TXDES1_LLC (1 << 22) +#define FTGMAC100_TXDES1_TX2FIC (1 << 30) +#define FTGMAC100_TXDES1_TXIC (1 << 31) + +/* + * Receive descriptor, aligned to 16 bytes + */ +struct ftgmac100_rxdes { + unsigned int rxdes0; + unsigned int rxdes1; + unsigned int rxdes2; /* not used by HW */ + unsigned int rxdes3; /* RXBUF_BADR */ +} __attribute__ ((aligned(16))); + +#define FTGMAC100_RXDES0_VDBC(x) ((x) & 0x3fff) +#define FTGMAC100_RXDES0_EDORR (1 << 15) +#define FTGMAC100_RXDES0_MULTICAST (1 << 16) +#define FTGMAC100_RXDES0_BROADCAST (1 << 17) +#define FTGMAC100_RXDES0_RX_ERR (1 << 18) +#define FTGMAC100_RXDES0_CRC_ERR (1 << 19) +#define FTGMAC100_RXDES0_FTL (1 << 20) +#define FTGMAC100_RXDES0_RUNT (1 << 21) +#define FTGMAC100_RXDES0_RX_ODD_NB (1 << 22) +#define FTGMAC100_RXDES0_FIFO_FULL (1 << 23) +#define FTGMAC100_RXDES0_PAUSE_OPCODE (1 << 24) +#define FTGMAC100_RXDES0_PAUSE_FRAME (1 << 25) +#define FTGMAC100_RXDES0_LRS (1 << 28) +#define FTGMAC100_RXDES0_FRS (1 << 29) +#define FTGMAC100_RXDES0_RXPKT_RDY (1 << 31) + +#define FTGMAC100_RXDES1_VLANTAG_CI 0xffff +#define FTGMAC100_RXDES1_PROT_MASK (0x3 << 20) +#define FTGMAC100_RXDES1_PROT_NONIP (0x0 << 20) +#define FTGMAC100_RXDES1_PROT_IP (0x1 << 20) +#define FTGMAC100_RXDES1_PROT_TCPIP (0x2 << 20) +#define FTGMAC100_RXDES1_PROT_UDPIP (0x3 << 20) +#define FTGMAC100_RXDES1_LLC (1 << 22) +#define FTGMAC100_RXDES1_DF (1 << 23) +#define FTGMAC100_RXDES1_VLANTAG_AVAIL (1 << 24) +#define FTGMAC100_RXDES1_TCP_CHKSUM_ERR (1 << 25) +#define FTGMAC100_RXDES1_UDP_CHKSUM_ERR (1 << 26) +#define FTGMAC100_RXDES1_IP_CHKSUM_ERR (1 << 27) + +#endif /* __FTGMAC100_H */ diff --git a/include/netdev.h b/include/netdev.h index 7f66419..9bbbdad 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -62,6 +62,7 @@ int eth_3com_initialize (bd_t * bis); int fec_initialize (bd_t *bis); int fecmxc_initialize (bd_t *bis); int ftmac100_initialize(bd_t *bits); +int ftgmac100_initialize(bd_t *bits); int greth_initialize(bd_t *bis); void gt6426x_eth_initialize(bd_t *bis); int inca_switch_initialize(bd_t *bis);

Dear Macpaul Lin,
In message 1291969229-3884-1-git-send-email-macpaul@andestech.com you wrote:
Add Faraday's ftgmac100 (gigabit ethernet) MAC controller's driver.
Sub configuration in this driver:
CONFIG_FTGMAC100_EGIGA: Support GE link update with gigabit PHY.
This needs to be documented in the README.
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index b605eea..faeab32 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -48,6 +48,7 @@ COBJS-$(CONFIG_ETHOC) += ethoc.o COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o COBJS-$(CONFIG_FTMAC100) += ftmac100.o +COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o COBJS-$(CONFIG_GRETH) += greth.o COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
Please keep list sorted.
diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c new file mode 100644 index 0000000..7616fcd --- /dev/null +++ b/drivers/net/ftgmac100.c @@ -0,0 +1,598 @@
...
+struct ftgmac100_data {
- volatile struct ftgmac100_txdes txdes[PKTBUFSTX]; /* must be power of 2 */
- volatile struct ftgmac100_rxdes rxdes[PKTBUFSRX]; /* must be power of 2 */
Please re-read Documentation/volatile-considered-harmful.txt and then explain why this volatile here is needed.
...
- for (i = 0; i < 10; i++) {
phycr = readl(&ftgmac100->phycr);
if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) {
debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: phy_addr: %x\n", phy_addr);
Line too long. Please fix globally (consider running checkpatch.pl).
+static int ftgmac100_mdiobus_reset(struct eth_device *dev) +{
- return 0;
+}
Why do we need this function?
+int ftgmac100_phy_read(struct eth_device *dev, int addr,
int reg, u16 *value)
+{
- *value = ftgmac100_mdiobus_read(dev , addr, reg);
- return 0;
+}
Error handling missing.
+int ftgmac100_phy_write(struct eth_device *dev, int addr,
int reg, u16 value)
+{
- ftgmac100_mdiobus_write(dev, addr, reg, value);
- return 0;
+}
Error handling missing. Please check and fix globally.
+static int ftgmac100_phy_reset(struct eth_device *dev) +{
...
- for (i = 0; i < 100000 / 100; i++) {
ftgmac100_phy_read(dev, priv->phy_addr,
MII_BMSR, &status);
if (status & BMSR_ANEGCOMPLETE)
break;
udelay(100);
Are you sure that autonegotiation will always complete within 100 milliseconds or less?
- /* Check if the PHY is up to snuff... */
- for (phy_addr=0; phy_addr < CONFIG_PHY_MAX_ADDR; phy_addr++) {
ftgmac100_phy_read(dev, phy_addr,
MII_PHYSID1, &phy_id);
See note above about error handling. You need to reqork all your code.
/* When it is unable to found PHY, the interface usually return 0xffff or 0x0000 */
Ditto for line too long.
for (i = 0; i < 100000 / 100; i++) {
ftgmac100_phy_read(dev, priv->phy_addr,
MII_BMSR, &status);
if (status & BMSR_LSTATUS)
break;
udelay(100);
See note above - are 100 milliseconds always sufficient?
- }
- if (!(status & BMSR_LSTATUS)) {
printf("%s: link down\n", dev->name);
return 3;
- } else {
No "else" needed after a "return".
+#ifdef CONFIG_FTGMAC100_EGIGA
ftgmac100_phy_read(dev, priv->phy_addr,
MII_STAT1000, &stat_ge); /* 1000 Base-T Status Register */
speed = (stat_ge & (LPA_1000FULL | LPA_1000HALF)
? 1 : 0);
duplex = ((stat_ge & LPA_1000FULL)
? 1 : 0);
if (speed) { /* Speed is 1000 */
printf("%s: link up, %sMbps %s-duplex\n",
dev->name,
speed ? "1000" : "10/100",
This makes no sense. You tested "speed" 4 lines above, so we know it's always true.
duplex ? "full" : "half");
return 0;
}
+#endif
ftgmac100_phy_read(dev, priv->phy_addr,
MII_ADVERTISE, &adv);
ftgmac100_phy_read(dev, priv->phy_addr,
MII_LPA, &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\n",
dev->name,
speed ? "100" : "10",
duplex ? "full" : "half");
- }
- return 0;
+}
+int ftgmac100_update_link_speed(struct eth_device *dev) +{
- struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
- struct ftgmac100_data *priv = dev->priv;
- unsigned short stat_fe;
- unsigned short stat_ge;
+#ifdef CONFIG_FTGMAC100_EGIGA
- ftgmac100_phy_read(dev, priv->phy_addr,
MII_STAT1000, &stat_ge); /* 1000 Base-T Status Register */
+#endif
- ftgmac100_phy_read(dev, priv->phy_addr,
MII_BMSR, &stat_fe);
- if (!(stat_fe & BMSR_LSTATUS)) /* link status up? */
return 1;
+#ifdef CONFIG_FTGMAC100_EGIGA
- if (stat_ge & LPA_1000FULL) {
/*set Emac for 1000BaseTX and Full Duplex */
writel((readl(&ftgmac100->maccr) &
~(FTGMAC100_MACCR_GIGA_MODE |
FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
) | FTGMAC100_MACCR_GIGA_MODE | FTGMAC100_MACCR_FULLDUP,
&ftgmac100->maccr);
return 0;
- }
- if (stat_ge & LPA_1000HALF) {
/*set Emac for 1000BaseTX and Half Duplex */
writel((readl(&ftgmac100->maccr) &
~(FTGMAC100_MACCR_GIGA_MODE |
FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
) | FTGMAC100_MACCR_GIGA_MODE,
&ftgmac100->maccr);
return 0;
- }
+#endif
- if (stat_fe & BMSR_100FULL) {
/*set Emac for 100BaseTX and Full Duplex */
writel((readl(&ftgmac100->maccr) &
~(FTGMAC100_MACCR_GIGA_MODE |
FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
) | FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP,
&ftgmac100->maccr);
return 0;
- }
- if (stat_fe & BMSR_10FULL) {
/*set MII for 10BaseT and Full Duplex */
writel((readl(&ftgmac100->maccr) &
~(FTGMAC100_MACCR_GIGA_MODE |
FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
) | FTGMAC100_MACCR_FULLDUP,
&ftgmac100->maccr);
return 0;
- }
- if (stat_fe & BMSR_100HALF) {
/*set MII for 100BaseTX and Half Duplex */
writel((readl(&ftgmac100->maccr) &
~(FTGMAC100_MACCR_GIGA_MODE |
FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
) | FTGMAC100_MACCR_FAST_MODE,
&ftgmac100->maccr);
return 0;
- }
- if (stat_fe & BMSR_10HALF) {
/*set MII for 10BaseT and Half Duplex */
writel((readl(&ftgmac100->maccr) &
~(FTGMAC100_MACCR_GIGA_MODE |
FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)),
&ftgmac100->maccr);
return 0;
Instead of repeating this code fragment again and again, can you not make the code data driven, i. e. use a table to look up the mask?
- /* pass the packet up to the protocol layers. */
- NetReceive ((void *)curr_des->rxdes3, rxlen);
- /* release buffer to DMA */
- curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
Please remove the blank lines between these on-line comments and the code. Please do globally.
+ftgmac100_send (struct eth_device *dev, volatile void *packet, int length) +{
- struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
- struct ftgmac100_data *priv = dev->priv;
- volatile struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
Please explain why this volatile is needed.
- tmo = get_timer (0) + 5 * CONFIG_SYS_HZ;
- while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
if (get_timer (0) >= tmo) {
This is bound to fail when the timer wraps around.
+#define FTGMAC100_OFFSET_ISR 0x00 +#define FTGMAC100_OFFSET_IER 0x04 +#define FTGMAC100_OFFSET_MAC_MADR 0x08 +#define FTGMAC100_OFFSET_MAC_LADR 0x0c +#define FTGMAC100_OFFSET_MAHT0 0x10 +#define FTGMAC100_OFFSET_MAHT1 0x14 +#define FTGMAC100_OFFSET_NPTXPD 0x18 +#define FTGMAC100_OFFSET_RXPD 0x1c +#define FTGMAC100_OFFSET_NPTXR_BADR 0x20 +#define FTGMAC100_OFFSET_RXR_BADR 0x24 +#define FTGMAC100_OFFSET_HPTXPD 0x28 +#define FTGMAC100_OFFSET_HPTXR_BADR 0x2c
...
Ouch.
+struct ftgmac100 {
- unsigned int isr; /* 0x00 */
- unsigned int ier; /* 0x04 */
- unsigned int mac_madr; /* 0x08 */
- unsigned int mac_ladr; /* 0x0c */
- unsigned int maht0; /* 0x10 */
- unsigned int maht1; /* 0x14 */
- unsigned int txpd; /* 0x18 */
- unsigned int rxpd; /* 0x1c */
- unsigned int txr_badr; /* 0x20 */
- unsigned int rxr_badr; /* 0x24 */
- unsigned int hptxpd; /* 0x28 */
- unsigned int hptxpd_badr; /* 0x2c */
Um.... We don't need both offset tables and C structs, do we?
Please dump the offset table.
--- a/include/netdev.h +++ b/include/netdev.h @@ -62,6 +62,7 @@ int eth_3com_initialize (bd_t * bis); int fec_initialize (bd_t *bis); int fecmxc_initialize (bd_t *bis); int ftmac100_initialize(bd_t *bits); +int ftgmac100_initialize(bd_t *bits); int greth_initialize(bd_t *bis); void gt6426x_eth_initialize(bd_t *bis); int inca_switch_initialize(bd_t *bis);
Please keep list sorted.
Best regards,
Wolfgang Denk

Dear Wolfgang,
Please take a look at the similar driver "ftmac100.c", Some coding patterns in "ftgmac100.c" are followed as "ftmac100.c". Since the ftgmac100 has the similar hardware logic inside as the same as ftmac100. The code of ftgmac100.c is modified from ftmac100.c So I think you've permit that kind of coding style and related issues, this code of ftgmac100 shouldn't be a problem. ;p
2010/12/13 Wolfgang Denk wd@denx.de:
Dear Macpaul Lin,
In message 1291969229-3884-1-git-send-email-macpaul@andestech.com you wrote:
Add Faraday's ftgmac100 (gigabit ethernet) MAC controller's driver.
Sub configuration in this driver:
CONFIG_FTGMAC100_EGIGA: Support GE link update with gigabit PHY.
This needs to be documented in the README.
Okay, next patch will trying to add correct format of this statement into README.
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index b605eea..faeab32 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -48,6 +48,7 @@ COBJS-$(CONFIG_ETHOC) += ethoc.o COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o COBJS-$(CONFIG_FTMAC100) += ftmac100.o +COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o COBJS-$(CONFIG_GRETH) += greth.o COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
Please keep list sorted.
OK. g comes before m. ;p
diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c new file mode 100644 index 0000000..7616fcd --- /dev/null +++ b/drivers/net/ftgmac100.c @@ -0,0 +1,598 @@
...
+struct ftgmac100_data {
- volatile struct ftgmac100_txdes txdes[PKTBUFSTX]; /* must be power of 2 */
- volatile struct ftgmac100_rxdes rxdes[PKTBUFSRX]; /* must be power of 2 */
Please re-read Documentation/volatile-considered-harmful.txt and then explain why this volatile here is needed.
This code was copied originate from ftmac100.c
...
- for (i = 0; i < 10; i++) {
- phycr = readl(&ftgmac100->phycr);
- if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) {
- debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: phy_addr: %x\n", phy_addr);
Line too long. Please fix globally (consider running checkpatch.pl).
Ok.
+static int ftgmac100_mdiobus_reset(struct eth_device *dev) +{
- return 0;
+}
Why do we need this function?
Okay, I will take it off. It comes from Linux driver "ftgmac100.c"
+int ftgmac100_phy_read(struct eth_device *dev, int addr,
- int reg, u16 *value)
+{
- *value = ftgmac100_mdiobus_read(dev , addr, reg);
- return 0;
+}
Error handling missing.
Okay, will fix it.
+int ftgmac100_phy_write(struct eth_device *dev, int addr,
- int reg, u16 value)
+{
- ftgmac100_mdiobus_write(dev, addr, reg, value);
- return 0;
+}
Error handling missing. Please check and fix globally.
Okay, will fix it.
+static int ftgmac100_phy_reset(struct eth_device *dev) +{
...
- for (i = 0; i < 100000 / 100; i++) {
- ftgmac100_phy_read(dev, priv->phy_addr,
- MII_BMSR, &status);
- if (status & BMSR_ANEGCOMPLETE)
- break;
- udelay(100);
Are you sure that autonegotiation will always complete within 100 milliseconds or less?
On the board I have was running at 200MHz ~ 500Mhz, it is usaully done. What value will you suggest? 1000 millisecond?
- /* Check if the PHY is up to snuff... */
- for (phy_addr=0; phy_addr < CONFIG_PHY_MAX_ADDR; phy_addr++) {
- ftgmac100_phy_read(dev, phy_addr,
- MII_PHYSID1, &phy_id);
See note above about error handling. You need to reqork all your code.
Okay.
- /* When it is unable to found PHY, the interface usually return 0xffff or 0x0000 */
Ditto for line too long.
Okay.
- for (i = 0; i < 100000 / 100; i++) {
- ftgmac100_phy_read(dev, priv->phy_addr,
- MII_BMSR, &status);
- if (status & BMSR_LSTATUS)
- break;
- udelay(100);
See note above - are 100 milliseconds always sufficient?
- }
- if (!(status & BMSR_LSTATUS)) {
- printf("%s: link down\n", dev->name);
- return 3;
- } else {
No "else" needed after a "return".
Ah, thanks.
+#ifdef CONFIG_FTGMAC100_EGIGA
- ftgmac100_phy_read(dev, priv->phy_addr,
- MII_STAT1000, &stat_ge); /* 1000 Base-T Status Register */
- speed = (stat_ge & (LPA_1000FULL | LPA_1000HALF)
- ? 1 : 0);
- duplex = ((stat_ge & LPA_1000FULL)
- ? 1 : 0);
- if (speed) { /* Speed is 1000 */
- printf("%s: link up, %sMbps %s-duplex\n",
- dev->name,
- speed ? "1000" : "10/100",
This makes no sense. You tested "speed" 4 lines above, so we know it's always true.
Oh thanks, the speed test of gigabit part will be fixed.
- duplex ? "full" : "half");
- return 0;
- }
+#endif
- ftgmac100_phy_read(dev, priv->phy_addr,
- MII_ADVERTISE, &adv);
- ftgmac100_phy_read(dev, priv->phy_addr,
- MII_LPA, &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\n",
- dev->name,
- speed ? "100" : "10",
- duplex ? "full" : "half");
- }
- return 0;
+}
+int ftgmac100_update_link_speed(struct eth_device *dev) +{
- struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
- struct ftgmac100_data *priv = dev->priv;
- unsigned short stat_fe;
- unsigned short stat_ge;
+#ifdef CONFIG_FTGMAC100_EGIGA
- ftgmac100_phy_read(dev, priv->phy_addr,
- MII_STAT1000, &stat_ge); /* 1000 Base-T Status Register */
+#endif
- ftgmac100_phy_read(dev, priv->phy_addr,
- MII_BMSR, &stat_fe);
- if (!(stat_fe & BMSR_LSTATUS)) /* link status up? */
- return 1;
+#ifdef CONFIG_FTGMAC100_EGIGA
- if (stat_ge & LPA_1000FULL) {
- /*set Emac for 1000BaseTX and Full Duplex */
- writel((readl(&ftgmac100->maccr) &
- ~(FTGMAC100_MACCR_GIGA_MODE |
- FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
- ) | FTGMAC100_MACCR_GIGA_MODE | FTGMAC100_MACCR_FULLDUP,
- &ftgmac100->maccr);
- return 0;
- }
- if (stat_ge & LPA_1000HALF) {
- /*set Emac for 1000BaseTX and Half Duplex */
- writel((readl(&ftgmac100->maccr) &
- ~(FTGMAC100_MACCR_GIGA_MODE |
- FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
- ) | FTGMAC100_MACCR_GIGA_MODE,
- &ftgmac100->maccr);
- return 0;
- }
+#endif
- if (stat_fe & BMSR_100FULL) {
- /*set Emac for 100BaseTX and Full Duplex */
- writel((readl(&ftgmac100->maccr) &
- ~(FTGMAC100_MACCR_GIGA_MODE |
- FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
- ) | FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP,
- &ftgmac100->maccr);
- return 0;
- }
- if (stat_fe & BMSR_10FULL) {
- /*set MII for 10BaseT and Full Duplex */
- writel((readl(&ftgmac100->maccr) &
- ~(FTGMAC100_MACCR_GIGA_MODE |
- FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
- ) | FTGMAC100_MACCR_FULLDUP,
- &ftgmac100->maccr);
- return 0;
- }
- if (stat_fe & BMSR_100HALF) {
- /*set MII for 100BaseTX and Half Duplex */
- writel((readl(&ftgmac100->maccr) &
- ~(FTGMAC100_MACCR_GIGA_MODE |
- FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)
- ) | FTGMAC100_MACCR_FAST_MODE,
- &ftgmac100->maccr);
- return 0;
- }
- if (stat_fe & BMSR_10HALF) {
- /*set MII for 10BaseT and Half Duplex */
- writel((readl(&ftgmac100->maccr) &
- ~(FTGMAC100_MACCR_GIGA_MODE |
- FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP)),
- &ftgmac100->maccr);
- return 0;
Instead of repeating this code fragment again and again, can you not make the code data driven, i. e. use a table to look up the mask?
I found at91_emac.c accepts this kind of code. So I used this pattern to do link update detection. I will try to think another method to do so.
- /* pass the packet up to the protocol layers. */
- NetReceive ((void *)curr_des->rxdes3, rxlen);
- /* release buffer to DMA */
- curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
Please remove the blank lines between these on-line comments and the code. Please do globally.
Okay, but please check ftmac100.c I just followed the coding style I guess which should be permit on last time. Will to cleanup on next patch.
+ftgmac100_send (struct eth_device *dev, volatile void *packet, int length) +{
- struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
- struct ftgmac100_data *priv = dev->priv;
- volatile struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
Please explain why this volatile is needed.
Please check ftmac100.c
- tmo = get_timer (0) + 5 * CONFIG_SYS_HZ;
- while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
- if (get_timer (0) >= tmo) {
This is bound to fail when the timer wraps around.
It is a tx timeout detection necessary to monitor if hardware behaves correctly. Hardware should clear FTGMAC100_TXDES0_TXDMA_OWN bit before driver here to examine the bit is cleared or not. If hardware didn't clear this bit, it might indicate hardware has problem will reset is needed.
+#define FTGMAC100_OFFSET_ISR 0x00 +#define FTGMAC100_OFFSET_IER 0x04 +#define FTGMAC100_OFFSET_MAC_MADR 0x08 +#define FTGMAC100_OFFSET_MAC_LADR 0x0c +#define FTGMAC100_OFFSET_MAHT0 0x10 +#define FTGMAC100_OFFSET_MAHT1 0x14 +#define FTGMAC100_OFFSET_NPTXPD 0x18 +#define FTGMAC100_OFFSET_RXPD 0x1c +#define FTGMAC100_OFFSET_NPTXR_BADR 0x20 +#define FTGMAC100_OFFSET_RXR_BADR 0x24 +#define FTGMAC100_OFFSET_HPTXPD 0x28 +#define FTGMAC100_OFFSET_HPTXR_BADR 0x2c
...
Ouch.
+struct ftgmac100 {
- unsigned int isr; /* 0x00 */
- unsigned int ier; /* 0x04 */
- unsigned int mac_madr; /* 0x08 */
- unsigned int mac_ladr; /* 0x0c */
- unsigned int maht0; /* 0x10 */
- unsigned int maht1; /* 0x14 */
- unsigned int txpd; /* 0x18 */
- unsigned int rxpd; /* 0x1c */
- unsigned int txr_badr; /* 0x20 */
- unsigned int rxr_badr; /* 0x24 */
- unsigned int hptxpd; /* 0x28 */
- unsigned int hptxpd_badr; /* 0x2c */
Um.... We don't need both offset tables and C structs, do we?
Please dump the offset table.
This is all the offset table here. Start from 0x0 to 0xc8. The offset table here and the following structure are identical. However, I'm afraid of that some customer will need to access offset table with assembly in lowlevel_init.S. So I just keep a copy here.
--- a/include/netdev.h +++ b/include/netdev.h @@ -62,6 +62,7 @@ int eth_3com_initialize (bd_t * bis); int fec_initialize (bd_t *bis); int fecmxc_initialize (bd_t *bis); int ftmac100_initialize(bd_t *bits); +int ftgmac100_initialize(bd_t *bits); int greth_initialize(bd_t *bis); void gt6426x_eth_initialize(bd_t *bis); int inca_switch_initialize(bd_t *bis);
Please keep list sorted.
Best regards,
Wolfgang Denk
-- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de "Have you lived in this village all your life?" "No, not yet." _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Dear Macpaul Lin,
In message AANLkTikJM4hAw8yAWeUPiumiiN3vr9qgY-TT8KyYuSVZ@mail.gmail.com you wrote:
Please take a look at the similar driver "ftmac100.c", Some coding patterns in "ftgmac100.c" are followed as "ftmac100.c".
Oh. Thanks for pointing out. So this other driver needs to be fixed, too.
So I think you've permit that kind of coding style and related issues, this code of ftgmac100 shouldn't be a problem. ;p
The fact that some bad code slips through a review does not mean that it's blessed.
Best regards,
Wolfgang Denk
participants (3)
-
Macpaul Lin
-
Macpaul Lin
-
Wolfgang Denk