[U-Boot] [PATCH v2 2/7] net: Re-add support for the Faraday ftgmac100 controller

Cédric Le Goater clg at kaod.org
Mon Oct 1 08:53:51 UTC 2018


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 at kaod.org>
Reviewed-by: Simon Glass <sjg at chromium.org>
---

 Changes since v1 :

 - improved comments in the code
 - changed the type of 'iobase' to 'struct ftgmac100 *' to remove the
   casts in other routines.
 - replaced the loop in the mdio methods by a call to readl_poll_timeout()
   and fixed the returned value.
 - added a flush cache on the arrays of TX and RX descriptors in
   ftgmac100_start()
 - fixed returned value of 
 - added a timer loop to catch transmit timeouts
 - introduced a clk_bulk
 - improved Kconfig description
 
 drivers/net/ftgmac100.h | 242 ++++++++++++++++++
 drivers/net/ftgmac100.c | 548 ++++++++++++++++++++++++++++++++++++++++
 drivers/net/Kconfig     |  26 ++
 drivers/net/Makefile    |   1 +
 4 files changed, 817 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 at faraday-tech.com>
+ *
+ * (C) Copyright 2010 Andes Technology
+ * Macpaul Lin <macpaul at 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..4596385d68cf
--- /dev/null
+++ b/drivers/net/ftgmac100.c
@@ -0,0 +1,548 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Faraday FTGMAC100 Ethernet
+ *
+ * (C) Copyright 2009 Faraday Technology
+ * Po-Yu Chuang <ratbert at faraday-tech.com>
+ *
+ * (C) Copyright 2010 Andes Technology
+ * Macpaul Lin <macpaul at andestech.com>
+ *
+ * Copyright (C) 2018, IBM Corporation.
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <miiphy.h>
+#include <net.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#include "ftgmac100.h"
+
+/* Min frame ethernet frame size without FCS */
+#define ETH_ZLEN			60
+
+/* Receive Buffer Size Register - HW default is 0x640 */
+#define FTGMAC100_RBSR_DEFAULT		0x640
+
+/* PKTBUFSTX/PKTBUFSRX must both be power of 2 */
+#define PKTBUFSTX			4
+
+/* Timeout for transmit */
+#define FTGMAC100_TX_TIMEOUT_MS		1000
+
+/* Timeout for a mdio read/write operation */
+#define FTGMAC100_MDIO_TIMEOUT_USEC	10000
+
+/*
+ * MDC clock cycle threshold
+ *
+ * 20us * 100 = 2ms > (1 / 2.5Mhz) * 0x34
+ */
+#define MDC_CYCTHR			0x34
+
+/**
+ * struct ftgmac100_data - private data for the FTGMAC100 driver
+ *
+ * @iobase: The base address of the hardware registers
+ * @txdes: The array of transmit descriptors
+ * @rxdes: The array of receive descriptors
+ * @tx_index: Transmit descriptor index in @txdes
+ * @rx_index: Receive descriptor index in @rxdes
+ * @phyaddr: The PHY interface address to use
+ * @phydev: The PHY device backing the MAC
+ * @bus: The mdio bus
+ * @phy_mode: The mode of the PHY interface (rgmii, rmii, ...)
+ * @max_speed: Maximum speed of Ethernet connection supported by MAC
+ * @clks: The bulk of clocks assigned to the device in the DT
+ */
+struct ftgmac100_data {
+	struct ftgmac100 *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;
+
+	struct clk_bulk	clks;
+};
+
+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 = priv->iobase;
+	int phycr;
+	int data;
+	int ret;
+
+	phycr = FTGMAC100_PHYCR_MDC_CYCTHR(MDC_CYCTHR) |
+		FTGMAC100_PHYCR_PHYAD(phy_addr) |
+		FTGMAC100_PHYCR_REGAD(reg_addr) |
+		FTGMAC100_PHYCR_MIIRD;
+	writel(phycr, &ftgmac100->phycr);
+
+	ret = readl_poll_timeout(&ftgmac100->phycr, phycr,
+				 !(phycr & FTGMAC100_PHYCR_MIIRD),
+				 FTGMAC100_MDIO_TIMEOUT_USEC);
+	if (ret) {
+		pr_err("%s: mdio read failed (phy:%d reg:%x)\n",
+		       priv->phydev->dev->name, phy_addr, reg_addr);
+		return ret;
+	}
+
+	data = readl(&ftgmac100->phydata);
+
+	return FTGMAC100_PHYDATA_MIIRDATA(data);
+}
+
+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 = priv->iobase;
+	int phycr;
+	int data;
+	int ret;
+
+	phycr = FTGMAC100_PHYCR_MDC_CYCTHR(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);
+
+	ret = readl_poll_timeout(&ftgmac100->phycr, phycr,
+				 !(phycr & FTGMAC100_PHYCR_MIIWR),
+				 FTGMAC100_MDIO_TIMEOUT_USEC);
+	if (ret) {
+		pr_err("%s: mdio write failed (phy:%d reg:%x)\n",
+		       priv->phydev->dev->name, phy_addr, reg_addr);
+	}
+
+	return ret;
+}
+
+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 = priv->iobase;
+	struct phy_device *phydev = priv->phydev;
+	u32 maccr;
+
+	if (!phydev->link) {
+		dev_err(phydev->dev, "No link\n");
+		return -EREMOTEIO;
+	}
+
+	/* 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);
+	if (!phydev)
+		return -ENODEV;
+
+	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 = 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 = 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 = 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 = priv->iobase;
+	struct phy_device *phydev = priv->phydev;
+	unsigned int maccr;
+	ulong start, end;
+	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;
+
+	start = (ulong)&priv->txdes[0];
+	end = start + roundup(sizeof(priv->txdes), ARCH_DMA_MINALIGN);
+	flush_dcache_range(start, end);
+
+	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;
+
+	start = (ulong)&priv->rxdes[0];
+	end = start + roundup(sizeof(priv->rxdes), ARCH_DMA_MINALIGN);
+	flush_dcache_range(start, end);
+
+	/* 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(FTGMAC100_RBSR_DEFAULT), &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 = 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;
+	ulong start;
+
+	invalidate_dcache_range(des_start, des_end);
+
+	if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
+		dev_err(dev, "no TX descriptor available\n");
+		return -EPERM;
+	}
+
+	debug("%s(%x, %x)\n", __func__, (int)packet, length);
+
+	length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
+
+	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 segment 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);
+
+	/* Start transmit */
+	writel(1, &ftgmac100->txpd);
+
+	/* Wait until packet is transmitted */
+	start = get_timer(0);
+	while (get_timer(start) < FTGMAC100_TX_TIMEOUT_MS) {
+		invalidate_dcache_range(des_start, des_end);
+		if (!(curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN))
+			break;
+		udelay(10);
+	}
+
+	if (get_timer(start) >= FTGMAC100_TX_TIMEOUT_MS) {
+		dev_err(dev, "transmit timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	debug("%s(): packet sent\n", __func__);
+
+	/* Move to next descriptor */
+	priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
+
+	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);
+	struct ftgmac100_data *priv = dev_get_priv(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 clk_get_bulk(dev, &priv->clks);
+}
+
+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 = (struct ftgmac100 *)pdata->iobase;
+	priv->phy_mode = pdata->phy_interface;
+	priv->max_speed = pdata->max_speed;
+	priv->phyaddr = 0;
+
+	ret = clk_enable_bulk(&priv->clks);
+	if (ret)
+		goto out;
+
+	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:
+	if (ret)
+		clk_release_bulk(&priv->clks);
+
+	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);
+	clk_release_bulk(&priv->clks);
+
+	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..3efdc5dc2fae 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -186,6 +186,32 @@ config FTMAC100
 	help
 	  This MAC is present in Andestech SoCs.
 
