[U-Boot] [PATCH 0/5] Support for the Faraday ftgmac100 controller

Hello,
This series re-adds a driver for the Faraday ftgmac100 controller and its Aspeed variant as as one can find on the OpenPOWER platforms. I have choosen to remove and re-add the driver to ease review of the changes, which are numerous, but we can proceed differently if you prefer.
The DT patch depends on:
[PATCH 3/3] aspeed: Add SPI support to the ast2500 Eval Board https://lists.denx.de/pipermail/u-boot/2018-September/340568.html
It was tested on the AST2500 evb.
Git tree available here:
https://github.com/legoater/u-boot/commits/aspeed
Thanks,
C.
Cédric Le Goater (5): net: remove the Faraday ftgmac100 controller driver net: re-add support for the Faraday ftgmac100 controller aspeed: ast2500: fix missing break in D2PLL clock enablement net: ftgmac100: add support for Aspeed SoC aspeed: Activate ethernet devices on the ast2500 Eval Board
drivers/net/ftgmac100.h | 163 +++---- include/netdev.h | 1 - drivers/clk/aspeed/clk_ast2500.c | 1 + drivers/net/ftgmac100.c | 701 +++++++++++++++---------------- arch/arm/dts/ast2500-evb.dts | 17 + arch/arm/dts/ast2500.dtsi | 4 +- configs/evb-ast2500_defconfig | 8 + drivers/net/Kconfig | 8 + 8 files changed, 456 insertions(+), 447 deletions(-)

There are too many changes in the following patch fixing support for the Faraday ftgmac100 controller. To ease the review, remove the whole file which is not compiled anymore today (no Kconfig option for the driver).
Signed-off-by: Cédric Le Goater clg@kaod.org --- drivers/net/ftgmac100.h | 242 ----------------- include/netdev.h | 1 - drivers/net/ftgmac100.c | 582 ---------------------------------------- drivers/net/Makefile | 1 - 4 files changed, 826 deletions(-) delete mode 100644 drivers/net/ftgmac100.h delete mode 100644 drivers/net/ftgmac100.c
diff --git a/drivers/net/ftgmac100.h b/drivers/net/ftgmac100.h deleted file mode 100644 index ffbe1f3e3fa7..000000000000 --- a/drivers/net/ftgmac100.h +++ /dev/null @@ -1,242 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * 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 - */ - -#ifndef __FTGMAC100_H -#define __FTGMAC100_H - -/* The registers offset table of ftgmac100 */ -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 55001625fb92..0a1a3a2d8da2 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); diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c deleted file mode 100644 index c996f5f4a167..000000000000 --- a/drivers/net/ftgmac100.c +++ /dev/null @@ -1,582 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * 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 - */ - -#include <config.h> -#include <common.h> -#include <malloc.h> -#include <net.h> -#include <asm/io.h> -#include <asm/dma-mapping.h> -#include <linux/mii.h> - -#include "ftgmac100.h" - -#define ETH_ZLEN 60 -#define CFG_XBUF_SIZE 1536 - -/* RBSR - hw default init value is also 0x640 */ -#define RBSR_DEFAULT_VALUE 0x640 - -/* PKTBUFSTX/PKTBUFSRX must both be power of 2 */ -#define PKTBUFSTX 4 /* must be power of 2 */ - -struct ftgmac100_data { - ulong txdes_dma; - struct ftgmac100_txdes *txdes; - ulong rxdes_dma; - struct ftgmac100_rxdes *rxdes; - 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; -} - -int ftgmac100_phy_read(struct eth_device *dev, int addr, int reg, u16 *value) -{ - *value = ftgmac100_mdiobus_read(dev , addr, reg); - - if (*value == -1) - return -1; - - return 0; -} - -int ftgmac100_phy_write(struct eth_device *dev, int addr, int reg, u16 value) -{ - if (ftgmac100_mdiobus_write(dev, addr, reg, value) == -1) - return -1; - - 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; - mdelay(1); - } - - 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 0; - } - - return 1; -} - -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 0; - } - - 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. */ - ftgmac100_phy_reset(dev); - - 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 0; - } - -#ifdef CONFIG_FTGMAC100_EGIGA - /* 1000 Base-T Status Register */ - ftgmac100_phy_read(dev, priv->phy_addr, - MII_STAT1000, &stat_ge); - - 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, 1000bps %s-duplex\n", - dev->name, 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 1; -} - -static 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; - unsigned int maccr; - -#ifdef CONFIG_FTGMAC100_EGIGA - /* 1000 Base-T Status Register */ - ftgmac100_phy_read(dev, priv->phy_addr, MII_STAT1000, &stat_ge); -#endif - - ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &stat_fe); - - if (!(stat_fe & BMSR_LSTATUS)) /* link status up? */ - return 0; - - /* read MAC control register and clear related bits */ - maccr = readl(&ftgmac100->maccr) & - ~(FTGMAC100_MACCR_GIGA_MODE | - FTGMAC100_MACCR_FAST_MODE | - FTGMAC100_MACCR_FULLDUP); - -#ifdef CONFIG_FTGMAC100_EGIGA - if (stat_ge & LPA_1000FULL) { - /* set gmac for 1000BaseTX and Full Duplex */ - maccr |= FTGMAC100_MACCR_GIGA_MODE | FTGMAC100_MACCR_FULLDUP; - } - - if (stat_ge & LPA_1000HALF) { - /* set gmac for 1000BaseTX and Half Duplex */ - maccr |= FTGMAC100_MACCR_GIGA_MODE; - } -#endif - - if (stat_fe & BMSR_100FULL) { - /* set MII for 100BaseTX and Full Duplex */ - maccr |= FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP; - } - - if (stat_fe & BMSR_10FULL) { - /* set MII for 10BaseT and Full Duplex */ - maccr |= FTGMAC100_MACCR_FULLDUP; - } - - if (stat_fe & BMSR_100HALF) { - /* set MII for 100BaseTX and Half Duplex */ - maccr |= FTGMAC100_MACCR_FAST_MODE; - } - - if (stat_fe & BMSR_10HALF) { - /* set MII for 10BaseT and Half Duplex */ - /* we have already clear these bits, do nothing */ - ; - } - - /* update MII config into maccr */ - writel(maccr, &ftgmac100->maccr); - - 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_env_get_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; - struct ftgmac100_txdes *txdes; - struct ftgmac100_rxdes *rxdes; - unsigned int maccr; - void *buf; - int i; - - debug("%s()\n", __func__); - - if (!priv->txdes) { - txdes = dma_alloc_coherent( - sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma); - if (!txdes) - panic("ftgmac100: out of memory\n"); - memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX); - priv->txdes = txdes; - } - txdes = priv->txdes; - - if (!priv->rxdes) { - rxdes = dma_alloc_coherent( - sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma); - if (!rxdes) - panic("ftgmac100: out of memory\n"); - memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX); - priv->rxdes = rxdes; - } - rxdes = priv->rxdes; - - /* 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 */ - if (!txdes[i].txdes2) { - buf = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE); - if (!buf) - panic("ftgmac100: out of memory\n"); - txdes[i].txdes3 = virt_to_phys(buf); - txdes[i].txdes2 = (uint)buf; - } - txdes[i].txdes1 = 0; - } - - for (i = 0; i < PKTBUFSRX; i++) { - /* RXBUF_BADR */ - if (!rxdes[i].rxdes2) { - buf = net_rx_packets[i]; - rxdes[i].rxdes3 = virt_to_phys(buf); - rxdes[i].rxdes2 = (uint)buf; - } - rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY; - } - - /* transmit ring */ - writel(priv->txdes_dma, &ftgmac100->txr_badr); - - /* receive ring */ - writel(priv->rxdes_dma, &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)) { - if (!ftgmac100_update_link_speed(dev)) - return -1; - } - - return 0; -} - -/* - * Get a data block via Ethernet - */ -static int ftgmac100_recv(struct eth_device *dev) -{ - struct ftgmac100_data *priv = dev->priv; - 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); - - /* invalidate d-cache */ - dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE); - - /* pass the packet up to the protocol layers. */ - net_process_received_packet((void *)curr_des->rxdes2, 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, void *packet, int length) -{ - struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; - struct ftgmac100_data *priv = dev->priv; - struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index]; - - 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; - - memcpy((void *)curr_des->txdes2, (void *)packet, length); - dma_map_single((void *)curr_des->txdes2, length, DMA_TO_DEVICE); - - /* only one descriptor on TXBUF */ - curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR; - curr_des->txdes0 |= FTGMAC100_TXDES0_FTS | - FTGMAC100_TXDES0_LTS | - FTGMAC100_TXDES0_TXBUF_SIZE(length) | - FTGMAC100_TXDES0_TXDMA_OWN ; - - /* start transmit */ - writel(1, &ftgmac100->txpd); - - 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)); - - 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; - - eth_register(dev); - - ftgmac100_reset(dev); - - return 1; - -free_dev: - free(dev); -out: - return 0; -} diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 48a2878071d1..4ca4e15bdd71 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -26,7 +26,6 @@ obj-$(CONFIG_EP93XX) += ep93xx_eth.o obj-$(CONFIG_ETHOC) += ethoc.o obj-$(CONFIG_FEC_MXC) += fec_mxc.o obj-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o -obj-$(CONFIG_FTGMAC100) += ftgmac100.o obj-$(CONFIG_FTMAC110) += ftmac110.o obj-$(CONFIG_FTMAC100) += ftmac100.o obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o

