diff options
-rw-r--r-- | drivers/net/Kconfig | 26 | ||||
-rw-r--r-- | drivers/net/ftgmac100.c | 223 | ||||
-rw-r--r-- | include/netdev.h | 1 |
3 files changed, 157 insertions, 93 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 3ce46c84907..fd1c48049a9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -186,6 +186,32 @@ config FTMAC100 help This MAC is present in Andestech SoCs. +config FTGMAC100 + bool "Ftgmac100 Ethernet Support" + depends on DM_ETH + select PHYLIB + help + This driver supports the Faraday's FTGMAC100 Gigabit SoC + Ethernet controller that can be found on Aspeed SoCs (which + include NCSI). + + It is fully compliant with IEEE 802.3 specification for + 10/100 Mbps Ethernet and IEEE 802.3z specification for 1000 + Mbps Ethernet and includes Reduced Media Independent + Interface (RMII) and Reduced Gigabit Media Independent + Interface (RGMII) interfaces. It adopts an AHB bus interface + and integrates a link list DMA engine with direct M-Bus + accesses for transmitting and receiving packets. It has + independent TX/RX fifos, supports half and full duplex (1000 + Mbps mode only supports full duplex), flow control for full + duplex and backpressure for half duplex. + + The FTGMAC100 also implements IP, TCP, UDP checksum offloads + and supports IEEE 802.1Q VLAN tag insertion and removal. It + offers high-priority transmit queue for QoS and CoS + applications. + + config MVGBE bool "Marvell Orion5x/Kirkwood network interface support" depends on KIRKWOOD || ORION5X diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c index c996f5f4a16..67a7c73503c 100644 --- a/drivers/net/ftgmac100.c +++ b/drivers/net/ftgmac100.c @@ -7,15 +7,16 @@ * * (C) Copyright 2010 Andes Technology * Macpaul Lin <macpaul@andestech.com> + * + * Copyright (C) 2018, IBM Corporation. */ -#include <config.h> -#include <common.h> +#include <dm.h> +#include <miiphy.h> #include <malloc.h> #include <net.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/dma-mapping.h> -#include <linux/mii.h> #include "ftgmac100.h" @@ -28,7 +29,19 @@ /* PKTBUFSTX/PKTBUFSRX must both be power of 2 */ #define PKTBUFSTX 4 /* must be power of 2 */ +/** + * struct ftgmac100_data - private data for the FTGMAC100 driver + * + * @iobase: The base address of the hardware registers + * @txdes: The array of transmit descriptors + * @rxdes: The array of receive descriptors + * @tx_index: Transmit descriptor index in @txdes + * @rx_index: Receive descriptor index in @rxdes + * @phy_addr: The PHY interface address to use + */ struct ftgmac100_data { + struct ftgmac100 *iobase; + ulong txdes_dma; struct ftgmac100_txdes *txdes; ulong rxdes_dma; @@ -41,10 +54,10 @@ struct ftgmac100_data { /* * struct mii_bus functions */ -static int ftgmac100_mdiobus_read(struct eth_device *dev, int phy_addr, - int regnum) +static int ftgmac100_mdiobus_read(struct ftgmac100_data *priv, int phy_addr, + int regnum) { - struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; + struct ftgmac100 *ftgmac100 = priv->iobase; int phycr; int i; @@ -76,10 +89,10 @@ static int ftgmac100_mdiobus_read(struct eth_device *dev, int phy_addr, return -1; } -static int ftgmac100_mdiobus_write(struct eth_device *dev, int phy_addr, - int regnum, u16 value) +static int ftgmac100_mdiobus_write(struct ftgmac100_data *priv, int phy_addr, + int regnum, u16 value) { - struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; + struct ftgmac100 *ftgmac100 = priv->iobase; int phycr; int data; int i; @@ -114,9 +127,10 @@ static int ftgmac100_mdiobus_write(struct eth_device *dev, int phy_addr, return -1; } -int ftgmac100_phy_read(struct eth_device *dev, int addr, int reg, u16 *value) +int ftgmac100_phy_read(struct ftgmac100_data *priv, int addr, int reg, + u16 *value) { - *value = ftgmac100_mdiobus_read(dev , addr, reg); + *value = ftgmac100_mdiobus_read(priv, addr, reg); if (*value == -1) return -1; @@ -124,31 +138,31 @@ int ftgmac100_phy_read(struct eth_device *dev, int addr, int reg, u16 *value) return 0; } -int ftgmac100_phy_write(struct eth_device *dev, int addr, int reg, u16 value) +int ftgmac100_phy_write(struct ftgmac100_data *priv, int addr, int reg, + u16 value) { - if (ftgmac100_mdiobus_write(dev, addr, reg, value) == -1) + if (ftgmac100_mdiobus_write(priv, addr, reg, value) == -1) return -1; return 0; } -static int ftgmac100_phy_reset(struct eth_device *dev) +static int ftgmac100_phy_reset(struct ftgmac100_data *priv, struct udevice *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); + ftgmac100_phy_write(priv, 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)); + ftgmac100_phy_write(priv, 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); + ftgmac100_phy_read(priv, priv->phy_addr, MII_BMSR, &status); if (status & BMSR_ANEGCOMPLETE) break; @@ -166,19 +180,17 @@ static int ftgmac100_phy_reset(struct eth_device *dev) return 1; } -static int ftgmac100_phy_init(struct eth_device *dev) +static int ftgmac100_phy_init(struct ftgmac100_data *priv, struct udevice *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++) { + for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { - ftgmac100_phy_read(dev, phy_addr, MII_PHYSID1, &phy_id); + ftgmac100_phy_read(priv, phy_addr, MII_PHYSID1, &phy_id); /* * When it is unable to found PHY, @@ -197,15 +209,15 @@ static int ftgmac100_phy_init(struct eth_device *dev) return 0; } - ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &status); + ftgmac100_phy_read(priv, priv->phy_addr, MII_BMSR, &status); if (!(status & BMSR_LSTATUS)) { /* Try to re-negotiate if we don't have link already. */ - ftgmac100_phy_reset(dev); + ftgmac100_phy_reset(priv, dev); for (i = 0; i < 100000 / 100; i++) { - ftgmac100_phy_read(dev, priv->phy_addr, - MII_BMSR, &status); + ftgmac100_phy_read(priv, priv->phy_addr, + MII_BMSR, &status); if (status & BMSR_LSTATUS) break; udelay(100); @@ -235,8 +247,8 @@ static int ftgmac100_phy_init(struct eth_device *dev) } #endif - ftgmac100_phy_read(dev, priv->phy_addr, MII_ADVERTISE, &adv); - ftgmac100_phy_read(dev, priv->phy_addr, MII_LPA, &lpa); + ftgmac100_phy_read(priv, priv->phy_addr, MII_ADVERTISE, &adv); + ftgmac100_phy_read(priv, priv->phy_addr, MII_LPA, &lpa); media = mii_nway_result(lpa & adv); speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? 1 : 0); @@ -248,21 +260,19 @@ static int ftgmac100_phy_init(struct eth_device *dev) return 1; } -static int ftgmac100_update_link_speed(struct eth_device *dev) +static int ftgmac100_update_link_speed(struct ftgmac100_data *priv) { - struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; - struct ftgmac100_data *priv = dev->priv; - + struct ftgmac100 *ftgmac100 = priv->iobase; unsigned short stat_fe; unsigned short stat_ge; unsigned int maccr; #ifdef CONFIG_FTGMAC100_EGIGA /* 1000 Base-T Status Register */ - ftgmac100_phy_read(dev, priv->phy_addr, MII_STAT1000, &stat_ge); + ftgmac100_phy_read(priv, priv->phy_addr, MII_STAT1000, &stat_ge); #endif - ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &stat_fe); + ftgmac100_phy_read(priv, priv->phy_addr, MII_BMSR, &stat_fe); if (!(stat_fe & BMSR_LSTATUS)) /* link status up? */ return 0; @@ -315,9 +325,9 @@ static int ftgmac100_update_link_speed(struct eth_device *dev) /* * Reset MAC */ -static void ftgmac100_reset(struct eth_device *dev) +static void ftgmac100_reset(struct ftgmac100_data *priv) { - struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; + struct ftgmac100 *ftgmac100 = priv->iobase; debug("%s()\n", __func__); @@ -330,10 +340,10 @@ static void ftgmac100_reset(struct eth_device *dev) /* * Set MAC address */ -static void ftgmac100_set_mac(struct eth_device *dev, - const unsigned char *mac) +static int ftgmac100_set_mac(struct ftgmac100_data *priv, + const unsigned char *mac) { - struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; + struct ftgmac100 *ftgmac100 = priv->iobase; unsigned int maddr = mac[0] << 8 | mac[1]; unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; @@ -341,31 +351,28 @@ static void ftgmac100_set_mac(struct eth_device *dev, writel(maddr, &ftgmac100->mac_madr); writel(laddr, &ftgmac100->mac_ladr); -} -static void ftgmac100_set_mac_from_env(struct eth_device *dev) -{ - eth_env_get_enetaddr("ethaddr", dev->enetaddr); - - ftgmac100_set_mac(dev, dev->enetaddr); + return 0; } /* * disable transmitter, receiver */ -static void ftgmac100_halt(struct eth_device *dev) +static void ftgmac100_stop(struct udevice *dev) { - struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; + struct ftgmac100_data *priv = dev_get_priv(dev); + struct ftgmac100 *ftgmac100 = priv->iobase; debug("%s()\n", __func__); writel(0, &ftgmac100->maccr); } -static int ftgmac100_init(struct eth_device *dev, bd_t *bd) +static int ftgmac100_start(struct udevice *dev) { - struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; - struct ftgmac100_data *priv = dev->priv; + struct eth_pdata *plat = dev_get_platdata(dev); + struct ftgmac100_data *priv = dev_get_priv(dev); + struct ftgmac100 *ftgmac100 = priv->iobase; struct ftgmac100_txdes *txdes; struct ftgmac100_rxdes *rxdes; unsigned int maccr; @@ -374,6 +381,8 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd) debug("%s()\n", __func__); + ftgmac100_reset(priv); + if (!priv->txdes) { txdes = dma_alloc_coherent( sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma); @@ -395,7 +404,7 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd) rxdes = priv->rxdes; /* set the ethernet address */ - ftgmac100_set_mac_from_env(dev); + ftgmac100_set_mac(priv, plat->enetaddr); /* disable all interrupts */ writel(0, &ftgmac100->ier); @@ -453,20 +462,34 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd) writel(maccr, &ftgmac100->maccr); - if (!ftgmac100_phy_init(dev)) { - if (!ftgmac100_update_link_speed(dev)) + if (!ftgmac100_phy_init(priv, dev)) { + if (!ftgmac100_update_link_speed(priv)) return -1; } return 0; } +static int ftgmac100_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct ftgmac100_data *priv = dev_get_priv(dev); + struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index]; + + /* Release buffer to DMA */ + curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY; + + /* Move to next descriptor */ + priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX; + + return 0; +} + /* * Get a data block via Ethernet */ -static int ftgmac100_recv(struct eth_device *dev) +static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp) { - struct ftgmac100_data *priv = dev->priv; + struct ftgmac100_data *priv = dev_get_priv(dev); struct ftgmac100_rxdes *curr_des; unsigned short rxlen; @@ -505,10 +528,10 @@ static int ftgmac100_recv(struct eth_device *dev) /* * Send a data block via Ethernet */ -static int ftgmac100_send(struct eth_device *dev, void *packet, int length) +static int ftgmac100_send(struct udevice *dev, void *packet, int length) { - struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; - struct ftgmac100_data *priv = dev->priv; + struct ftgmac100_data *priv = dev_get_priv(dev); + struct ftgmac100 *ftgmac100 = priv->iobase; struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index]; if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) { @@ -540,43 +563,59 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length) return 0; } -int ftgmac100_initialize(bd_t *bd) +static int ftgmac100_write_hwaddr(struct udevice *dev) { - struct eth_device *dev; - struct ftgmac100_data *priv; + struct eth_pdata *pdata = dev_get_platdata(dev); + struct ftgmac100_data *priv = dev_get_priv(dev); - 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)); + return ftgmac100_set_mac(priv, pdata->enetaddr); +} - strcpy(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; +static int ftgmac100_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); - eth_register(dev); + pdata->iobase = devfdt_get_addr(dev); + return 0; +} - ftgmac100_reset(dev); +static int ftgmac100_probe(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct ftgmac100_data *priv = dev_get_priv(dev); - return 1; + priv->iobase = (struct ftgmac100 *)pdata->iobase; + return 0; +} -free_dev: - free(dev); -out: +static int ftgmac100_remove(struct udevice *dev) +{ return 0; } + +static const struct eth_ops ftgmac100_ops = { + .start = ftgmac100_start, + .send = ftgmac100_send, + .recv = ftgmac100_recv, + .stop = ftgmac100_stop, + .free_pkt = ftgmac100_free_pkt, + .write_hwaddr = ftgmac100_write_hwaddr, +}; + +static const struct udevice_id ftgmac100_ids[] = { + { .compatible = "faraday,ftgmac100" }, + { } +}; + +U_BOOT_DRIVER(ftgmac100) = { + .name = "ftgmac100", + .id = UCLASS_ETH, + .of_match = ftgmac100_ids, + .ofdata_to_platdata = ftgmac100_ofdata_to_platdata, + .probe = ftgmac100_probe, + .remove = ftgmac100_remove, + .ops = &ftgmac100_ops, + .priv_auto_alloc_size = sizeof(struct ftgmac100_data), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/include/netdev.h b/include/netdev.h index 55001625fb9..0a1a3a2d8da 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -43,7 +43,6 @@ int ethoc_initialize(u8 dev_num, int base_addr); int fec_initialize (bd_t *bis); int fecmxc_initialize(bd_t *bis); int fecmxc_initialize_multi(bd_t *bis, int dev_id, int phy_id, uint32_t addr); -int ftgmac100_initialize(bd_t *bits); int ftmac100_initialize(bd_t *bits); int ftmac110_initialize(bd_t *bits); void gt6426x_eth_initialize(bd_t *bis); |