From 721aed79126ba954028137eabe71678523a8b157 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Fri, 25 Sep 2015 23:46:08 -0700 Subject: net: phy: Add support for Texas Instruments DP83867 Code is taken from Linux kernel driver (v4.2). Signed-off-by: Edgar E. Iglesias Signed-off-by: Michal Simek Reviewed-by: Tom Rini Acked-by: Joe Hershberger --- drivers/net/phy/Makefile | 1 + drivers/net/phy/phy.c | 3 + drivers/net/phy/ti.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 drivers/net/phy/ti.c (limited to 'drivers') diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index d096db87a27..9e4d4927e67 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -24,4 +24,5 @@ obj-$(CONFIG_PHY_NATSEMI) += natsemi.o obj-$(CONFIG_PHY_REALTEK) += realtek.o obj-$(CONFIG_PHY_SMSC) += smsc.o obj-$(CONFIG_PHY_TERANETICS) += teranetics.o +obj-$(CONFIG_PHY_TI) += ti.o obj-$(CONFIG_PHY_VITESSE) += vitesse.o diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index d7364ffc34f..5633ec2402b 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -484,6 +484,9 @@ int phy_init(void) #ifdef CONFIG_PHY_TERANETICS phy_teranetics_init(); #endif +#ifdef CONFIG_PHY_TI + phy_ti_init(); +#endif #ifdef CONFIG_PHY_VITESSE phy_vitesse_init(); #endif diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/ti.c new file mode 100644 index 00000000000..541a57f9802 --- /dev/null +++ b/drivers/net/phy/ti.c @@ -0,0 +1,200 @@ +/* + * TI PHY drivers + * + * SPDX-License-Identifier: GPL-2.0 + * + */ +#include +#include + +/* TI DP83867 */ +#define DP83867_DEVADDR 0x1f + +#define MII_DP83867_PHYCTRL 0x10 +#define MII_DP83867_MICR 0x12 +#define DP83867_CTRL 0x1f + +/* Extended Registers */ +#define DP83867_RGMIICTL 0x0032 +#define DP83867_RGMIIDCTL 0x0086 + +#define DP83867_SW_RESET BIT(15) +#define DP83867_SW_RESTART BIT(14) + +/* MICR Interrupt bits */ +#define MII_DP83867_MICR_AN_ERR_INT_EN BIT(15) +#define MII_DP83867_MICR_SPEED_CHNG_INT_EN BIT(14) +#define MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN BIT(13) +#define MII_DP83867_MICR_PAGE_RXD_INT_EN BIT(12) +#define MII_DP83867_MICR_AUTONEG_COMP_INT_EN BIT(11) +#define MII_DP83867_MICR_LINK_STS_CHNG_INT_EN BIT(10) +#define MII_DP83867_MICR_FALSE_CARRIER_INT_EN BIT(8) +#define MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN BIT(4) +#define MII_DP83867_MICR_WOL_INT_EN BIT(3) +#define MII_DP83867_MICR_XGMII_ERR_INT_EN BIT(2) +#define MII_DP83867_MICR_POL_CHNG_INT_EN BIT(1) +#define MII_DP83867_MICR_JABBER_INT_EN BIT(0) + +/* RGMIICTL bits */ +#define DP83867_RGMII_TX_CLK_DELAY_EN BIT(1) +#define DP83867_RGMII_RX_CLK_DELAY_EN BIT(0) + +/* PHY CTRL bits */ +#define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14 + +/* RGMIIDCTL bits */ +#define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4 + +#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */ +#define MII_MMD_DATA 0x0e /* MMD Access Data Register */ + +/* MMD Access Control register fields */ +#define MII_MMD_CTRL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/ +#define MII_MMD_CTRL_ADDR 0x0000 /* Address */ +#define MII_MMD_CTRL_NOINCR 0x4000 /* no post increment */ +#define MII_MMD_CTRL_INCR_RDWT 0x8000 /* post increment on reads & writes */ +#define MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */ + +/** + * phy_read_mmd_indirect - reads data from the MMD registers + * @phydev: The PHY device bus + * @prtad: MMD Address + * @devad: MMD DEVAD + * @addr: PHY address on the MII bus + * + * Description: it reads data from the MMD registers (clause 22 to access to + * clause 45) of the specified phy address. + * To read these registers we have: + * 1) Write reg 13 // DEVAD + * 2) Write reg 14 // MMD Address + * 3) Write reg 13 // MMD Data Command for MMD DEVAD + * 3) Read reg 14 // Read MMD data + */ +int phy_read_mmd_indirect(struct phy_device *phydev, int prtad, + int devad, int addr) +{ + int value = -1; + + /* Write the desired MMD Devad */ + phy_write(phydev, addr, MII_MMD_CTRL, devad); + + /* Write the desired MMD register address */ + phy_write(phydev, addr, MII_MMD_DATA, prtad); + + /* Select the Function : DATA with no post increment */ + phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR)); + + /* Read the content of the MMD's selected register */ + value = phy_read(phydev, addr, MII_MMD_DATA); + return value; +} + +/** + * phy_write_mmd_indirect - writes data to the MMD registers + * @phydev: The PHY device + * @prtad: MMD Address + * @devad: MMD DEVAD + * @addr: PHY address on the MII bus + * @data: data to write in the MMD register + * + * Description: Write data from the MMD registers of the specified + * phy address. + * To write these registers we have: + * 1) Write reg 13 // DEVAD + * 2) Write reg 14 // MMD Address + * 3) Write reg 13 // MMD Data Command for MMD DEVAD + * 3) Write reg 14 // Write MMD data + */ +void phy_write_mmd_indirect(struct phy_device *phydev, int prtad, + int devad, int addr, u32 data) +{ + /* Write the desired MMD Devad */ + phy_write(phydev, addr, MII_MMD_CTRL, devad); + + /* Write the desired MMD register address */ + phy_write(phydev, addr, MII_MMD_DATA, prtad); + + /* Select the Function : DATA with no post increment */ + phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR)); + + /* Write the data into MMD's selected register */ + phy_write(phydev, addr, MII_MMD_DATA, data); +} + +/** + * phy_interface_is_rgmii - Convenience function for testing if a PHY interface + * is RGMII (all variants) + * @phydev: the phy_device struct + */ +static inline bool phy_interface_is_rgmii(struct phy_device *phydev) +{ + return phydev->interface >= PHY_INTERFACE_MODE_RGMII && + phydev->interface <= PHY_INTERFACE_MODE_RGMII_TXID; +} + +/* User setting - can be taken from DTS */ +#define RX_ID_DELAY 8 +#define TX_ID_DELAY 0xa +#define FIFO_DEPTH 1 + +static int dp83867_config(struct phy_device *phydev) +{ + unsigned int val, delay; + int ret; + + /* Restart the PHY. */ + val = phy_read(phydev, MDIO_DEVAD_NONE, DP83867_CTRL); + phy_write(phydev, MDIO_DEVAD_NONE, DP83867_CTRL, + val | DP83867_SW_RESTART); + + if (phy_interface_is_rgmii(phydev)) { + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL, + (FIFO_DEPTH << DP83867_PHYCR_FIFO_DEPTH_SHIFT)); + if (ret) + return ret; + } + + if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) && + (phydev->interface <= PHY_INTERFACE_MODE_RGMII_RXID)) { + val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL, + DP83867_DEVADDR, phydev->addr); + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + val |= (DP83867_RGMII_TX_CLK_DELAY_EN | + DP83867_RGMII_RX_CLK_DELAY_EN); + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + val |= DP83867_RGMII_TX_CLK_DELAY_EN; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) + val |= DP83867_RGMII_RX_CLK_DELAY_EN; + + phy_write_mmd_indirect(phydev, DP83867_RGMIICTL, + DP83867_DEVADDR, phydev->addr, val); + + delay = (RX_ID_DELAY | + (TX_ID_DELAY << DP83867_RGMII_TX_CLK_DELAY_SHIFT)); + + phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL, + DP83867_DEVADDR, phydev->addr, delay); + } + + genphy_config_aneg(phydev); + return 0; +} + +static struct phy_driver DP83867_driver = { + .name = "TI DP83867", + .uid = 0x2000a231, + .mask = 0xfffffff0, + .features = PHY_GBIT_FEATURES, + .config = &dp83867_config, + .startup = &genphy_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_ti_init(void) +{ + phy_register(&DP83867_driver); + return 0; +} -- cgit v1.3.1 From 198e9a4fe99a9c2174f1ee332d602b3c94b4a8e6 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 7 Oct 2015 16:34:51 +0200 Subject: net: zynq: Add debug message to phyread/phywrite Add debug messages to phyread/write to help with PHY debug. Signed-off-by: Michal Simek Acked-by: Joe Hershberger --- drivers/net/zynq_gem.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 5637a0d083c..e3af8dc930f 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -208,12 +208,23 @@ static u32 phy_setup_op(struct eth_device *dev, u32 phy_addr, u32 regnum, static u32 phyread(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 *val) { - return phy_setup_op(dev, phy_addr, regnum, + u32 ret; + + ret = phy_setup_op(dev, phy_addr, regnum, ZYNQ_GEM_PHYMNTNC_OP_R_MASK, val); + + if (!ret) + debug("%s: phy_addr %d, regnum 0x%x, val 0x%x\n", __func__, + phy_addr, regnum, *val); + + return ret; } static u32 phywrite(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 data) { + debug("%s: phy_addr %d, regnum 0x%x, data 0x%x\n", __func__, phy_addr, + regnum, data); + return phy_setup_op(dev, phy_addr, regnum, ZYNQ_GEM_PHYMNTNC_OP_W_MASK, &data); } -- cgit v1.3.1 From 16ce6de87ecddc73943cd192195bb20148e80622 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 7 Oct 2015 16:42:56 +0200 Subject: net: zynq: Add support for different PHY interface types MII is setup by default for all cases. The most of boards are using RGMII but PHY drivers are not doing any specific setting that's why MII setting was working fine. With TI DP83867 is necessary to setup paramaters based on interface type. Use one setting per board for it which is something what will be removed when driver is moved to DM. Signed-off-by: Michal Simek Acked-by: Joe Hershberger --- drivers/net/zynq_gem.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index e3af8dc930f..ac3dd8b70fe 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -156,6 +156,7 @@ struct zynq_gem_priv { int phyaddr; u32 emio; int init; + phy_interface_t interface; struct phy_device *phydev; struct mii_dev *bus; }; @@ -359,7 +360,7 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) /* interface - look at tsec */ phydev = phy_connect(priv->bus, priv->phyaddr, dev, - PHY_INTERFACE_MODE_MII); + priv->interface); phydev->supported = supported | ADVERTISED_Pause | ADVERTISED_Asym_Pause; @@ -546,6 +547,12 @@ int zynq_gem_initialize(bd_t *bis, phys_addr_t base_addr, priv->phyaddr = phy_addr; priv->emio = emio; +#ifndef CONFIG_ZYNQ_GEM_INTERFACE + priv->interface = PHY_INTERFACE_MODE_MII; +#else + priv->interface = CONFIG_ZYNQ_GEM_INTERFACE; +#endif + sprintf(dev->name, "Gem.%lx", base_addr); dev->iobase = base_addr; -- cgit v1.3.1 From 97a51a036336c82d206e35b1235c679241db72a7 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 5 Oct 2015 11:49:43 +0200 Subject: net: zynq: Extend register description with offsets Extend comments with register offset to help with debuggging. Signed-off-by: Michal Simek Acked-by: Joe Hershberger --- drivers/net/zynq_gem.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index ac3dd8b70fe..fae61a0fa07 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -108,28 +108,28 @@ /* Device registers */ struct zynq_gem_regs { - u32 nwctrl; /* Network Control reg */ - u32 nwcfg; /* Network Config reg */ - u32 nwsr; /* Network Status reg */ + u32 nwctrl; /* 0x0 - Network Control reg */ + u32 nwcfg; /* 0x4 - Network Config reg */ + u32 nwsr; /* 0x8 - Network Status reg */ u32 reserved1; - u32 dmacr; /* DMA Control reg */ - u32 txsr; /* TX Status reg */ - u32 rxqbase; /* RX Q Base address reg */ - u32 txqbase; /* TX Q Base address reg */ - u32 rxsr; /* RX Status reg */ + u32 dmacr; /* 0x10 - DMA Control reg */ + u32 txsr; /* 0x14 - TX Status reg */ + u32 rxqbase; /* 0x18 - RX Q Base address reg */ + u32 txqbase; /* 0x1c - TX Q Base address reg */ + u32 rxsr; /* 0x20 - RX Status reg */ u32 reserved2[2]; - u32 idr; /* Interrupt Disable reg */ + u32 idr; /* 0x2c - Interrupt Disable reg */ u32 reserved3; - u32 phymntnc; /* Phy Maintaince reg */ + u32 phymntnc; /* 0x34 - Phy Maintaince reg */ u32 reserved4[18]; - u32 hashl; /* Hash Low address reg */ - u32 hashh; /* Hash High address reg */ + u32 hashl; /* 0x80 - Hash Low address reg */ + u32 hashh; /* 0x84 - Hash High address reg */ #define LADDR_LOW 0 #define LADDR_HIGH 1 - u32 laddr[4][LADDR_HIGH + 1]; /* Specific1 addr low/high reg */ - u32 match[4]; /* Type ID1 Match reg */ + u32 laddr[4][LADDR_HIGH + 1]; /* 0x8c - Specific1 addr low/high reg */ + u32 match[4]; /* 0xa8 - Type ID1 Match reg */ u32 reserved6[18]; - u32 stat[44]; /* Octects transmitted Low reg - stat start */ + u32 stat[44]; /* 0x100 - Octects transmitted Low reg - stat start */ }; /* BD descriptors */ -- cgit v1.3.1 From 0ebf40417df79ca0b73fa3fca0f6d13f47c5b530 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 5 Oct 2015 12:49:48 +0200 Subject: net: zynq: Fix clearing statistic Previous loop was completely bogus. Iterration should go just over statistic counters. Signed-off-by: Michal Simek Acked-by: Joe Hershberger --- drivers/net/zynq_gem.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index fae61a0fa07..41ac8295dbe 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -129,7 +129,8 @@ struct zynq_gem_regs { u32 laddr[4][LADDR_HIGH + 1]; /* 0x8c - Specific1 addr low/high reg */ u32 match[4]; /* 0xa8 - Type ID1 Match reg */ u32 reserved6[18]; - u32 stat[44]; /* 0x100 - Octects transmitted Low reg - stat start */ +#define STAT_SIZE 44 + u32 stat[STAT_SIZE]; /* 0x100 - Octects transmitted Low reg */ }; /* BD descriptors */ @@ -301,8 +302,6 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) u32 i; unsigned long clk_rate = 0; struct phy_device *phydev; - const u32 stat_size = (sizeof(struct zynq_gem_regs) - - offsetof(struct zynq_gem_regs, stat)) / 4; struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; struct zynq_gem_priv *priv = dev->priv; const u32 supported = SUPPORTED_10baseT_Half | @@ -330,7 +329,7 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) writel(0x0, ®s->hashh); /* Clear all counters */ - for (i = 0; i <= stat_size; i++) + for (i = 0; i < STAT_SIZE; i++) readl(®s->stat[i]); /* Setup RxBD space */ -- cgit v1.3.1 From ff4758789e969d1d0a23a0feb8edcab4dffc1250 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 17 Aug 2015 09:45:53 +0200 Subject: net: zynq: Allocate BD_SPACE in connection to RX_BUF BD_SEPRN_SPACE should not have hard coded value and it will be calculated based on the number of buffer descriptors that we would like to use. Signed-off-by: Michal Simek Acked-by: Joe Hershberger --- drivers/net/zynq_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 41ac8295dbe..875738abb25 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -145,7 +145,7 @@ struct emac_bd { */ #define BD_SPACE 0x100000 /* BD separation space */ -#define BD_SEPRN_SPACE 64 +#define BD_SEPRN_SPACE (RX_BUF * sizeof(struct emac_bd)) /* Initialized, rxbd_current, rx_first_buf must be 0 after init */ struct zynq_gem_priv { -- cgit v1.3.1 From 45c0774151183d04bc3bc5ecce96160dc736f96e Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 17 Aug 2015 09:50:09 +0200 Subject: net: zynq: Setup BD when structures are filled Fix incorrect sequence in BD handling. Signed-off-by: Michal Simek Acked-by: Joe Hershberger --- drivers/net/zynq_gem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 875738abb25..b8686f3e236 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -406,9 +406,6 @@ static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) struct zynq_gem_priv *priv = dev->priv; struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; - /* setup BD */ - writel((ulong)priv->tx_bd, ®s->txqbase); - /* Setup Tx BD */ memset(priv->tx_bd, 0, sizeof(struct emac_bd)); @@ -417,6 +414,9 @@ static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) ZYNQ_GEM_TXBUF_LAST_MASK | ZYNQ_GEM_TXBUF_WRAP_MASK; + /* setup BD */ + writel((ulong)priv->tx_bd, ®s->txqbase); + addr = (ulong) ptr; addr &= ~(ARCH_DMA_MINALIGN - 1); size = roundup(len, ARCH_DMA_MINALIGN); -- cgit v1.3.1 From 081dc2fa78e4a2760ffd713292da430e9290a662 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 17 Aug 2015 09:51:34 +0200 Subject: net: zynq: Do not report TX underrun Signed-off-by: Michal Simek Acked-by: Joe Hershberger --- drivers/net/zynq_gem.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index b8686f3e236..946dc1b6a9f 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -432,8 +432,6 @@ static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_STARTTX_MASK); /* Read TX BD status */ - if (priv->tx_bd->status & ZYNQ_GEM_TXBUF_UNDERRUN) - printf("TX underrun\n"); if (priv->tx_bd->status & ZYNQ_GEM_TXBUF_EXHAUSTED) printf("TX buffers exhausted in mid frame\n"); -- cgit v1.3.1 From 23a598f719811fbb1807ed377382fef019b9b3cd Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 17 Aug 2015 09:58:54 +0200 Subject: net: zynq: Add dummy packet to fix packet duplication issue Target is duplicating packets. IP prefetches another BD and process it when the first one is sent. Adding one dummy BD to the chain fix the problem with packet duplication. Signed-off-by: Michal Simek Acked-by: Joe Hershberger --- drivers/net/zynq_gem.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 946dc1b6a9f..1b5b6fd942a 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -46,6 +46,7 @@ /* Wrap bit, last descriptor */ #define ZYNQ_GEM_TXBUF_WRAP_MASK 0x40000000 #define ZYNQ_GEM_TXBUF_LAST_MASK 0x00008000 /* Last buffer */ +#define ZYNQ_GEM_TXBUF_USED_MASK 0x80000000 /* Used by Hw */ #define ZYNQ_GEM_NWCTRL_TXEN_MASK 0x00000008 /* Enable transmit */ #define ZYNQ_GEM_NWCTRL_RXEN_MASK 0x00000004 /* Enable receive */ @@ -405,14 +406,19 @@ static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) u32 addr, size; struct zynq_gem_priv *priv = dev->priv; struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; + struct emac_bd *current_bd = &priv->tx_bd[1]; /* Setup Tx BD */ memset(priv->tx_bd, 0, sizeof(struct emac_bd)); priv->tx_bd->addr = (ulong)ptr; priv->tx_bd->status = (len & ZYNQ_GEM_TXBUF_FRMLEN_MASK) | - ZYNQ_GEM_TXBUF_LAST_MASK | - ZYNQ_GEM_TXBUF_WRAP_MASK; + ZYNQ_GEM_TXBUF_LAST_MASK; + /* Dummy descriptor to mark it as the last in descriptor chain */ + current_bd->addr = 0x0; + current_bd->status = ZYNQ_GEM_TXBUF_WRAP_MASK | + ZYNQ_GEM_TXBUF_LAST_MASK| + ZYNQ_GEM_TXBUF_USED_MASK; /* setup BD */ writel((ulong)priv->tx_bd, ®s->txqbase); -- cgit v1.3.1 From 603ff0081af96a1694f0d86e1dccbc118871f27f Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Fri, 25 Sep 2015 23:50:07 -0700 Subject: net: zynq: Disable secondary queues Zynq has no priority queues. ZynqMP has one priority queue and this change is required to get ethernet working. This patch was not needed on ep108 for uknown reason even it should be used. Tested on Zynq and ZynqMP. Signed-off-by: Edgar E. Iglesias Signed-off-by: Michal Simek --- drivers/net/zynq_gem.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 1b5b6fd942a..027b49bf7b2 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -132,6 +132,10 @@ struct zynq_gem_regs { u32 reserved6[18]; #define STAT_SIZE 44 u32 stat[STAT_SIZE]; /* 0x100 - Octects transmitted Low reg */ + u32 reserved7[164]; + u32 transmit_q1_ptr; /* 0x440 - Transmit priority queue 1 */ + u32 reserved8[15]; + u32 receive_q1_ptr; /* 0x480 - Receive priority queue 1 */ }; /* BD descriptors */ @@ -148,6 +152,9 @@ struct emac_bd { /* BD separation space */ #define BD_SEPRN_SPACE (RX_BUF * sizeof(struct emac_bd)) +/* Setup the first free TX descriptor */ +#define TX_FREE_DESC 2 + /* Initialized, rxbd_current, rx_first_buf must be 0 after init */ struct zynq_gem_priv { struct emac_bd *tx_bd; @@ -305,6 +312,8 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) struct phy_device *phydev; struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; struct zynq_gem_priv *priv = dev->priv; + struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC]; + struct emac_bd *dummy_rx_bd = &priv->tx_bd[TX_FREE_DESC + 2]; const u32 supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | @@ -353,6 +362,23 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) /* Setup for Network Control register, MDIO, Rx and Tx enable */ setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK); + /* Disable the second priority queue */ + dummy_tx_bd->addr = 0; + dummy_tx_bd->status = ZYNQ_GEM_TXBUF_WRAP_MASK | + ZYNQ_GEM_TXBUF_LAST_MASK| + ZYNQ_GEM_TXBUF_USED_MASK; + + dummy_rx_bd->addr = ZYNQ_GEM_RXBUF_WRAP_MASK | + ZYNQ_GEM_RXBUF_NEW_MASK; + dummy_rx_bd->status = 0; + flush_dcache_range((ulong)&dummy_tx_bd, (ulong)&dummy_tx_bd + + sizeof(dummy_tx_bd)); + flush_dcache_range((ulong)&dummy_rx_bd, (ulong)&dummy_rx_bd + + sizeof(dummy_rx_bd)); + + writel((ulong)dummy_tx_bd, ®s->transmit_q1_ptr); + writel((ulong)dummy_rx_bd, ®s->receive_q1_ptr); + priv->init++; } -- cgit v1.3.1 From e4d2318adbcff084dbbed2f84e4a51da09a1b21b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 17 Aug 2015 09:57:46 +0200 Subject: net: zynq: Wait till packet is sent Wait till BD is processed to ensure that packet was sent successfully. Signed-off-by: Michal Simek --- drivers/net/zynq_gem.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 027b49bf7b2..56651e94bb8 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -23,6 +23,7 @@ #include #include #include +#include #if !defined(CONFIG_PHYLIB) # error XILINX_GEM_ETHERNET requires PHYLIB @@ -86,6 +87,8 @@ ZYNQ_GEM_DMACR_TXSIZE | \ ZYNQ_GEM_DMACR_RXBUF) +#define ZYNQ_GEM_TSR_DONE 0x00000020 /* Tx done mask */ + /* Use MII register 1 (MII status register) to detect PHY */ #define PHY_DETECT_REG 1 @@ -427,6 +430,33 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) return 0; } +static int wait_for_bit(const char *func, u32 *reg, const u32 mask, + bool set, unsigned int timeout) +{ + u32 val; + unsigned long start = get_timer(0); + + while (1) { + val = readl(reg); + + if (!set) + val = ~val; + + if ((val & mask) == mask) + return 0; + + if (get_timer(start) > timeout) + break; + + udelay(1); + } + + debug("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n", + func, reg, mask, set); + + return -ETIMEDOUT; +} + static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) { u32 addr, size; @@ -467,7 +497,8 @@ static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) if (priv->tx_bd->status & ZYNQ_GEM_TXBUF_EXHAUSTED) printf("TX buffers exhausted in mid frame\n"); - return 0; + return wait_for_bit(__func__, ®s->txsr, ZYNQ_GEM_TSR_DONE, + true, 20000); } /* Do not check frame_recd flag in rx_status register 0x20 - just poll BD */ -- cgit v1.3.1 From 242b15476c94752494670a3e419e639d2df08dfd Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 8 Sep 2015 16:55:42 +0200 Subject: net: zynq: Fix mdc clock division setting for 100Mbit/s Using set and clear macro is incorrect because it is not overwritting origin mdc clock division setup. For example origin setup is 8(0b001) and new setup is 64(0b100) which means 0b101 is setup which is 96 divider. Using writel to rewrite all setting like for 1000Mbit/s case. Signed-off-by: Michal Simek Acked-by: Joe Hershberger --- drivers/net/zynq_gem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 56651e94bb8..9d69c8408da 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -410,8 +410,8 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) clk_rate = ZYNQ_GEM_FREQUENCY_1000; break; case SPEED_100: - clrsetbits_le32(®s->nwcfg, ZYNQ_GEM_NWCFG_SPEED1000, - ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED100); + writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED100, + ®s->nwcfg); clk_rate = ZYNQ_GEM_FREQUENCY_100; break; case SPEED_10: -- cgit v1.3.1 From 2889659a5510558f55c50c51a29bd701792536fd Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 8 Sep 2015 16:54:39 +0200 Subject: net: zynq: Remove unused MDCCLKDIV2 macro Driver cleanup. Signed-off-by: Michal Simek Acked-by: Joe Hershberger --- drivers/net/zynq_gem.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 9d69c8408da..4db3ed4339a 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -59,7 +59,6 @@ #define ZYNQ_GEM_NWCFG_FDEN 0x000000002 /* Full Duplex mode */ #define ZYNQ_GEM_NWCFG_FSREM 0x000020000 /* FCS removal */ #define ZYNQ_GEM_NWCFG_MDCCLKDIV 0x000080000 /* Div pclk by 32, 80MHz */ -#define ZYNQ_GEM_NWCFG_MDCCLKDIV2 0x0000c0000 /* Div pclk by 48, 120MHz */ #ifdef CONFIG_ARM64 # define ZYNQ_GEM_DBUS_WIDTH (1 << 21) /* 64 bit bus */ -- cgit v1.3.1 From 6777f3863044bf58082a3fdd67a890f2b5080e14 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 8 Sep 2015 17:07:01 +0200 Subject: net: zynq: Fix MDC setting for zynq Based on spec: "MDC must not exceed 2.5 MHz (MDC is only active during MDIO read and write operations)" Zynq is running on 111MHz. Current setting is 32 which is 111/32=3.47 which is above of 2.5MHz. Using 48 divider will give us correct setting according spec (111/48=2.31). Signed-off-by: Michal Simek Acked-by: Joe Hershberger --- drivers/net/zynq_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 4db3ed4339a..858093f0d7e 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -58,7 +58,7 @@ #define ZYNQ_GEM_NWCFG_SPEED1000 0x000000400 /* 1Gbps operation */ #define ZYNQ_GEM_NWCFG_FDEN 0x000000002 /* Full Duplex mode */ #define ZYNQ_GEM_NWCFG_FSREM 0x000020000 /* FCS removal */ -#define ZYNQ_GEM_NWCFG_MDCCLKDIV 0x000080000 /* Div pclk by 32, 80MHz */ +#define ZYNQ_GEM_NWCFG_MDCCLKDIV 0x0000c0000 /* Div pclk by 48, max 120MHz */ #ifdef CONFIG_ARM64 # define ZYNQ_GEM_DBUS_WIDTH (1 << 21) /* 64 bit bus */ -- cgit v1.3.1 From f3bd72801aade1eb74e153bfa57c26f327571475 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 29 Sep 2015 01:27:13 +0200 Subject: zynq: sdhci: Define max clock by macro zc1571 with silicon can operate on 200MHz maximum frequency. Setup this frequency by default and fix setting for ep108. Signed-off-by: Michal Simek --- drivers/mmc/zynq_sdhci.c | 2 +- include/configs/xilinx_zynqmp.h | 3 +++ include/configs/xilinx_zynqmp_ep.h | 1 + include/configs/zynq-common.h | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index c69f5d4e2d4..e169b774932 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -29,7 +29,7 @@ int zynq_sdhci_init(phys_addr_t regbase) SDHCI_QUIRK_BROKEN_R1B; host->version = sdhci_readw(host, SDHCI_HOST_VERSION); - add_sdhci(host, 52000000, 52000000 >> 9); + add_sdhci(host, CONFIG_ZYNQ_SDHCI_MAX_FREQ, 52000000 >> 9); return 0; } diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h index 574f788500b..e990512083e 100644 --- a/include/configs/xilinx_zynqmp.h +++ b/include/configs/xilinx_zynqmp.h @@ -94,6 +94,9 @@ # define CONFIG_SDHCI # define CONFIG_ZYNQ_SDHCI # define CONFIG_CMD_MMC +# ifndef CONFIG_ZYNQ_SDHCI_MAX_FREQ +# define CONFIG_ZYNQ_SDHCI_MAX_FREQ 200000000 +# endif #endif #if defined(CONFIG_ZYNQ_SDHCI) diff --git a/include/configs/xilinx_zynqmp_ep.h b/include/configs/xilinx_zynqmp_ep.h index ed6023a7bfa..8bdb5c9c6d5 100644 --- a/include/configs/xilinx_zynqmp_ep.h +++ b/include/configs/xilinx_zynqmp_ep.h @@ -19,6 +19,7 @@ #define CONFIG_ZYNQ_GEM_PHY_ADDR0 7 #define CONFIG_ZYNQ_SDHCI0 +#define CONFIG_ZYNQ_SDHCI_MAX_FREQ 52000000 #define CONFIG_ZYNQ_I2C0 #define CONFIG_SYS_I2C_ZYNQ #define CONFIG_ZYNQ_EEPROM diff --git a/include/configs/zynq-common.h b/include/configs/zynq-common.h index f33a3bcc68a..d10f1ddacaf 100644 --- a/include/configs/zynq-common.h +++ b/include/configs/zynq-common.h @@ -105,6 +105,7 @@ # define CONFIG_SDHCI # define CONFIG_ZYNQ_SDHCI # define CONFIG_CMD_MMC +# define CONFIG_ZYNQ_SDHCI_MAX_FREQ 52000000 #endif #ifdef CONFIG_ZYNQ_USB -- cgit v1.3.1