The driver is based on the previous one and adds the same support for the Faraday ftgmac100 controller with MAC and MDIO bus support for RGMII/RMII modes.
Driver model support was added as well as some enhancements and fixes.
Signed-off-by: Cédric Le Goater clg@kaod.org --- drivers/net/ftgmac100.h | 242 ++++++++++++++++++++ drivers/net/ftgmac100.c | 493 ++++++++++++++++++++++++++++++++++++++++ drivers/net/Kconfig | 8 + drivers/net/Makefile | 1 + 4 files changed, 744 insertions(+) create mode 100644 drivers/net/ftgmac100.h create mode 100644 drivers/net/ftgmac100.c
diff --git a/drivers/net/ftgmac100.h b/drivers/net/ftgmac100.h new file mode 100644 index 000000000000..9a789e4d5bee --- /dev/null +++ b/drivers/net/ftgmac100.h @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * 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 + */ + +#ifndef __FTGMAC100_H +#define __FTGMAC100_H + +/* The registers offset table of ftgmac100 */ +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 BIT(0) +#define FTGMAC100_INT_RPKT_FIFO BIT(1) +#define FTGMAC100_INT_NO_RXBUF BIT(2) +#define FTGMAC100_INT_RPKT_LOST BIT(3) +#define FTGMAC100_INT_XPKT_ETH BIT(4) +#define FTGMAC100_INT_XPKT_FIFO BIT(5) +#define FTGMAC100_INT_NO_NPTXBUF BIT(6) +#define FTGMAC100_INT_XPKT_LOST BIT(7) +#define FTGMAC100_INT_AHB_ERR BIT(8) +#define FTGMAC100_INT_PHYSTS_CHG BIT(9) +#define FTGMAC100_INT_NO_HPTXBUF BIT(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 BIT(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 BIT(15) + +/* + * Automatic polling timer control register + */ +#define FTGMAC100_APTC_RXPOLL_CNT(x) (((x) & 0xf) << 0) +#define FTGMAC100_APTC_RXPOLL_TIME_SEL BIT(4) +#define FTGMAC100_APTC_TXPOLL_CNT(x) (((x) & 0xf) << 8) +#define FTGMAC100_APTC_TXPOLL_TIME_SEL BIT(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 BIT(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 BIT(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 BIT(26) +#define FTGMAC100_DMAFIFOS_TXFIFO_EMPTY BIT(27) +#define FTGMAC100_DMAFIFOS_RXDMA_GRANT BIT(28) +#define FTGMAC100_DMAFIFOS_TXDMA_GRANT BIT(29) +#define FTGMAC100_DMAFIFOS_RXDMA_REQ BIT(30) +#define FTGMAC100_DMAFIFOS_TXDMA_REQ BIT(31) + +/* + * Receive buffer size register + */ +#define FTGMAC100_RBSR_SIZE(x) ((x) & 0x3fff) + +/* + * MAC control register + */ +#define FTGMAC100_MACCR_TXDMA_EN BIT(0) +#define FTGMAC100_MACCR_RXDMA_EN BIT(1) +#define FTGMAC100_MACCR_TXMAC_EN BIT(2) +#define FTGMAC100_MACCR_RXMAC_EN BIT(3) +#define FTGMAC100_MACCR_RM_VLAN BIT(4) +#define FTGMAC100_MACCR_HPTXR_EN BIT(5) +#define FTGMAC100_MACCR_LOOP_EN BIT(6) +#define FTGMAC100_MACCR_ENRX_IN_HALFTX BIT(7) +#define FTGMAC100_MACCR_FULLDUP BIT(8) +#define FTGMAC100_MACCR_GIGA_MODE BIT(9) +#define FTGMAC100_MACCR_CRC_APD BIT(10) +#define FTGMAC100_MACCR_RX_RUNT BIT(12) +#define FTGMAC100_MACCR_JUMBO_LF BIT(13) +#define FTGMAC100_MACCR_RX_ALL BIT(14) +#define FTGMAC100_MACCR_HT_MULTI_EN BIT(15) +#define FTGMAC100_MACCR_RX_MULTIPKT BIT(16) +#define FTGMAC100_MACCR_RX_BROADPKT BIT(17) +#define FTGMAC100_MACCR_DISCARD_CRCERR BIT(18) +#define FTGMAC100_MACCR_FAST_MODE BIT(19) +#define FTGMAC100_MACCR_SW_RST BIT(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 BIT(26) +#define FTGMAC100_PHYCR_MIIWR BIT(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 */ +} __aligned(16); + +#define FTGMAC100_TXDES0_TXBUF_SIZE(x) ((x) & 0x3fff) +#define FTGMAC100_TXDES0_EDOTR BIT(15) +#define FTGMAC100_TXDES0_CRC_ERR BIT(19) +#define FTGMAC100_TXDES0_LTS BIT(28) +#define FTGMAC100_TXDES0_FTS BIT(29) +#define FTGMAC100_TXDES0_TXDMA_OWN BIT(31) + +#define FTGMAC100_TXDES1_VLANTAG_CI(x) ((x) & 0xffff) +#define FTGMAC100_TXDES1_INS_VLANTAG BIT(16) +#define FTGMAC100_TXDES1_TCP_CHKSUM BIT(17) +#define FTGMAC100_TXDES1_UDP_CHKSUM BIT(18) +#define FTGMAC100_TXDES1_IP_CHKSUM BIT(19) +#define FTGMAC100_TXDES1_LLC BIT(22) +#define FTGMAC100_TXDES1_TX2FIC BIT(30) +#define FTGMAC100_TXDES1_TXIC BIT(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 */ +} __aligned(16); + +#define FTGMAC100_RXDES0_VDBC(x) ((x) & 0x3fff) +#define FTGMAC100_RXDES0_EDORR BIT(15) +#define FTGMAC100_RXDES0_MULTICAST BIT(16) +#define FTGMAC100_RXDES0_BROADCAST BIT(17) +#define FTGMAC100_RXDES0_RX_ERR BIT(18) +#define FTGMAC100_RXDES0_CRC_ERR BIT(19) +#define FTGMAC100_RXDES0_FTL BIT(20) +#define FTGMAC100_RXDES0_RUNT BIT(21) +#define FTGMAC100_RXDES0_RX_ODD_NB BIT(22) +#define FTGMAC100_RXDES0_FIFO_FULL BIT(23) +#define FTGMAC100_RXDES0_PAUSE_OPCODE BIT(24) +#define FTGMAC100_RXDES0_PAUSE_FRAME BIT(25) +#define FTGMAC100_RXDES0_LRS BIT(28) +#define FTGMAC100_RXDES0_FRS BIT(29) +#define FTGMAC100_RXDES0_RXPKT_RDY BIT(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 BIT(22) +#define FTGMAC100_RXDES1_DF BIT(23) +#define FTGMAC100_RXDES1_VLANTAG_AVAIL BIT(24) +#define FTGMAC100_RXDES1_TCP_CHKSUM_ERR BIT(25) +#define FTGMAC100_RXDES1_UDP_CHKSUM_ERR BIT(26) +#define FTGMAC100_RXDES1_IP_CHKSUM_ERR BIT(27) + +#endif /* __FTGMAC100_H */ diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c new file mode 100644 index 000000000000..8d7bf5b9b351 --- /dev/null +++ b/drivers/net/ftgmac100.c @@ -0,0 +1,493 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * 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 + * + * Copyright (C) 2018, IBM Corporation. + */ + +#include <clk.h> +#include <miiphy.h> +#include <net.h> +#include <asm/io.h> + +#include "ftgmac100.h" + +#define ETH_ZLEN 60 +#define CFG_XBUF_SIZE 1536 + +/* RBSR - hw default init value is also 0x640 */ +#define RBSR_DEFAULT_VALUE 0x640 + +/* PKTBUFSTX/PKTBUFSRX must both be power of 2 */ +#define PKTBUFSTX 4 + +struct ftgmac100_data { + phys_addr_t iobase; + + struct ftgmac100_txdes txdes[PKTBUFSTX]; + struct ftgmac100_rxdes rxdes[PKTBUFSRX]; + int tx_index; + int rx_index; + + u32 phyaddr; + struct phy_device *phydev; + struct mii_dev *bus; + u32 phy_mode; + u32 max_speed; +}; + +/* + * MDC clock cycle threshold + * + * 20us * 100 = 2ms > (1 / 2.5Mhz) * 0x34 + */ +#define MDC_CYCTHR 0x34 + +static int ftgmac100_mdio_read(struct mii_dev *bus, int phy_addr, int dev_addr, + int reg_addr) +{ + struct ftgmac100_data *priv = bus->priv; + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase; + int phycr; + int i; + + phycr = MDC_CYCTHR | + FTGMAC100_PHYCR_PHYAD(phy_addr) | + FTGMAC100_PHYCR_REGAD(reg_addr) | + 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); + } + + pr_err("mdio read timed out\n"); + return -1; +} + +static int ftgmac100_mdio_write(struct mii_dev *bus, int phy_addr, int dev_addr, + int reg_addr, u16 value) +{ + struct ftgmac100_data *priv = bus->priv; + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase; + int phycr; + int data; + int i; + + phycr = MDC_CYCTHR | + FTGMAC100_PHYCR_PHYAD(phy_addr) | + FTGMAC100_PHYCR_REGAD(reg_addr) | + 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) + return 0; + + mdelay(1); + } + + pr_err("mdio write timed out\n"); + return -1; +} + +static int ftgmac100_mdio_init(struct ftgmac100_data *priv, int dev_id) +{ + struct mii_dev *bus; + int ret; + + bus = mdio_alloc(); + if (!bus) + return -ENOMEM; + + bus->read = ftgmac100_mdio_read; + bus->write = ftgmac100_mdio_write; + bus->priv = priv; + + ret = mdio_register_seq(bus, dev_id); + if (ret) { + free(bus); + return ret; + } + + priv->bus = bus; + return 0; +} + +static int ftgmac100_phy_adjust_link(struct ftgmac100_data *priv) +{ + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase; + struct phy_device *phydev = priv->phydev; + u32 maccr; + + if (!phydev->link) { + dev_err(phydev->dev, "No link\n"); + return -ENODEV; + } + + /* read MAC control register and clear related bits */ + maccr = readl(&ftgmac100->maccr) & + ~(FTGMAC100_MACCR_GIGA_MODE | + FTGMAC100_MACCR_FAST_MODE | + FTGMAC100_MACCR_FULLDUP); + + if (phy_interface_is_rgmii(phydev) && phydev->speed == 1000) + maccr |= FTGMAC100_MACCR_GIGA_MODE; + + if (phydev->speed == 100) + maccr |= FTGMAC100_MACCR_FAST_MODE; + + if (phydev->duplex) + maccr |= FTGMAC100_MACCR_FULLDUP; + + /* update MII config into maccr */ + writel(maccr, &ftgmac100->maccr); + + return 0; +} + +static int ftgmac100_phy_init(struct ftgmac100_data *priv, void *dev) +{ + struct phy_device *phydev; + int ret; + + phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->phy_mode); + + phydev->supported &= PHY_GBIT_FEATURES; + if (priv->max_speed) { + ret = phy_set_supported(phydev, priv->max_speed); + if (ret) + return ret; + } + phydev->advertising = phydev->supported; + priv->phydev = phydev; + phy_config(phydev); + + return 0; +} + +static void ftgmac100_reset(struct ftgmac100_data *priv) +{ + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase; + + setbits_le32(&ftgmac100->maccr, FTGMAC100_MACCR_SW_RST); + + while (readl(&ftgmac100->maccr) & FTGMAC100_MACCR_SW_RST) + ; +} + +static int ftgmac100_set_mac(struct ftgmac100_data *priv, + const unsigned char *mac) +{ + struct ftgmac100 *ftgmac100 = (struct 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]; + + writel(maddr, &ftgmac100->mac_madr); + writel(laddr, &ftgmac100->mac_ladr); + return 0; +} + +static void ftgmac100_stop(struct udevice *dev) +{ + struct ftgmac100_data *priv = dev_get_priv(dev); + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase; + + writel(0, &ftgmac100->maccr); + + phy_shutdown(priv->phydev); +} + +static int ftgmac100_start(struct udevice *dev) +{ + struct eth_pdata *plat = dev_get_platdata(dev); + struct ftgmac100_data *priv = dev_get_priv(dev); + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase; + struct phy_device *phydev = priv->phydev; + unsigned int maccr; + int ret; + int i; + + ftgmac100_reset(priv); + + /* set the ethernet address */ + ftgmac100_set_mac(priv, plat->enetaddr); + + /* disable all interrupts */ + writel(0, &ftgmac100->ier); + + /* initialize descriptor tables */ + priv->tx_index = 0; + priv->rx_index = 0; + + for (i = 0; i < PKTBUFSTX; i++) { + priv->txdes[i].txdes3 = 0; + priv->txdes[i].txdes0 = 0; + } + priv->txdes[PKTBUFSTX - 1].txdes0 = FTGMAC100_TXDES0_EDOTR; + + for (i = 0; i < PKTBUFSRX; i++) { + priv->rxdes[i].rxdes3 = (unsigned int)net_rx_packets[i]; + priv->rxdes[i].rxdes0 = 0; + } + priv->rxdes[PKTBUFSRX - 1].rxdes0 = FTGMAC100_RXDES0_EDORR; + + /* transmit ring */ + writel((u32)priv->txdes, &ftgmac100->txr_badr); + + /* receive ring */ + writel((u32)priv->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); + + ret = phy_startup(phydev); + if (ret) { + dev_err(phydev->dev, "Could not start PHY\n"); + return ret; + } + + ret = ftgmac100_phy_adjust_link(priv); + if (ret) { + dev_err(phydev->dev, "Could not adjust link\n"); + return ret; + } + + printf("%s: link up, %d Mbps %s-duplex mac:%pM\n", phydev->dev->name, + phydev->speed, phydev->duplex ? "full" : "half", plat->enetaddr); + + 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]; + ulong des_start = (ulong)curr_des; + ulong des_end = des_start + + roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN); + + /* Release buffer to DMA and flush descriptor */ + curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY; + flush_dcache_range(des_start, des_end); + + /* Move to next descriptor */ + priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX; + return 0; +} + +static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct ftgmac100_data *priv = dev_get_priv(dev); + struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index]; + int length; + ulong des_start = (ulong)curr_des; + ulong des_end = des_start + + roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN); + ulong data_start = curr_des->rxdes3; + ulong data_end; + + invalidate_dcache_range(des_start, des_end); + + if (!(curr_des->rxdes0 & FTGMAC100_RXDES0_RXPKT_RDY)) + return -EAGAIN; + + if (curr_des->rxdes0 & (FTGMAC100_RXDES0_RX_ERR | + FTGMAC100_RXDES0_CRC_ERR | + FTGMAC100_RXDES0_FTL | + FTGMAC100_RXDES0_RUNT | + FTGMAC100_RXDES0_RX_ODD_NB)) { + return -EAGAIN; + } + + length = FTGMAC100_RXDES0_VDBC(curr_des->rxdes0); + + /* Invalidate received data */ + data_end = data_start + roundup(length, ARCH_DMA_MINALIGN); + invalidate_dcache_range(data_start, data_end); + *packetp = (uchar *)data_start; + + return length; +} + +static int ftgmac100_send(struct udevice *dev, void *packet, int length) +{ + struct ftgmac100_data *priv = dev_get_priv(dev); + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase; + struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index]; + ulong des_start = (ulong)curr_des; + ulong des_end = des_start + + roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN); + ulong data_start; + ulong data_end; + + invalidate_dcache_range(des_start, des_end); + + if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) { + pr_err("no TX descriptor available\n"); + return -EPERM; + } + + 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; + + /* Flush data to be sent */ + data_start = curr_des->txdes3; + data_end = data_start + roundup(length, ARCH_DMA_MINALIGN); + flush_dcache_range(data_start, data_end); + + /* only one descriptor on TXBUF */ + curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR; + curr_des->txdes0 |= FTGMAC100_TXDES0_FTS | + FTGMAC100_TXDES0_LTS | + FTGMAC100_TXDES0_TXBUF_SIZE(length) | + FTGMAC100_TXDES0_TXDMA_OWN; + + /* Flush modified buffer descriptor */ + flush_dcache_range(des_start, des_end); + + debug("%s(): packet sent\n", __func__); + + priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX; + + /* start transmit */ + writel(1, &ftgmac100->txpd); + + /* TODO: check TXDMA_OWN bit for xmit timeouts */ + + return 0; +} + +static int ftgmac100_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct ftgmac100_data *priv = dev_get_priv(dev); + + return ftgmac100_set_mac(priv, pdata->enetaddr); +} + +static int ftgmac100_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + const char *phy_mode; + + pdata->iobase = devfdt_get_addr(dev); + pdata->phy_interface = -1; + phy_mode = dev_read_string(dev, "phy-mode"); + if (phy_mode) + pdata->phy_interface = phy_get_interface_by_name(phy_mode); + if (pdata->phy_interface == -1) { + dev_err(dev, "Invalid PHY interface '%s'\n", phy_mode); + return -EINVAL; + } + + pdata->max_speed = dev_read_u32_default(dev, "max-speed", 0); + + return 0; +} + +static int ftgmac100_probe(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct ftgmac100_data *priv = dev_get_priv(dev); + int ret; + + priv->iobase = pdata->iobase; + priv->phy_mode = pdata->phy_interface; + priv->max_speed = pdata->max_speed; + priv->phyaddr = 0; + + ret = ftgmac100_mdio_init(priv, dev->seq); + if (ret) { + dev_err(dev, "Failed to initialize mdiobus: %d\n", ret); + goto out; + } + + ret = ftgmac100_phy_init(priv, dev); + if (ret) { + dev_err(dev, "Failed to initialize PHY: %d\n", ret); + goto out; + } + +out: + return ret; +} + +static int ftgmac100_remove(struct udevice *dev) +{ + struct ftgmac100_data *priv = dev_get_priv(dev); + + free(priv->phydev); + mdio_unregister(priv->bus); + mdio_free(priv->bus); + + 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/drivers/net/Kconfig b/drivers/net/Kconfig index 5441da47d13e..65edb0316e6f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -186,6 +186,14 @@ 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. + config MVGBE bool "Marvell Orion5x/Kirkwood network interface support" depends on KIRKWOOD || ORION5X diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4ca4e15bdd71..48a2878071d1 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_EP93XX) += ep93xx_eth.o obj-$(CONFIG_ETHOC) += ethoc.o obj-$(CONFIG_FEC_MXC) += fec_mxc.o obj-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o +obj-$(CONFIG_FTGMAC100) += ftgmac100.o obj-$(CONFIG_FTMAC110) += ftmac110.o obj-$(CONFIG_FTMAC100) += ftmac100.o obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o