+config FTGMAC100
+	bool "Ftgmac100 Ethernet Support"
+	depends on DM_ETH
+	select PHYLIB
+	help
+	  This driver supports the Faraday's FTGMAC100 Gigabit SoC
+	  Ethernet controller that can be found on Aspeed SoCs (which
+	  include NCSI).
+
+	  It is fully compliant with IEEE 802.3 specification for
+	  10/100 Mbps Ethernet and IEEE 802.3z specification for 1000
+	  Mbps Ethernet and includes Reduced Media Independent
+	  Interface (RMII) and Reduced Gigabit Media Independent
+	  Interface (RGMII) interfaces. It adopts an AHB bus interface
+	  and integrates a link list DMA engine with direct M-Bus
+	  accesses for transmitting and receiving packets. It has
+	  independent TX/RX fifos, supports half and full duplex (1000
+	  Mbps mode only supports full duplex), flow control for full
+	  duplex and backpressure for half duplex.
+
+	  The FTGMAC100 also implements IP, TCP, UDP checksum offloads
+	  and supports IEEE 802.1Q VLAN tag insertion and removal. It
+	  offers high-priority transmit queue for QoS and CoS
+	  applications.
+
+
 config MVGBE
 	bool "Marvell Orion5x/Kirkwood network interface support"
 	depends on KIRKWOOD || ORION5X
diff --git a/drivers/net/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



More information about the U-Boot mailing list