On Mon, 10 Sep 2018 at 23:54, Cédric Le Goater clg@kaod.org wrote:
The driver is based on the previous one and adds the same support for the Faraday ftgmac100 controller with MAC and MDIO bus support for RGMII/RMII modes.
Driver model support was added as well as some enhancements and fixes.
Signed-off-by: Cédric Le Goater clg@kaod.org
There are some discrepancies between the datasheet I have and the register layout. The rest of the driver looks good.
+++ b/drivers/net/ftgmac100.h
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 */
The datasheet calls MAC3C DBG_STS: Debug status register. Actually, the next few are different too:
0x3c: dbg_sts 0x40: fear 0x44: undocumented
unsigned int revr; /* 0x40 */
unsigned int fear; /* 0x44 */
From here on it looks good again:
unsigned int tpafcr; /* 0x48 */
unsigned int rbsr; /* 0x4c */
unsigned int maccr; /* 0x50 */
unsigned int macsr; /* 0x54 */
unsigned int tm; /* 0x58 */
but here it goes wrong again:
0x58: undocumented
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 */
And from here it gets confusing agian. The definitions you have appear to match the Linux driver.
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 */
+static int ftgmac100_start(struct udevice *dev) +{
/* 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;
Just reviewing for differences between this and the kernel driver; the kernel driver sets PHY_LINK_LEVEL. Is there a reason u-boot doesn't?
writel(maccr, &ftgmac100->maccr);
ret = phy_startup(phydev);
if (ret) {
dev_err(phydev->dev, "Could not start PHY\n");
return ret;
}
ret = ftgmac100_phy_adjust_link(priv);
if (ret) {
dev_err(phydev->dev, "Could not adjust link\n");
return ret;
}
printf("%s: link up, %d Mbps %s-duplex mac:%pM\n", phydev->dev->name,
phydev->speed, phydev->duplex ? "full" : "half", plat->enetaddr);
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];
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
/* Release buffer to DMA and flush descriptor */
curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
flush_dcache_range(des_start, des_end);
/* Move to next descriptor */
priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX;
return 0;
+}
+static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index];
int length;
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
ulong data_start = curr_des->rxdes3;
ulong data_end;
invalidate_dcache_range(des_start, des_end);
if (!(curr_des->rxdes0 & FTGMAC100_RXDES0_RXPKT_RDY))
return -EAGAIN;
if (curr_des->rxdes0 & (FTGMAC100_RXDES0_RX_ERR |
FTGMAC100_RXDES0_CRC_ERR |
FTGMAC100_RXDES0_FTL |
FTGMAC100_RXDES0_RUNT |
FTGMAC100_RXDES0_RX_ODD_NB)) {
return -EAGAIN;
}
length = FTGMAC100_RXDES0_VDBC(curr_des->rxdes0);
/* Invalidate received data */
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
invalidate_dcache_range(data_start, data_end);
*packetp = (uchar *)data_start;
return length;
+}
+static int ftgmac100_send(struct udevice *dev, void *packet, int length) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
ulong data_start;
ulong data_end;
invalidate_dcache_range(des_start, des_end);
if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
pr_err("no TX descriptor available\n");
return -EPERM;
}
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;
/* Flush data to be sent */
data_start = curr_des->txdes3;
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
flush_dcache_range(data_start, data_end);
/* only one descriptor on TXBUF */
curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
curr_des->txdes0 |= FTGMAC100_TXDES0_FTS |
FTGMAC100_TXDES0_LTS |
FTGMAC100_TXDES0_TXBUF_SIZE(length) |
FTGMAC100_TXDES0_TXDMA_OWN;
/* Flush modified buffer descriptor */
flush_dcache_range(des_start, des_end);
debug("%s(): packet sent\n", __func__);
priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
/* start transmit */
writel(1, &ftgmac100->txpd);
/* TODO: check TXDMA_OWN bit for xmit timeouts */
return 0;
+}
+static int ftgmac100_write_hwaddr(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
return ftgmac100_set_mac(priv, pdata->enetaddr);
+}
+static int ftgmac100_ofdata_to_platdata(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
const char *phy_mode;
pdata->iobase = devfdt_get_addr(dev);
pdata->phy_interface = -1;
phy_mode = dev_read_string(dev, "phy-mode");
if (phy_mode)
pdata->phy_interface = phy_get_interface_by_name(phy_mode);
if (pdata->phy_interface == -1) {
dev_err(dev, "Invalid PHY interface '%s'\n", phy_mode);
return -EINVAL;
}
pdata->max_speed = dev_read_u32_default(dev, "max-speed", 0);
return 0;
+}
+static int ftgmac100_probe(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
int ret;
priv->iobase = pdata->iobase;
priv->phy_mode = pdata->phy_interface;
priv->max_speed = pdata->max_speed;
priv->phyaddr = 0;
ret = ftgmac100_mdio_init(priv, dev->seq);
if (ret) {
dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
goto out;
}
ret = ftgmac100_phy_init(priv, dev);
if (ret) {
dev_err(dev, "Failed to initialize PHY: %d\n", ret);
goto out;
}
+out:
return ret;
+}
+static int ftgmac100_remove(struct udevice *dev) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
free(priv->phydev);
mdio_unregister(priv->bus);
mdio_free(priv->bus);
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/drivers/net/Kconfig b/drivers/net/Kconfig index 5441da47d13e..65edb0316e6f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -186,6 +186,14 @@ 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.
config MVGBE bool "Marvell Orion5x/Kirkwood network interface support" depends on KIRKWOOD || ORION5X diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4ca4e15bdd71..48a2878071d1 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_EP93XX) += ep93xx_eth.o obj-$(CONFIG_ETHOC) += ethoc.o obj-$(CONFIG_FEC_MXC) += fec_mxc.o obj-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o +obj-$(CONFIG_FTGMAC100) += ftgmac100.o obj-$(CONFIG_FTMAC110) += ftmac110.o obj-$(CONFIG_FTMAC100) += ftmac100.o obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o -- 2.17.1
U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot

On 09/12/2018 11:27 AM, Joel Stanley wrote:
On Mon, 10 Sep 2018 at 23:54, Cédric Le Goater clg@kaod.org wrote:
The driver is based on the previous one and adds the same support for the Faraday ftgmac100 controller with MAC and MDIO bus support for RGMII/RMII modes.
Driver model support was added as well as some enhancements and fixes.
Signed-off-by: Cédric Le Goater clg@kaod.org
There are some discrepancies between the datasheet I have and the register layout. The rest of the driver looks good.
I kept the original register layout which came with an Andes Technology SoCs (I think) as it is compatible with the Aspeed layout. The feature reg name differs indeed but for the rest we are fine.
unless we want to fully drop old layout and directly use the one we have in Aspeed SoC ?
+++ b/drivers/net/ftgmac100.h
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 */
The datasheet calls MAC3C DBG_STS: Debug status register. Actually, the next few are different too:
0x3c: dbg_sts 0x40: fear 0x44: undocumented
unsigned int revr; /* 0x40 */
unsigned int fear; /* 0x44 */
From here on it looks good again:
unsigned int tpafcr; /* 0x48 */
unsigned int rbsr; /* 0x4c */
unsigned int maccr; /* 0x50 */
unsigned int macsr; /* 0x54 */
unsigned int tm; /* 0x58 */
but here it goes wrong again:
0x58: undocumented
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 */
And from here it gets confusing agian. The definitions you have appear to match the Linux driver.
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 */
+static int ftgmac100_start(struct udevice *dev) +{
/* 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;
Just reviewing for differences between this and the kernel driver; the kernel driver sets PHY_LINK_LEVEL. Is there a reason u-boot doesn't?
u-boot doesn't, nor does Linux on the EVB.
Maybe it is related to NCSI ? I will ask around.
Thanks,
C.
writel(maccr, &ftgmac100->maccr);
ret = phy_startup(phydev);
if (ret) {
dev_err(phydev->dev, "Could not start PHY\n");
return ret;
}
ret = ftgmac100_phy_adjust_link(priv);
if (ret) {
dev_err(phydev->dev, "Could not adjust link\n");
return ret;
}
printf("%s: link up, %d Mbps %s-duplex mac:%pM\n", phydev->dev->name,
phydev->speed, phydev->duplex ? "full" : "half", plat->enetaddr);
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];
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
/* Release buffer to DMA and flush descriptor */
curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
flush_dcache_range(des_start, des_end);
/* Move to next descriptor */
priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX;
return 0;
+}
+static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index];
int length;
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
ulong data_start = curr_des->rxdes3;
ulong data_end;
invalidate_dcache_range(des_start, des_end);
if (!(curr_des->rxdes0 & FTGMAC100_RXDES0_RXPKT_RDY))
return -EAGAIN;
if (curr_des->rxdes0 & (FTGMAC100_RXDES0_RX_ERR |
FTGMAC100_RXDES0_CRC_ERR |
FTGMAC100_RXDES0_FTL |
FTGMAC100_RXDES0_RUNT |
FTGMAC100_RXDES0_RX_ODD_NB)) {
return -EAGAIN;
}
length = FTGMAC100_RXDES0_VDBC(curr_des->rxdes0);
/* Invalidate received data */
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
invalidate_dcache_range(data_start, data_end);
*packetp = (uchar *)data_start;
return length;
+}
+static int ftgmac100_send(struct udevice *dev, void *packet, int length) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
ulong data_start;
ulong data_end;
invalidate_dcache_range(des_start, des_end);
if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
pr_err("no TX descriptor available\n");
return -EPERM;
}
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;
/* Flush data to be sent */
data_start = curr_des->txdes3;
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
flush_dcache_range(data_start, data_end);
/* only one descriptor on TXBUF */
curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
curr_des->txdes0 |= FTGMAC100_TXDES0_FTS |
FTGMAC100_TXDES0_LTS |
FTGMAC100_TXDES0_TXBUF_SIZE(length) |
FTGMAC100_TXDES0_TXDMA_OWN;
/* Flush modified buffer descriptor */
flush_dcache_range(des_start, des_end);
debug("%s(): packet sent\n", __func__);
priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
/* start transmit */
writel(1, &ftgmac100->txpd);
/* TODO: check TXDMA_OWN bit for xmit timeouts */
return 0;
+}
+static int ftgmac100_write_hwaddr(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
return ftgmac100_set_mac(priv, pdata->enetaddr);
+}
+static int ftgmac100_ofdata_to_platdata(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
const char *phy_mode;
pdata->iobase = devfdt_get_addr(dev);
pdata->phy_interface = -1;
phy_mode = dev_read_string(dev, "phy-mode");
if (phy_mode)
pdata->phy_interface = phy_get_interface_by_name(phy_mode);
if (pdata->phy_interface == -1) {
dev_err(dev, "Invalid PHY interface '%s'\n", phy_mode);
return -EINVAL;
}
pdata->max_speed = dev_read_u32_default(dev, "max-speed", 0);
return 0;
+}
+static int ftgmac100_probe(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
int ret;
priv->iobase = pdata->iobase;
priv->phy_mode = pdata->phy_interface;
priv->max_speed = pdata->max_speed;
priv->phyaddr = 0;
ret = ftgmac100_mdio_init(priv, dev->seq);
if (ret) {
dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
goto out;
}
ret = ftgmac100_phy_init(priv, dev);
if (ret) {
dev_err(dev, "Failed to initialize PHY: %d\n", ret);
goto out;
}
+out:
return ret;
+}
+static int ftgmac100_remove(struct udevice *dev) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
free(priv->phydev);
mdio_unregister(priv->bus);
mdio_free(priv->bus);
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/drivers/net/Kconfig b/drivers/net/Kconfig index 5441da47d13e..65edb0316e6f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -186,6 +186,14 @@ 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.
config MVGBE bool "Marvell Orion5x/Kirkwood network interface support" depends on KIRKWOOD || ORION5X diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4ca4e15bdd71..48a2878071d1 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_EP93XX) += ep93xx_eth.o obj-$(CONFIG_ETHOC) += ethoc.o obj-$(CONFIG_FEC_MXC) += fec_mxc.o obj-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o +obj-$(CONFIG_FTGMAC100) += ftgmac100.o obj-$(CONFIG_FTMAC110) += ftmac110.o obj-$(CONFIG_FTMAC100) += ftmac100.o obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o -- 2.17.1
U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot

Hi Cedric,
On 10 September 2018 at 07:21, Cédric Le Goater clg@kaod.org wrote:
The driver is based on the previous one and adds the same support for the Faraday ftgmac100 controller with MAC and MDIO bus support for RGMII/RMII modes.
Driver model support was added as well as some enhancements and fixes.
Signed-off-by: Cédric Le Goater clg@kaod.org
drivers/net/ftgmac100.h | 242 ++++++++++++++++++++ drivers/net/ftgmac100.c | 493 ++++++++++++++++++++++++++++++++++++++++ drivers/net/Kconfig | 8 + drivers/net/Makefile | 1 + 4 files changed, 744 insertions(+) create mode 100644 drivers/net/ftgmac100.h create mode 100644 drivers/net/ftgmac100.c
Reviewed-by: Simon Glass sjg@chromium.org
Various minor comments below.
diff --git a/drivers/net/ftgmac100.h b/drivers/net/ftgmac100.h new file mode 100644 index 000000000000..9a789e4d5bee --- /dev/null +++ b/drivers/net/ftgmac100.h @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- 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
- */
+#ifndef __FTGMAC100_H +#define __FTGMAC100_H
+/* The registers offset table of ftgmac100 */ +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 BIT(0) +#define FTGMAC100_INT_RPKT_FIFO BIT(1) +#define FTGMAC100_INT_NO_RXBUF BIT(2) +#define FTGMAC100_INT_RPKT_LOST BIT(3) +#define FTGMAC100_INT_XPKT_ETH BIT(4) +#define FTGMAC100_INT_XPKT_FIFO BIT(5) +#define FTGMAC100_INT_NO_NPTXBUF BIT(6) +#define FTGMAC100_INT_XPKT_LOST BIT(7) +#define FTGMAC100_INT_AHB_ERR BIT(8) +#define FTGMAC100_INT_PHYSTS_CHG BIT(9) +#define FTGMAC100_INT_NO_HPTXBUF BIT(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 BIT(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 BIT(15)
+/*
- Automatic polling timer control register
- */
+#define FTGMAC100_APTC_RXPOLL_CNT(x) (((x) & 0xf) << 0) +#define FTGMAC100_APTC_RXPOLL_TIME_SEL BIT(4) +#define FTGMAC100_APTC_TXPOLL_CNT(x) (((x) & 0xf) << 8) +#define FTGMAC100_APTC_TXPOLL_TIME_SEL BIT(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 BIT(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 BIT(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 BIT(26) +#define FTGMAC100_DMAFIFOS_TXFIFO_EMPTY BIT(27) +#define FTGMAC100_DMAFIFOS_RXDMA_GRANT BIT(28) +#define FTGMAC100_DMAFIFOS_TXDMA_GRANT BIT(29) +#define FTGMAC100_DMAFIFOS_RXDMA_REQ BIT(30) +#define FTGMAC100_DMAFIFOS_TXDMA_REQ BIT(31)
+/*
- Receive buffer size register
- */
+#define FTGMAC100_RBSR_SIZE(x) ((x) & 0x3fff)
+/*
- MAC control register
- */
+#define FTGMAC100_MACCR_TXDMA_EN BIT(0) +#define FTGMAC100_MACCR_RXDMA_EN BIT(1) +#define FTGMAC100_MACCR_TXMAC_EN BIT(2) +#define FTGMAC100_MACCR_RXMAC_EN BIT(3) +#define FTGMAC100_MACCR_RM_VLAN BIT(4) +#define FTGMAC100_MACCR_HPTXR_EN BIT(5) +#define FTGMAC100_MACCR_LOOP_EN BIT(6) +#define FTGMAC100_MACCR_ENRX_IN_HALFTX BIT(7) +#define FTGMAC100_MACCR_FULLDUP BIT(8) +#define FTGMAC100_MACCR_GIGA_MODE BIT(9) +#define FTGMAC100_MACCR_CRC_APD BIT(10) +#define FTGMAC100_MACCR_RX_RUNT BIT(12) +#define FTGMAC100_MACCR_JUMBO_LF BIT(13) +#define FTGMAC100_MACCR_RX_ALL BIT(14) +#define FTGMAC100_MACCR_HT_MULTI_EN BIT(15) +#define FTGMAC100_MACCR_RX_MULTIPKT BIT(16) +#define FTGMAC100_MACCR_RX_BROADPKT BIT(17) +#define FTGMAC100_MACCR_DISCARD_CRCERR BIT(18) +#define FTGMAC100_MACCR_FAST_MODE BIT(19) +#define FTGMAC100_MACCR_SW_RST BIT(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 BIT(26) +#define FTGMAC100_PHYCR_MIIWR BIT(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 */
+} __aligned(16);
+#define FTGMAC100_TXDES0_TXBUF_SIZE(x) ((x) & 0x3fff) +#define FTGMAC100_TXDES0_EDOTR BIT(15) +#define FTGMAC100_TXDES0_CRC_ERR BIT(19) +#define FTGMAC100_TXDES0_LTS BIT(28) +#define FTGMAC100_TXDES0_FTS BIT(29) +#define FTGMAC100_TXDES0_TXDMA_OWN BIT(31)
+#define FTGMAC100_TXDES1_VLANTAG_CI(x) ((x) & 0xffff) +#define FTGMAC100_TXDES1_INS_VLANTAG BIT(16) +#define FTGMAC100_TXDES1_TCP_CHKSUM BIT(17) +#define FTGMAC100_TXDES1_UDP_CHKSUM BIT(18) +#define FTGMAC100_TXDES1_IP_CHKSUM BIT(19) +#define FTGMAC100_TXDES1_LLC BIT(22) +#define FTGMAC100_TXDES1_TX2FIC BIT(30) +#define FTGMAC100_TXDES1_TXIC BIT(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 */
+} __aligned(16);
+#define FTGMAC100_RXDES0_VDBC(x) ((x) & 0x3fff) +#define FTGMAC100_RXDES0_EDORR BIT(15) +#define FTGMAC100_RXDES0_MULTICAST BIT(16) +#define FTGMAC100_RXDES0_BROADCAST BIT(17) +#define FTGMAC100_RXDES0_RX_ERR BIT(18) +#define FTGMAC100_RXDES0_CRC_ERR BIT(19) +#define FTGMAC100_RXDES0_FTL BIT(20) +#define FTGMAC100_RXDES0_RUNT BIT(21) +#define FTGMAC100_RXDES0_RX_ODD_NB BIT(22) +#define FTGMAC100_RXDES0_FIFO_FULL BIT(23) +#define FTGMAC100_RXDES0_PAUSE_OPCODE BIT(24) +#define FTGMAC100_RXDES0_PAUSE_FRAME BIT(25) +#define FTGMAC100_RXDES0_LRS BIT(28) +#define FTGMAC100_RXDES0_FRS BIT(29) +#define FTGMAC100_RXDES0_RXPKT_RDY BIT(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 BIT(22) +#define FTGMAC100_RXDES1_DF BIT(23) +#define FTGMAC100_RXDES1_VLANTAG_AVAIL BIT(24) +#define FTGMAC100_RXDES1_TCP_CHKSUM_ERR BIT(25) +#define FTGMAC100_RXDES1_UDP_CHKSUM_ERR BIT(26) +#define FTGMAC100_RXDES1_IP_CHKSUM_ERR BIT(27)
+#endif /* __FTGMAC100_H */ diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c new file mode 100644 index 000000000000..8d7bf5b9b351 --- /dev/null +++ b/drivers/net/ftgmac100.c @@ -0,0 +1,493 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- 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
- Copyright (C) 2018, IBM Corporation.
- */
+#include <clk.h> +#include <miiphy.h> +#include <net.h> +#include <asm/io.h>
+#include "ftgmac100.h"
+#define ETH_ZLEN 60 +#define CFG_XBUF_SIZE 1536
Comments on these
+/* RBSR - hw default init value is also 0x640 */ +#define RBSR_DEFAULT_VALUE 0x640
+/* PKTBUFSTX/PKTBUFSRX must both be power of 2 */ +#define PKTBUFSTX 4
+struct ftgmac100_data {
Comment here and on members
phys_addr_t iobase;
struct ftgmac100_txdes txdes[PKTBUFSTX];
struct ftgmac100_rxdes rxdes[PKTBUFSRX];
int tx_index;
int rx_index;
u32 phyaddr;
struct phy_device *phydev;
struct mii_dev *bus;
u32 phy_mode;
u32 max_speed;
+};
+/*
- MDC clock cycle threshold
- 20us * 100 = 2ms > (1 / 2.5Mhz) * 0x34
- */
+#define MDC_CYCTHR 0x34
+static int ftgmac100_mdio_read(struct mii_dev *bus, int phy_addr, int dev_addr,
int reg_addr)
+{
struct ftgmac100_data *priv = bus->priv;
dev_get_priv(bus)
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
Can you put the struct ftgmac100 * in priv and avoid the cast each time?
int phycr;
int i;
phycr = MDC_CYCTHR |
FTGMAC100_PHYCR_PHYAD(phy_addr) |
FTGMAC100_PHYCR_REGAD(reg_addr) |
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);
This is an extraordinarily long delay. Is this described in the datasheet?
}
pr_err("mdio read timed out\n");
return -1;
-ETIMEDOUT
Same below
+}
+static int ftgmac100_mdio_write(struct mii_dev *bus, int phy_addr, int dev_addr,
int reg_addr, u16 value)
+{
struct ftgmac100_data *priv = bus->priv;
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
int phycr;
int data;
int i;
phycr = MDC_CYCTHR |
FTGMAC100_PHYCR_PHYAD(phy_addr) |
FTGMAC100_PHYCR_REGAD(reg_addr) |
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)
return 0;
mdelay(1);
}
pr_err("mdio write timed out\n");
return -1;
+}
+static int ftgmac100_mdio_init(struct ftgmac100_data *priv, int dev_id) +{
struct mii_dev *bus;
int ret;
bus = mdio_alloc();
if (!bus)
return -ENOMEM;
bus->read = ftgmac100_mdio_read;
bus->write = ftgmac100_mdio_write;
bus->priv = priv;
ret = mdio_register_seq(bus, dev_id);
if (ret) {
free(bus);
return ret;
}
priv->bus = bus;
return 0;
+}
+static int ftgmac100_phy_adjust_link(struct ftgmac100_data *priv) +{
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
struct phy_device *phydev = priv->phydev;
u32 maccr;
if (!phydev->link) {
dev_err(phydev->dev, "No link\n");
return -ENODEV;
-EREMOTEIO perhaps? You cannot use -ENODEV since there is a device
}
/* read MAC control register and clear related bits */
maccr = readl(&ftgmac100->maccr) &
~(FTGMAC100_MACCR_GIGA_MODE |
FTGMAC100_MACCR_FAST_MODE |
FTGMAC100_MACCR_FULLDUP);
if (phy_interface_is_rgmii(phydev) && phydev->speed == 1000)
maccr |= FTGMAC100_MACCR_GIGA_MODE;
if (phydev->speed == 100)
maccr |= FTGMAC100_MACCR_FAST_MODE;
if (phydev->duplex)
maccr |= FTGMAC100_MACCR_FULLDUP;
/* update MII config into maccr */
writel(maccr, &ftgmac100->maccr);
return 0;
+}
+static int ftgmac100_phy_init(struct ftgmac100_data *priv, void *dev) +{
struct phy_device *phydev;
int ret;
phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->phy_mode);
phydev->supported &= PHY_GBIT_FEATURES;
if (priv->max_speed) {
ret = phy_set_supported(phydev, priv->max_speed);
if (ret)
return ret;
}
phydev->advertising = phydev->supported;
priv->phydev = phydev;
phy_config(phydev);
return 0;
+}
+static void ftgmac100_reset(struct ftgmac100_data *priv) +{
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
setbits_le32(&ftgmac100->maccr, FTGMAC100_MACCR_SW_RST);
while (readl(&ftgmac100->maccr) & FTGMAC100_MACCR_SW_RST)
;
+}
+static int ftgmac100_set_mac(struct ftgmac100_data *priv,
const unsigned char *mac)
+{
struct ftgmac100 *ftgmac100 = (struct 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];
writel(maddr, &ftgmac100->mac_madr);
writel(laddr, &ftgmac100->mac_ladr);
return 0;
+}
+static void ftgmac100_stop(struct udevice *dev) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
writel(0, &ftgmac100->maccr);
phy_shutdown(priv->phydev);
+}
+static int ftgmac100_start(struct udevice *dev) +{
struct eth_pdata *plat = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
struct phy_device *phydev = priv->phydev;
unsigned int maccr;
int ret;
int i;
ftgmac100_reset(priv);
/* set the ethernet address */
ftgmac100_set_mac(priv, plat->enetaddr);
/* disable all interrupts */
writel(0, &ftgmac100->ier);
/* initialize descriptor tables */
priv->tx_index = 0;
priv->rx_index = 0;
for (i = 0; i < PKTBUFSTX; i++) {
priv->txdes[i].txdes3 = 0;
priv->txdes[i].txdes0 = 0;
}
priv->txdes[PKTBUFSTX - 1].txdes0 = FTGMAC100_TXDES0_EDOTR;
for (i = 0; i < PKTBUFSRX; i++) {
priv->rxdes[i].rxdes3 = (unsigned int)net_rx_packets[i];
priv->rxdes[i].rxdes0 = 0;
}
priv->rxdes[PKTBUFSRX - 1].rxdes0 = FTGMAC100_RXDES0_EDORR;
/* transmit ring */
writel((u32)priv->txdes, &ftgmac100->txr_badr);
/* receive ring */
writel((u32)priv->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);
ret = phy_startup(phydev);
if (ret) {
dev_err(phydev->dev, "Could not start PHY\n");
return ret;
}
ret = ftgmac100_phy_adjust_link(priv);
if (ret) {
dev_err(phydev->dev, "Could not adjust link\n");
return ret;
}
printf("%s: link up, %d Mbps %s-duplex mac:%pM\n", phydev->dev->name,
phydev->speed, phydev->duplex ? "full" : "half", plat->enetaddr);
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];
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
/* Release buffer to DMA and flush descriptor */
curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
flush_dcache_range(des_start, des_end);
/* Move to next descriptor */
priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX;
return 0;
+}
+static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index];
int length;
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
ulong data_start = curr_des->rxdes3;
ulong data_end;
invalidate_dcache_range(des_start, des_end);
if (!(curr_des->rxdes0 & FTGMAC100_RXDES0_RXPKT_RDY))
return -EAGAIN;
if (curr_des->rxdes0 & (FTGMAC100_RXDES0_RX_ERR |
FTGMAC100_RXDES0_CRC_ERR |
FTGMAC100_RXDES0_FTL |
FTGMAC100_RXDES0_RUNT |
FTGMAC100_RXDES0_RX_ODD_NB)) {
return -EAGAIN;
}
length = FTGMAC100_RXDES0_VDBC(curr_des->rxdes0);
/* Invalidate received data */
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
invalidate_dcache_range(data_start, data_end);
*packetp = (uchar *)data_start;
return length;
+}
+static int ftgmac100_send(struct udevice *dev, void *packet, int length) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
ulong data_start;
ulong data_end;
invalidate_dcache_range(des_start, des_end);
if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
pr_err("no TX descriptor available\n");
return -EPERM;
}
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;
/* Flush data to be sent */
data_start = curr_des->txdes3;
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
flush_dcache_range(data_start, data_end);
/* only one descriptor on TXBUF */
curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
curr_des->txdes0 |= FTGMAC100_TXDES0_FTS |
FTGMAC100_TXDES0_LTS |
FTGMAC100_TXDES0_TXBUF_SIZE(length) |
FTGMAC100_TXDES0_TXDMA_OWN;
/* Flush modified buffer descriptor */
flush_dcache_range(des_start, des_end);
debug("%s(): packet sent\n", __func__);
priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
/* start transmit */
writel(1, &ftgmac100->txpd);
/* TODO: check TXDMA_OWN bit for xmit timeouts */
TODO(email)
Should this TODO actually be done now, perhaps?
return 0;
+}
+static int ftgmac100_write_hwaddr(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
return ftgmac100_set_mac(priv, pdata->enetaddr);
+}
+static int ftgmac100_ofdata_to_platdata(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
const char *phy_mode;
pdata->iobase = devfdt_get_addr(dev);
pdata->phy_interface = -1;
phy_mode = dev_read_string(dev, "phy-mode");
if (phy_mode)
pdata->phy_interface = phy_get_interface_by_name(phy_mode);
if (pdata->phy_interface == -1) {
dev_err(dev, "Invalid PHY interface '%s'\n", phy_mode);
return -EINVAL;
}
pdata->max_speed = dev_read_u32_default(dev, "max-speed", 0);
return 0;
+}
+static int ftgmac100_probe(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
int ret;
priv->iobase = pdata->iobase;
priv->phy_mode = pdata->phy_interface;
priv->max_speed = pdata->max_speed;
priv->phyaddr = 0;
ret = ftgmac100_mdio_init(priv, dev->seq);
if (ret) {
dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
goto out;
}
ret = ftgmac100_phy_init(priv, dev);
if (ret) {
dev_err(dev, "Failed to initialize PHY: %d\n", ret);
goto out;
}
+out:
return ret;
+}
+static int ftgmac100_remove(struct udevice *dev) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
free(priv->phydev);
mdio_unregister(priv->bus);
mdio_free(priv->bus);
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/drivers/net/Kconfig b/drivers/net/Kconfig index 5441da47d13e..65edb0316e6f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -186,6 +186,14 @@ 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.
Do you have any more details you could add here about the mac or what feature the driver supports?
config MVGBE bool "Marvell Orion5x/Kirkwood network interface support" depends on KIRKWOOD || ORION5X diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4ca4e15bdd71..48a2878071d1 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_EP93XX) += ep93xx_eth.o obj-$(CONFIG_ETHOC) += ethoc.o obj-$(CONFIG_FEC_MXC) += fec_mxc.o obj-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o +obj-$(CONFIG_FTGMAC100) += ftgmac100.o obj-$(CONFIG_FTMAC110) += ftmac110.o obj-$(CONFIG_FTMAC100) += ftmac100.o obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o -- 2.17.1
Regards, Simon

Hello Simon,
On 9/27/18 3:41 PM, Simon Glass wrote:
Hi Cedric,
On 10 September 2018 at 07:21, Cédric Le Goater clg@kaod.org wrote:
The driver is based on the previous one and adds the same support for the Faraday ftgmac100 controller with MAC and MDIO bus support for RGMII/RMII modes.
Driver model support was added as well as some enhancements and fixes.
Signed-off-by: Cédric Le Goater clg@kaod.org
drivers/net/ftgmac100.h | 242 ++++++++++++++++++++ drivers/net/ftgmac100.c | 493 ++++++++++++++++++++++++++++++++++++++++ drivers/net/Kconfig | 8 + drivers/net/Makefile | 1 + 4 files changed, 744 insertions(+) create mode 100644 drivers/net/ftgmac100.h create mode 100644 drivers/net/ftgmac100.c
Reviewed-by: Simon Glass sjg@chromium.org
Various minor comments below.
diff --git a/drivers/net/ftgmac100.h b/drivers/net/ftgmac100.h new file mode 100644 index 000000000000..9a789e4d5bee --- /dev/null +++ b/drivers/net/ftgmac100.h @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- 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
- */
+#ifndef __FTGMAC100_H +#define __FTGMAC100_H
+/* The registers offset table of ftgmac100 */ +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 BIT(0) +#define FTGMAC100_INT_RPKT_FIFO BIT(1) +#define FTGMAC100_INT_NO_RXBUF BIT(2) +#define FTGMAC100_INT_RPKT_LOST BIT(3) +#define FTGMAC100_INT_XPKT_ETH BIT(4) +#define FTGMAC100_INT_XPKT_FIFO BIT(5) +#define FTGMAC100_INT_NO_NPTXBUF BIT(6) +#define FTGMAC100_INT_XPKT_LOST BIT(7) +#define FTGMAC100_INT_AHB_ERR BIT(8) +#define FTGMAC100_INT_PHYSTS_CHG BIT(9) +#define FTGMAC100_INT_NO_HPTXBUF BIT(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 BIT(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 BIT(15)
+/*
- Automatic polling timer control register
- */
+#define FTGMAC100_APTC_RXPOLL_CNT(x) (((x) & 0xf) << 0) +#define FTGMAC100_APTC_RXPOLL_TIME_SEL BIT(4) +#define FTGMAC100_APTC_TXPOLL_CNT(x) (((x) & 0xf) << 8) +#define FTGMAC100_APTC_TXPOLL_TIME_SEL BIT(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 BIT(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 BIT(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 BIT(26) +#define FTGMAC100_DMAFIFOS_TXFIFO_EMPTY BIT(27) +#define FTGMAC100_DMAFIFOS_RXDMA_GRANT BIT(28) +#define FTGMAC100_DMAFIFOS_TXDMA_GRANT BIT(29) +#define FTGMAC100_DMAFIFOS_RXDMA_REQ BIT(30) +#define FTGMAC100_DMAFIFOS_TXDMA_REQ BIT(31)
+/*
- Receive buffer size register
- */
+#define FTGMAC100_RBSR_SIZE(x) ((x) & 0x3fff)
+/*
- MAC control register
- */
+#define FTGMAC100_MACCR_TXDMA_EN BIT(0) +#define FTGMAC100_MACCR_RXDMA_EN BIT(1) +#define FTGMAC100_MACCR_TXMAC_EN BIT(2) +#define FTGMAC100_MACCR_RXMAC_EN BIT(3) +#define FTGMAC100_MACCR_RM_VLAN BIT(4) +#define FTGMAC100_MACCR_HPTXR_EN BIT(5) +#define FTGMAC100_MACCR_LOOP_EN BIT(6) +#define FTGMAC100_MACCR_ENRX_IN_HALFTX BIT(7) +#define FTGMAC100_MACCR_FULLDUP BIT(8) +#define FTGMAC100_MACCR_GIGA_MODE BIT(9) +#define FTGMAC100_MACCR_CRC_APD BIT(10) +#define FTGMAC100_MACCR_RX_RUNT BIT(12) +#define FTGMAC100_MACCR_JUMBO_LF BIT(13) +#define FTGMAC100_MACCR_RX_ALL BIT(14) +#define FTGMAC100_MACCR_HT_MULTI_EN BIT(15) +#define FTGMAC100_MACCR_RX_MULTIPKT BIT(16) +#define FTGMAC100_MACCR_RX_BROADPKT BIT(17) +#define FTGMAC100_MACCR_DISCARD_CRCERR BIT(18) +#define FTGMAC100_MACCR_FAST_MODE BIT(19) +#define FTGMAC100_MACCR_SW_RST BIT(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 BIT(26) +#define FTGMAC100_PHYCR_MIIWR BIT(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 */
+} __aligned(16);
+#define FTGMAC100_TXDES0_TXBUF_SIZE(x) ((x) & 0x3fff) +#define FTGMAC100_TXDES0_EDOTR BIT(15) +#define FTGMAC100_TXDES0_CRC_ERR BIT(19) +#define FTGMAC100_TXDES0_LTS BIT(28) +#define FTGMAC100_TXDES0_FTS BIT(29) +#define FTGMAC100_TXDES0_TXDMA_OWN BIT(31)
+#define FTGMAC100_TXDES1_VLANTAG_CI(x) ((x) & 0xffff) +#define FTGMAC100_TXDES1_INS_VLANTAG BIT(16) +#define FTGMAC100_TXDES1_TCP_CHKSUM BIT(17) +#define FTGMAC100_TXDES1_UDP_CHKSUM BIT(18) +#define FTGMAC100_TXDES1_IP_CHKSUM BIT(19) +#define FTGMAC100_TXDES1_LLC BIT(22) +#define FTGMAC100_TXDES1_TX2FIC BIT(30) +#define FTGMAC100_TXDES1_TXIC BIT(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 */
+} __aligned(16);
+#define FTGMAC100_RXDES0_VDBC(x) ((x) & 0x3fff) +#define FTGMAC100_RXDES0_EDORR BIT(15) +#define FTGMAC100_RXDES0_MULTICAST BIT(16) +#define FTGMAC100_RXDES0_BROADCAST BIT(17) +#define FTGMAC100_RXDES0_RX_ERR BIT(18) +#define FTGMAC100_RXDES0_CRC_ERR BIT(19) +#define FTGMAC100_RXDES0_FTL BIT(20) +#define FTGMAC100_RXDES0_RUNT BIT(21) +#define FTGMAC100_RXDES0_RX_ODD_NB BIT(22) +#define FTGMAC100_RXDES0_FIFO_FULL BIT(23) +#define FTGMAC100_RXDES0_PAUSE_OPCODE BIT(24) +#define FTGMAC100_RXDES0_PAUSE_FRAME BIT(25) +#define FTGMAC100_RXDES0_LRS BIT(28) +#define FTGMAC100_RXDES0_FRS BIT(29) +#define FTGMAC100_RXDES0_RXPKT_RDY BIT(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 BIT(22) +#define FTGMAC100_RXDES1_DF BIT(23) +#define FTGMAC100_RXDES1_VLANTAG_AVAIL BIT(24) +#define FTGMAC100_RXDES1_TCP_CHKSUM_ERR BIT(25) +#define FTGMAC100_RXDES1_UDP_CHKSUM_ERR BIT(26) +#define FTGMAC100_RXDES1_IP_CHKSUM_ERR BIT(27)
+#endif /* __FTGMAC100_H */ diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c new file mode 100644 index 000000000000..8d7bf5b9b351 --- /dev/null +++ b/drivers/net/ftgmac100.c @@ -0,0 +1,493 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- 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
- Copyright (C) 2018, IBM Corporation.
- */
+#include <clk.h> +#include <miiphy.h> +#include <net.h> +#include <asm/io.h>
+#include "ftgmac100.h"
+#define ETH_ZLEN 60 +#define CFG_XBUF_SIZE 1536
Comments on these
yes.
+/* RBSR - hw default init value is also 0x640 */ +#define RBSR_DEFAULT_VALUE 0x640
+/* PKTBUFSTX/PKTBUFSRX must both be power of 2 */ +#define PKTBUFSTX 4
+struct ftgmac100_data {
Comment here and on members
ok
phys_addr_t iobase;
struct ftgmac100_txdes txdes[PKTBUFSTX];
struct ftgmac100_rxdes rxdes[PKTBUFSRX];
int tx_index;
int rx_index;
u32 phyaddr;
struct phy_device *phydev;
struct mii_dev *bus;
u32 phy_mode;
u32 max_speed;
+};
+/*
- MDC clock cycle threshold
- 20us * 100 = 2ms > (1 / 2.5Mhz) * 0x34
- */
+#define MDC_CYCTHR 0x34
+static int ftgmac100_mdio_read(struct mii_dev *bus, int phy_addr, int dev_addr,
int reg_addr)
+{
struct ftgmac100_data *priv = bus->priv;
dev_get_priv(bus)
That's a 'struct mii_dev'
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
Can you put the struct ftgmac100 * in priv and avoid the cast each time?
yes. We will still have this one :
priv->iobase = (struct ftgmac100 *)pdata->iobase;
int phycr;
int i;
phycr = MDC_CYCTHR |
FTGMAC100_PHYCR_PHYAD(phy_addr) |
FTGMAC100_PHYCR_REGAD(reg_addr) |
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);
This is an extraordinarily long delay. Is this described in the datasheet?
It came with the previous driver. Since I have changed this part to:
#define FTGMAC100_MDIO_TIMEOUT_USEC 10000
ret = readl_poll_timeout(&ftgmac100->phycr, phycr, !(phycr & FTGMAC100_PHYCR_MIIRD), FTGMAC100_MDIO_TIMEOUT_USEC);
and all looks fine.
}
pr_err("mdio read timed out\n");
return -1;
-ETIMEDOUT
Same below
yes.
+}
+static int ftgmac100_mdio_write(struct mii_dev *bus, int phy_addr, int dev_addr,
int reg_addr, u16 value)
+{
struct ftgmac100_data *priv = bus->priv;
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
int phycr;
int data;
int i;
phycr = MDC_CYCTHR |
FTGMAC100_PHYCR_PHYAD(phy_addr) |
FTGMAC100_PHYCR_REGAD(reg_addr) |
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)
return 0;
mdelay(1);
}
pr_err("mdio write timed out\n");
return -1;
+}
+static int ftgmac100_mdio_init(struct ftgmac100_data *priv, int dev_id) +{
struct mii_dev *bus;
int ret;
bus = mdio_alloc();
if (!bus)
return -ENOMEM;
bus->read = ftgmac100_mdio_read;
bus->write = ftgmac100_mdio_write;
bus->priv = priv;
ret = mdio_register_seq(bus, dev_id);
if (ret) {
free(bus);
return ret;
}
priv->bus = bus;
return 0;
+}
+static int ftgmac100_phy_adjust_link(struct ftgmac100_data *priv) +{
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
struct phy_device *phydev = priv->phydev;
u32 maccr;
if (!phydev->link) {
dev_err(phydev->dev, "No link\n");
return -ENODEV;
-EREMOTEIO perhaps? You cannot use -ENODEV since there is a device
yes.
}
/* read MAC control register and clear related bits */
maccr = readl(&ftgmac100->maccr) &
~(FTGMAC100_MACCR_GIGA_MODE |
FTGMAC100_MACCR_FAST_MODE |
FTGMAC100_MACCR_FULLDUP);
if (phy_interface_is_rgmii(phydev) && phydev->speed == 1000)
maccr |= FTGMAC100_MACCR_GIGA_MODE;
if (phydev->speed == 100)
maccr |= FTGMAC100_MACCR_FAST_MODE;
if (phydev->duplex)
maccr |= FTGMAC100_MACCR_FULLDUP;
/* update MII config into maccr */
writel(maccr, &ftgmac100->maccr);
return 0;
+}
+static int ftgmac100_phy_init(struct ftgmac100_data *priv, void *dev) +{
struct phy_device *phydev;
int ret;
phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->phy_mode);
phydev->supported &= PHY_GBIT_FEATURES;
if (priv->max_speed) {
ret = phy_set_supported(phydev, priv->max_speed);
if (ret)
return ret;
}
phydev->advertising = phydev->supported;
priv->phydev = phydev;
phy_config(phydev);
return 0;
+}
+static void ftgmac100_reset(struct ftgmac100_data *priv) +{
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
setbits_le32(&ftgmac100->maccr, FTGMAC100_MACCR_SW_RST);
while (readl(&ftgmac100->maccr) & FTGMAC100_MACCR_SW_RST)
;
+}
+static int ftgmac100_set_mac(struct ftgmac100_data *priv,
const unsigned char *mac)
+{
struct ftgmac100 *ftgmac100 = (struct 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];
writel(maddr, &ftgmac100->mac_madr);
writel(laddr, &ftgmac100->mac_ladr);
return 0;
+}
+static void ftgmac100_stop(struct udevice *dev) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
writel(0, &ftgmac100->maccr);
phy_shutdown(priv->phydev);
+}
+static int ftgmac100_start(struct udevice *dev) +{
struct eth_pdata *plat = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
struct phy_device *phydev = priv->phydev;
unsigned int maccr;
int ret;
int i;
ftgmac100_reset(priv);
/* set the ethernet address */
ftgmac100_set_mac(priv, plat->enetaddr);
/* disable all interrupts */
writel(0, &ftgmac100->ier);
/* initialize descriptor tables */
priv->tx_index = 0;
priv->rx_index = 0;
for (i = 0; i < PKTBUFSTX; i++) {
priv->txdes[i].txdes3 = 0;
priv->txdes[i].txdes0 = 0;
}
priv->txdes[PKTBUFSTX - 1].txdes0 = FTGMAC100_TXDES0_EDOTR;
for (i = 0; i < PKTBUFSRX; i++) {
priv->rxdes[i].rxdes3 = (unsigned int)net_rx_packets[i];
priv->rxdes[i].rxdes0 = 0;
}
priv->rxdes[PKTBUFSRX - 1].rxdes0 = FTGMAC100_RXDES0_EDORR;
/* transmit ring */
writel((u32)priv->txdes, &ftgmac100->txr_badr);
/* receive ring */
writel((u32)priv->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);
ret = phy_startup(phydev);
if (ret) {
dev_err(phydev->dev, "Could not start PHY\n");
return ret;
}
ret = ftgmac100_phy_adjust_link(priv);
if (ret) {
dev_err(phydev->dev, "Could not adjust link\n");
return ret;
}
printf("%s: link up, %d Mbps %s-duplex mac:%pM\n", phydev->dev->name,
phydev->speed, phydev->duplex ? "full" : "half", plat->enetaddr);
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];
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
/* Release buffer to DMA and flush descriptor */
curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
flush_dcache_range(des_start, des_end);
/* Move to next descriptor */
priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX;
return 0;
+}
+static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index];
int length;
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
ulong data_start = curr_des->rxdes3;
ulong data_end;
invalidate_dcache_range(des_start, des_end);
if (!(curr_des->rxdes0 & FTGMAC100_RXDES0_RXPKT_RDY))
return -EAGAIN;
if (curr_des->rxdes0 & (FTGMAC100_RXDES0_RX_ERR |
FTGMAC100_RXDES0_CRC_ERR |
FTGMAC100_RXDES0_FTL |
FTGMAC100_RXDES0_RUNT |
FTGMAC100_RXDES0_RX_ODD_NB)) {
return -EAGAIN;
}
length = FTGMAC100_RXDES0_VDBC(curr_des->rxdes0);
/* Invalidate received data */
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
invalidate_dcache_range(data_start, data_end);
*packetp = (uchar *)data_start;
return length;
+}
+static int ftgmac100_send(struct udevice *dev, void *packet, int length) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase;
struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
ulong data_start;
ulong data_end;
invalidate_dcache_range(des_start, des_end);
if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
pr_err("no TX descriptor available\n");
return -EPERM;
}
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;
/* Flush data to be sent */
data_start = curr_des->txdes3;
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
flush_dcache_range(data_start, data_end);
/* only one descriptor on TXBUF */
curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
curr_des->txdes0 |= FTGMAC100_TXDES0_FTS |
FTGMAC100_TXDES0_LTS |
FTGMAC100_TXDES0_TXBUF_SIZE(length) |
FTGMAC100_TXDES0_TXDMA_OWN;
/* Flush modified buffer descriptor */
flush_dcache_range(des_start, des_end);
debug("%s(): packet sent\n", __func__);
priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
/* start transmit */
writel(1, &ftgmac100->txpd);
/* TODO: check TXDMA_OWN bit for xmit timeouts */
TODO(email)
Should this TODO actually be done now, perhaps?
indeed it should :)
return 0;
+}
+static int ftgmac100_write_hwaddr(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
return ftgmac100_set_mac(priv, pdata->enetaddr);
+}
+static int ftgmac100_ofdata_to_platdata(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
const char *phy_mode;
pdata->iobase = devfdt_get_addr(dev);
pdata->phy_interface = -1;
phy_mode = dev_read_string(dev, "phy-mode");
if (phy_mode)
pdata->phy_interface = phy_get_interface_by_name(phy_mode);
if (pdata->phy_interface == -1) {
dev_err(dev, "Invalid PHY interface '%s'\n", phy_mode);
return -EINVAL;
}
pdata->max_speed = dev_read_u32_default(dev, "max-speed", 0);
return 0;
+}
+static int ftgmac100_probe(struct udevice *dev) +{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
int ret;
priv->iobase = pdata->iobase;
priv->phy_mode = pdata->phy_interface;
priv->max_speed = pdata->max_speed;
priv->phyaddr = 0;
ret = ftgmac100_mdio_init(priv, dev->seq);
if (ret) {
dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
goto out;
}
ret = ftgmac100_phy_init(priv, dev);
if (ret) {
dev_err(dev, "Failed to initialize PHY: %d\n", ret);
goto out;
}
+out:
return ret;
+}
+static int ftgmac100_remove(struct udevice *dev) +{
struct ftgmac100_data *priv = dev_get_priv(dev);
free(priv->phydev);
mdio_unregister(priv->bus);
mdio_free(priv->bus);
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/drivers/net/Kconfig b/drivers/net/Kconfig index 5441da47d13e..65edb0316e6f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -186,6 +186,14 @@ 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.
Do you have any more details you could add here about the mac or what feature the driver supports?
yes. I will add some more documentation on the mac.
Thanks for the review,
C.
config MVGBE bool "Marvell Orion5x/Kirkwood network interface support" depends on KIRKWOOD || ORION5X diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4ca4e15bdd71..48a2878071d1 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_EP93XX) += ep93xx_eth.o obj-$(CONFIG_ETHOC) += ethoc.o obj-$(CONFIG_FEC_MXC) += fec_mxc.o obj-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o +obj-$(CONFIG_FTGMAC100) += ftgmac100.o obj-$(CONFIG_FTMAC110) += ftmac110.o obj-$(CONFIG_FTMAC100) += ftmac100.o obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o -- 2.17.1
Regards, Simon

Signed-off-by: Cédric Le Goater clg@kaod.org --- drivers/clk/aspeed/clk_ast2500.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/clk/aspeed/clk_ast2500.c b/drivers/clk/aspeed/clk_ast2500.c index c55f8d5ae30d..169c330d3d41 100644 --- a/drivers/clk/aspeed/clk_ast2500.c +++ b/drivers/clk/aspeed/clk_ast2500.c @@ -423,6 +423,7 @@ static int ast2500_clk_enable(struct clk *clk) break; case PLL_D2PLL: ast2500_configure_d2pll(priv->scu, D2PLL_DEFAULT_RATE); + break; default: return -ENOENT; }

On Mon, 10 Sep 2018 at 23:54, Cédric Le Goater clg@kaod.org wrote:
Signed-off-by: Cédric Le Goater clg@kaod.org
Reviewed-by: Joel Stanley joel@jms.id.au

On 10 September 2018 at 07:21, Cédric Le Goater clg@kaod.org wrote:
Signed-off-by: Cédric Le Goater clg@kaod.org
drivers/clk/aspeed/clk_ast2500.c | 1 + 1 file changed, 1 insertion(+)
Reviewed-by: Simon Glass sjg@chromium.org

The Faraday ftgmac100 MAC controllers as found on the Aspeed SoCs have some slight differences in the HW interface (End-Of-Rx/Tx-Ring bits). Also include the Aspeed clock enablement.
Signed-off-by: Cédric Le Goater clg@kaod.org --- drivers/net/ftgmac100.h | 5 +++ drivers/net/ftgmac100.c | 72 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 71 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ftgmac100.h b/drivers/net/ftgmac100.h index 9a789e4d5bee..b8f99ddf48bc 100644 --- a/drivers/net/ftgmac100.h +++ b/drivers/net/ftgmac100.h @@ -129,6 +129,11 @@ struct ftgmac100 { #define FTGMAC100_DMAFIFOS_RXDMA_REQ BIT(30) #define FTGMAC100_DMAFIFOS_TXDMA_REQ BIT(31)
+/* + * Feature Register + */ +#define FTGMAC100_REVR_NEW_MDIO BIT(31) + /* * Receive buffer size register */ diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c index 8d7bf5b9b351..3df48a82c1ad 100644 --- a/drivers/net/ftgmac100.c +++ b/drivers/net/ftgmac100.c @@ -27,6 +27,8 @@ /* PKTBUFSTX/PKTBUFSRX must both be power of 2 */ #define PKTBUFSTX 4
+#define FTGMAC100_ASPEED_NR_CLKS 2 + struct ftgmac100_data { phys_addr_t iobase;
@@ -40,6 +42,11 @@ struct ftgmac100_data { struct mii_dev *bus; u32 phy_mode; u32 max_speed; + + struct clk clks[FTGMAC100_ASPEED_NR_CLKS]; + u32 rxdes0_edorr_mask; + u32 txdes0_edotr_mask; + bool is_aspeed; };
/* @@ -115,9 +122,15 @@ static int ftgmac100_mdio_write(struct mii_dev *bus, int phy_addr, int dev_addr,
static int ftgmac100_mdio_init(struct ftgmac100_data *priv, int dev_id) { + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase; struct mii_dev *bus; int ret;
+ if (priv->is_aspeed) { + /* This driver supports the old MDIO interface */ + clrbits_le32(&ftgmac100->revr, FTGMAC100_REVR_NEW_MDIO); + }; + bus = mdio_alloc(); if (!bus) return -ENOMEM; @@ -246,13 +259,13 @@ static int ftgmac100_start(struct udevice *dev) priv->txdes[i].txdes3 = 0; priv->txdes[i].txdes0 = 0; } - priv->txdes[PKTBUFSTX - 1].txdes0 = FTGMAC100_TXDES0_EDOTR; + priv->txdes[PKTBUFSTX - 1].txdes0 = priv->txdes0_edotr_mask;
for (i = 0; i < PKTBUFSRX; i++) { priv->rxdes[i].rxdes3 = (unsigned int)net_rx_packets[i]; priv->rxdes[i].rxdes0 = 0; } - priv->rxdes[PKTBUFSRX - 1].rxdes0 = FTGMAC100_RXDES0_EDORR; + priv->rxdes[PKTBUFSRX - 1].rxdes0 = priv->rxdes0_edorr_mask;
/* transmit ring */ writel((u32)priv->txdes, &ftgmac100->txr_badr); @@ -378,7 +391,7 @@ static int ftgmac100_send(struct udevice *dev, void *packet, int length) flush_dcache_range(data_start, data_end);
/* only one descriptor on TXBUF */ - curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR; + curr_des->txdes0 &= priv->txdes0_edotr_mask; curr_des->txdes0 |= FTGMAC100_TXDES0_FTS | FTGMAC100_TXDES0_LTS | FTGMAC100_TXDES0_TXBUF_SIZE(length) | @@ -409,8 +422,11 @@ static int ftgmac100_write_hwaddr(struct udevice *dev)
static int ftgmac100_ofdata_to_platdata(struct udevice *dev) { + struct ftgmac100_data *priv = dev_get_priv(dev); struct eth_pdata *pdata = dev_get_platdata(dev); const char *phy_mode; + int ret; + int i;
pdata->iobase = devfdt_get_addr(dev); pdata->phy_interface = -1; @@ -424,13 +440,39 @@ static int ftgmac100_ofdata_to_platdata(struct udevice *dev)
pdata->max_speed = dev_read_u32_default(dev, "max-speed", 0);
+ if (device_is_compatible(dev, "aspeed,ast2500-mac")) { + priv->rxdes0_edorr_mask = BIT(30); + priv->txdes0_edotr_mask = BIT(30); + priv->is_aspeed = true; + } else { + priv->rxdes0_edorr_mask = BIT(15); + priv->txdes0_edotr_mask = BIT(15); + } + + if (priv->is_aspeed) { + for (i = 0; i < FTGMAC100_ASPEED_NR_CLKS; i++) { + ret = clk_get_by_index(dev, i, &priv->clks[i]); + if (ret) { + dev_err(dev, "Failed to get clock: %d\n", ret); + goto out_clk_free; + } + } + } + return 0; + +out_clk_free: + while (--i >= 0) + clk_free(&priv->clks[i]); + + return ret; }
static int ftgmac100_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); struct ftgmac100_data *priv = dev_get_priv(dev); + int i; int ret;
priv->iobase = pdata->iobase; @@ -438,19 +480,33 @@ static int ftgmac100_probe(struct udevice *dev) priv->max_speed = pdata->max_speed; priv->phyaddr = 0;
+ if (priv->is_aspeed) { + for (i = 0; i < FTGMAC100_ASPEED_NR_CLKS; i++) { + ret = clk_enable(&priv->clks[i]); + if (ret) { + dev_err(dev, "Failed to enable clock: %d\n", + ret); + goto out_clk_release; + } + } + } + ret = ftgmac100_mdio_init(priv, dev->seq); if (ret) { dev_err(dev, "Failed to initialize mdiobus: %d\n", ret); - goto out; + goto out_clk_release; }
ret = ftgmac100_phy_init(priv, dev); if (ret) { dev_err(dev, "Failed to initialize PHY: %d\n", ret); - goto out; + goto out_clk_release; }
-out: +out_clk_release: + if (ret && priv->is_aspeed) + clk_release_all(priv->clks, FTGMAC100_ASPEED_NR_CLKS); + return ret; }
@@ -462,6 +518,9 @@ static int ftgmac100_remove(struct udevice *dev) mdio_unregister(priv->bus); mdio_free(priv->bus);
+ if (priv->is_aspeed) + clk_release_all(priv->clks, FTGMAC100_ASPEED_NR_CLKS); + return 0; }
@@ -476,6 +535,7 @@ static const struct eth_ops ftgmac100_ops = {
static const struct udevice_id ftgmac100_ids[] = { { .compatible = "faraday,ftgmac100" }, + { .compatible = "aspeed,ast2500-mac" }, { } };

On Mon, 10 Sep 2018 at 23:55, Cédric Le Goater clg@kaod.org wrote:
The Faraday ftgmac100 MAC controllers as found on the Aspeed SoCs have some slight differences in the HW interface (End-Of-Rx/Tx-Ring bits). Also include the Aspeed clock enablement.
Signed-off-by: Cédric Le Goater clg@kaod.org
Reviewed-by: Joel Stanley joel@jms.id.au

Hi Cedric,
On 10 September 2018 at 07:21, Cédric Le Goater clg@kaod.org wrote:
The Faraday ftgmac100 MAC controllers as found on the Aspeed SoCs have some slight differences in the HW interface (End-Of-Rx/Tx-Ring bits). Also include the Aspeed clock enablement.
Signed-off-by: Cédric Le Goater clg@kaod.org
drivers/net/ftgmac100.h | 5 +++ drivers/net/ftgmac100.c | 72 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 71 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ftgmac100.h b/drivers/net/ftgmac100.h index 9a789e4d5bee..b8f99ddf48bc 100644 --- a/drivers/net/ftgmac100.h +++ b/drivers/net/ftgmac100.h @@ -129,6 +129,11 @@ struct ftgmac100 { #define FTGMAC100_DMAFIFOS_RXDMA_REQ BIT(30) #define FTGMAC100_DMAFIFOS_TXDMA_REQ BIT(31)
+/*
- Feature Register
- */
+#define FTGMAC100_REVR_NEW_MDIO BIT(31)
/*
- Receive buffer size register
*/ diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c index 8d7bf5b9b351..3df48a82c1ad 100644 --- a/drivers/net/ftgmac100.c +++ b/drivers/net/ftgmac100.c @@ -27,6 +27,8 @@ /* PKTBUFSTX/PKTBUFSRX must both be power of 2 */ #define PKTBUFSTX 4
+#define FTGMAC100_ASPEED_NR_CLKS 2
struct ftgmac100_data { phys_addr_t iobase;
@@ -40,6 +42,11 @@ struct ftgmac100_data {
Comments on struct and members
struct mii_dev *bus; u32 phy_mode; u32 max_speed;
struct clk clks[FTGMAC100_ASPEED_NR_CLKS];
u32 rxdes0_edorr_mask;
u32 txdes0_edotr_mask;
bool is_aspeed;
};
/* @@ -115,9 +122,15 @@ static int ftgmac100_mdio_write(struct mii_dev *bus, int phy_addr, int dev_addr,
static int ftgmac100_mdio_init(struct ftgmac100_data *priv, int dev_id) {
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase; struct mii_dev *bus; int ret;
if (priv->is_aspeed) {
Perhaps call this old_mdio_if ?
/* This driver supports the old MDIO interface */
clrbits_le32(&ftgmac100->revr, FTGMAC100_REVR_NEW_MDIO);
};
bus = mdio_alloc(); if (!bus) return -ENOMEM;
@@ -246,13 +259,13 @@ static int ftgmac100_start(struct udevice *dev) priv->txdes[i].txdes3 = 0; priv->txdes[i].txdes0 = 0; }
priv->txdes[PKTBUFSTX - 1].txdes0 = FTGMAC100_TXDES0_EDOTR;
priv->txdes[PKTBUFSTX - 1].txdes0 = priv->txdes0_edotr_mask; for (i = 0; i < PKTBUFSRX; i++) { priv->rxdes[i].rxdes3 = (unsigned int)net_rx_packets[i]; priv->rxdes[i].rxdes0 = 0; }
priv->rxdes[PKTBUFSRX - 1].rxdes0 = FTGMAC100_RXDES0_EDORR;
priv->rxdes[PKTBUFSRX - 1].rxdes0 = priv->rxdes0_edorr_mask; /* transmit ring */ writel((u32)priv->txdes, &ftgmac100->txr_badr);
@@ -378,7 +391,7 @@ static int ftgmac100_send(struct udevice *dev, void *packet, int length) flush_dcache_range(data_start, data_end);
/* only one descriptor on TXBUF */
curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
curr_des->txdes0 &= priv->txdes0_edotr_mask; curr_des->txdes0 |= FTGMAC100_TXDES0_FTS | FTGMAC100_TXDES0_LTS | FTGMAC100_TXDES0_TXBUF_SIZE(length) |
@@ -409,8 +422,11 @@ static int ftgmac100_write_hwaddr(struct udevice *dev)
static int ftgmac100_ofdata_to_platdata(struct udevice *dev) {
struct ftgmac100_data *priv = dev_get_priv(dev); struct eth_pdata *pdata = dev_get_platdata(dev); const char *phy_mode;
int ret;
int i; pdata->iobase = devfdt_get_addr(dev); pdata->phy_interface = -1;
@@ -424,13 +440,39 @@ static int ftgmac100_ofdata_to_platdata(struct udevice *dev)
pdata->max_speed = dev_read_u32_default(dev, "max-speed", 0);
if (device_is_compatible(dev, "aspeed,ast2500-mac")) {
Should use dev_get_driver_data() here.
priv->rxdes0_edorr_mask = BIT(30);
priv->txdes0_edotr_mask = BIT(30);
priv->is_aspeed = true;
} else {
priv->rxdes0_edorr_mask = BIT(15);
priv->txdes0_edotr_mask = BIT(15);
}
if (priv->is_aspeed) {
for (i = 0; i < FTGMAC100_ASPEED_NR_CLKS; i++) {
ret = clk_get_by_index(dev, i, &priv->clks[i]);
if (ret) {
dev_err(dev, "Failed to get clock: %d\n", ret);
goto out_clk_free;
}
}
clk_get_bulk() ?
}
return 0;
+out_clk_free:
while (--i >= 0)
clk_free(&priv->clks[i]);
return ret;
}
static int ftgmac100_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); struct ftgmac100_data *priv = dev_get_priv(dev);
int i; int ret; priv->iobase = pdata->iobase;
@@ -438,19 +480,33 @@ static int ftgmac100_probe(struct udevice *dev) priv->max_speed = pdata->max_speed; priv->phyaddr = 0;
if (priv->is_aspeed) {
Why does this depend on aspeed? Can the DT specify what clocks are needed and how many?
for (i = 0; i < FTGMAC100_ASPEED_NR_CLKS; i++) {
clk_get_bulk() ?
Should use device tree to get number of clocks.
ret = clk_enable(&priv->clks[i]);
if (ret) {
dev_err(dev, "Failed to enable clock: %d\n",
ret);
goto out_clk_release;
}
}
}
ret = ftgmac100_mdio_init(priv, dev->seq); if (ret) { dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
goto out;
goto out_clk_release; } ret = ftgmac100_phy_init(priv, dev); if (ret) { dev_err(dev, "Failed to initialize PHY: %d\n", ret);
goto out;
goto out_clk_release; }
-out: +out_clk_release:
if (ret && priv->is_aspeed)
clk_release_all(priv->clks, FTGMAC100_ASPEED_NR_CLKS);
return ret;
}
@@ -462,6 +518,9 @@ static int ftgmac100_remove(struct udevice *dev) mdio_unregister(priv->bus); mdio_free(priv->bus);
if (priv->is_aspeed)
clk_release_all(priv->clks, FTGMAC100_ASPEED_NR_CLKS);
return 0;
}
@@ -476,6 +535,7 @@ static const struct eth_ops ftgmac100_ops = {
static const struct udevice_id ftgmac100_ids[] = { { .compatible = "faraday,ftgmac100" },
{ .compatible = "aspeed,ast2500-mac" },
Need .data = ASPEED here, or something like that
{ }
};
-- 2.17.1
Regards, Simon

Hello Simon,
On 9/27/18 3:41 PM, Simon Glass wrote:
Hi Cedric,
On 10 September 2018 at 07:21, Cédric Le Goater clg@kaod.org wrote:
The Faraday ftgmac100 MAC controllers as found on the Aspeed SoCs have some slight differences in the HW interface (End-Of-Rx/Tx-Ring bits). Also include the Aspeed clock enablement.
Signed-off-by: Cédric Le Goater clg@kaod.org
drivers/net/ftgmac100.h | 5 +++ drivers/net/ftgmac100.c | 72 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 71 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ftgmac100.h b/drivers/net/ftgmac100.h index 9a789e4d5bee..b8f99ddf48bc 100644 --- a/drivers/net/ftgmac100.h +++ b/drivers/net/ftgmac100.h @@ -129,6 +129,11 @@ struct ftgmac100 { #define FTGMAC100_DMAFIFOS_RXDMA_REQ BIT(30) #define FTGMAC100_DMAFIFOS_TXDMA_REQ BIT(31)
+/*
- Feature Register
- */
+#define FTGMAC100_REVR_NEW_MDIO BIT(31)
/*
- Receive buffer size register
*/ diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c index 8d7bf5b9b351..3df48a82c1ad 100644 --- a/drivers/net/ftgmac100.c +++ b/drivers/net/ftgmac100.c @@ -27,6 +27,8 @@ /* PKTBUFSTX/PKTBUFSRX must both be power of 2 */ #define PKTBUFSTX 4
+#define FTGMAC100_ASPEED_NR_CLKS 2
struct ftgmac100_data { phys_addr_t iobase;
@@ -40,6 +42,11 @@ struct ftgmac100_data {
Comments on struct and members
ok.
struct mii_dev *bus; u32 phy_mode; u32 max_speed;
struct clk clks[FTGMAC100_ASPEED_NR_CLKS];
u32 rxdes0_edorr_mask;
u32 txdes0_edotr_mask;
bool is_aspeed;
};
/* @@ -115,9 +122,15 @@ static int ftgmac100_mdio_write(struct mii_dev *bus, int phy_addr, int dev_addr,
static int ftgmac100_mdio_init(struct ftgmac100_data *priv, int dev_id) {
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)priv->iobase; struct mii_dev *bus; int ret;
if (priv->is_aspeed) {
Perhaps call this old_mdio_if ?
Well, this feature is related to the Aspeed socs. The old MDIO interface is used by default so I think we don't have to force the value below.
However, we can imagine selecting the mdio interface, new or old, through a DT property. I will follow your suggestion then.
/* This driver supports the old MDIO interface */
clrbits_le32(&ftgmac100->revr, FTGMAC100_REVR_NEW_MDIO);
};
bus = mdio_alloc(); if (!bus) return -ENOMEM;
@@ -246,13 +259,13 @@ static int ftgmac100_start(struct udevice *dev) priv->txdes[i].txdes3 = 0; priv->txdes[i].txdes0 = 0; }
priv->txdes[PKTBUFSTX - 1].txdes0 = FTGMAC100_TXDES0_EDOTR;
priv->txdes[PKTBUFSTX - 1].txdes0 = priv->txdes0_edotr_mask; for (i = 0; i < PKTBUFSRX; i++) { priv->rxdes[i].rxdes3 = (unsigned int)net_rx_packets[i]; priv->rxdes[i].rxdes0 = 0; }
priv->rxdes[PKTBUFSRX - 1].rxdes0 = FTGMAC100_RXDES0_EDORR;
priv->rxdes[PKTBUFSRX - 1].rxdes0 = priv->rxdes0_edorr_mask; /* transmit ring */ writel((u32)priv->txdes, &ftgmac100->txr_badr);
@@ -378,7 +391,7 @@ static int ftgmac100_send(struct udevice *dev, void *packet, int length) flush_dcache_range(data_start, data_end);
/* only one descriptor on TXBUF */
curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
curr_des->txdes0 &= priv->txdes0_edotr_mask; curr_des->txdes0 |= FTGMAC100_TXDES0_FTS | FTGMAC100_TXDES0_LTS | FTGMAC100_TXDES0_TXBUF_SIZE(length) |
@@ -409,8 +422,11 @@ static int ftgmac100_write_hwaddr(struct udevice *dev)
static int ftgmac100_ofdata_to_platdata(struct udevice *dev) {
struct ftgmac100_data *priv = dev_get_priv(dev); struct eth_pdata *pdata = dev_get_platdata(dev); const char *phy_mode;
int ret;
int i; pdata->iobase = devfdt_get_addr(dev); pdata->phy_interface = -1;
@@ -424,13 +440,39 @@ static int ftgmac100_ofdata_to_platdata(struct udevice *dev)
pdata->max_speed = dev_read_u32_default(dev, "max-speed", 0);
if (device_is_compatible(dev, "aspeed,ast2500-mac")) {
Should use dev_get_driver_data() here.
OK. I see.
priv->rxdes0_edorr_mask = BIT(30);
priv->txdes0_edotr_mask = BIT(30);
priv->is_aspeed = true;
} else {
priv->rxdes0_edorr_mask = BIT(15);
priv->txdes0_edotr_mask = BIT(15);
}
if (priv->is_aspeed) {
for (i = 0; i < FTGMAC100_ASPEED_NR_CLKS; i++) {
ret = clk_get_by_index(dev, i, &priv->clks[i]);
if (ret) {
dev_err(dev, "Failed to get clock: %d\n", ret);
goto out_clk_free;
}
}
clk_get_bulk() ?
I should help indeed. I will take a look.
}
return 0;
+out_clk_free:
while (--i >= 0)
clk_free(&priv->clks[i]);
return ret;
}
static int ftgmac100_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); struct ftgmac100_data *priv = dev_get_priv(dev);
int i; int ret; priv->iobase = pdata->iobase;
@@ -438,19 +480,33 @@ static int ftgmac100_probe(struct udevice *dev) priv->max_speed = pdata->max_speed; priv->phyaddr = 0;
if (priv->is_aspeed) {
Why does this depend on aspeed? Can the DT specify what clocks are needed and how many?
yes. it does.
I should be able to make this part more generic with clk_get_bulk() and merge it in the initial patch covering the whole ftgmac100 family. I only have access to an Aspeed one.
for (i = 0; i < FTGMAC100_ASPEED_NR_CLKS; i++) {
clk_get_bulk() ?
Should use device tree to get number of clocks.
ret = clk_enable(&priv->clks[i]);
if (ret) {
dev_err(dev, "Failed to enable clock: %d\n",
ret);
goto out_clk_release;
}
}
}
ret = ftgmac100_mdio_init(priv, dev->seq); if (ret) { dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
goto out;
goto out_clk_release; } ret = ftgmac100_phy_init(priv, dev); if (ret) { dev_err(dev, "Failed to initialize PHY: %d\n", ret);
goto out;
goto out_clk_release; }
-out: +out_clk_release:
if (ret && priv->is_aspeed)
clk_release_all(priv->clks, FTGMAC100_ASPEED_NR_CLKS);
return ret;
}
@@ -462,6 +518,9 @@ static int ftgmac100_remove(struct udevice *dev) mdio_unregister(priv->bus); mdio_free(priv->bus);
if (priv->is_aspeed)
clk_release_all(priv->clks, FTGMAC100_ASPEED_NR_CLKS);
return 0;
}
@@ -476,6 +535,7 @@ static const struct eth_ops ftgmac100_ops = {
static const struct udevice_id ftgmac100_ids[] = { { .compatible = "faraday,ftgmac100" },
{ .compatible = "aspeed,ast2500-mac" },
Need .data = ASPEED here, or something like that
ok.
Thanks for the review.
C.
{ }
};
-- 2.17.1
Regards, Simon

Signed-off-by: Cédric Le Goater clg@kaod.org --- arch/arm/dts/ast2500-evb.dts | 17 +++++++++++++++++ arch/arm/dts/ast2500.dtsi | 4 ++-- configs/evb-ast2500_defconfig | 8 ++++++++ 3 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/arch/arm/dts/ast2500-evb.dts b/arch/arm/dts/ast2500-evb.dts index 609678ff7989..1bd224dacf78 100644 --- a/arch/arm/dts/ast2500-evb.dts +++ b/arch/arm/dts/ast2500-evb.dts @@ -14,6 +14,7 @@
aliases { spi0 = &fmc; + ethernet0 = &mac0; }; };
@@ -53,3 +54,19 @@ spi-rx-bus-width = <2>; }; }; + +&mac0 { + status = "okay"; + + phy-mode = "rgmii"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mac1link_default &pinctrl_mdio1_default>; +}; + +&mac1 { + status = "disabled"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mac2link_default &pinctrl_mdio2_default>; +}; diff --git a/arch/arm/dts/ast2500.dtsi b/arch/arm/dts/ast2500.dtsi index de7607aaafff..a1fc5370b109 100644 --- a/arch/arm/dts/ast2500.dtsi +++ b/arch/arm/dts/ast2500.dtsi @@ -108,7 +108,7 @@ };
mac0: ethernet@1e660000 { - compatible = "faraday,ftgmac100"; + compatible = "aspeed,ast2500-mac", "faraday,ftgmac100"; reg = <0x1e660000 0x180>; interrupts = <2>; no-hw-checksum; @@ -116,7 +116,7 @@ };
mac1: ethernet@1e680000 { - compatible = "faraday,ftgmac100"; + compatible = "aspeed,ast2500-mac", "faraday,ftgmac100"; reg = <0x1e680000 0x180>; interrupts = <3>; no-hw-checksum; diff --git a/configs/evb-ast2500_defconfig b/configs/evb-ast2500_defconfig index eb0fe00fb49f..4e65388dab23 100644 --- a/configs/evb-ast2500_defconfig +++ b/configs/evb-ast2500_defconfig @@ -38,3 +38,11 @@ CONFIG_CMD_SF=y CONFIG_CMD_SAVEENV=y CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_FIT=y +CONFIG_NETDEVICES=y +CONFIG_PHY=y +CONFIG_DM_ETH=y +CONFIG_FTGMAC100=y +CONFIG_PHY_REALTEK=y +CONFIG_CMD_PING=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_MII=y

On Mon, 10 Sep 2018 at 23:56, Cédric Le Goater clg@kaod.org wrote:
diff --git a/arch/arm/dts/ast2500-evb.dts b/arch/arm/dts/ast2500-evb.dts index 609678ff7989..1bd224dacf78 100644 --- a/arch/arm/dts/ast2500-evb.dts +++ b/arch/arm/dts/ast2500-evb.dts
+&mac0 {
status = "okay";
phy-mode = "rgmii";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mac1link_default &pinctrl_mdio1_default>;
+};
+&mac1 {
status = "disabled";
Is there a reason you don't have both enabled? On the eval board I use I can use either.
Cheers,
Joel

On 09/11/2018 02:55 AM, Joel Stanley wrote:
On Mon, 10 Sep 2018 at 23:56, Cédric Le Goater clg@kaod.org wrote:
diff --git a/arch/arm/dts/ast2500-evb.dts b/arch/arm/dts/ast2500-evb.dts index 609678ff7989..1bd224dacf78 100644 --- a/arch/arm/dts/ast2500-evb.dts +++ b/arch/arm/dts/ast2500-evb.dts
+&mac0 {
status = "okay";
phy-mode = "rgmii";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mac1link_default &pinctrl_mdio1_default>;
+};
+&mac1 {
status = "disabled";
Is there a reason you don't have both enabled?
none. we should enable both. I initially disabled mac1 to check how the scu bits where being set by the pinctrl driver in U-Boot.
On the eval board I use I can use either.
yes.
Thanks,
C.

On 10 September 2018 at 07:21, Cédric Le Goater clg@kaod.org wrote:
Signed-off-by: Cédric Le Goater clg@kaod.org
arch/arm/dts/ast2500-evb.dts | 17 +++++++++++++++++ arch/arm/dts/ast2500.dtsi | 4 ++-- configs/evb-ast2500_defconfig | 8 ++++++++ 3 files changed, 27 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/arch/arm/dts/ast2500-evb.dts b/arch/arm/dts/ast2500-evb.dts index 609678ff7989..1bd224dacf78 100644 --- a/arch/arm/dts/ast2500-evb.dts +++ b/arch/arm/dts/ast2500-evb.dts @@ -14,6 +14,7 @@
aliases { spi0 = &fmc;
ethernet0 = &mac0; };
};
@@ -53,3 +54,19 @@ spi-rx-bus-width = <2>; }; };
+&mac0 {
status = "okay";
phy-mode = "rgmii";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mac1link_default &pinctrl_mdio1_default>;
+};
+&mac1 {
status = "disabled";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mac2link_default &pinctrl_mdio2_default>;
+}; diff --git a/arch/arm/dts/ast2500.dtsi b/arch/arm/dts/ast2500.dtsi index de7607aaafff..a1fc5370b109 100644 --- a/arch/arm/dts/ast2500.dtsi +++ b/arch/arm/dts/ast2500.dtsi @@ -108,7 +108,7 @@ };
mac0: ethernet@1e660000 {
compatible = "faraday,ftgmac100";
compatible = "aspeed,ast2500-mac", "faraday,ftgmac100"; reg = <0x1e660000 0x180>; interrupts = <2>; no-hw-checksum;
@@ -116,7 +116,7 @@ };
mac1: ethernet@1e680000 {
compatible = "faraday,ftgmac100";
compatible = "aspeed,ast2500-mac", "faraday,ftgmac100"; reg = <0x1e680000 0x180>; interrupts = <3>; no-hw-checksum;
diff --git a/configs/evb-ast2500_defconfig b/configs/evb-ast2500_defconfig index eb0fe00fb49f..4e65388dab23 100644 --- a/configs/evb-ast2500_defconfig +++ b/configs/evb-ast2500_defconfig @@ -38,3 +38,11 @@ CONFIG_CMD_SF=y CONFIG_CMD_SAVEENV=y CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_FIT=y +CONFIG_NETDEVICES=y +CONFIG_PHY=y +CONFIG_DM_ETH=y +CONFIG_FTGMAC100=y +CONFIG_PHY_REALTEK=y +CONFIG_CMD_PING=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_MII=y
Are these correctly sorted? (make savedevconfig)
Regards, Simon
participants (3)
-
Cédric Le Goater
-
Joel Stanley
-
Simon Glass