#include <asm/arch/sys_proto.h>
#include <linux/errno.h>
-DECLARE_GLOBAL_DATA_PTR;
-
/* Bit/mask specification */
#define ZYNQ_GEM_PHYMNTNC_OP_MASK 0x40020000 /* operation mask bits */
#define ZYNQ_GEM_PHYMNTNC_OP_R_MASK 0x20000000 /* read operation */
/* Set with binary 00011000 to use 1536 byte(1*max length frame/buffer) */
#define ZYNQ_GEM_DMACR_RXBUF 0x00180000
+#if defined(CONFIG_PHYS_64BIT)
+# define ZYNQ_GEM_DMA_BUS_WIDTH BIT(30) /* 64 bit bus */
+#else
+# define ZYNQ_GEM_DMA_BUS_WIDTH (0 << 30) /* 32 bit bus */
+#endif
+
#define ZYNQ_GEM_DMACR_INIT (ZYNQ_GEM_DMACR_BLENGTH | \
ZYNQ_GEM_DMACR_RXSIZE | \
ZYNQ_GEM_DMACR_TXSIZE | \
- ZYNQ_GEM_DMACR_RXBUF)
+ ZYNQ_GEM_DMACR_RXBUF | \
+ ZYNQ_GEM_DMA_BUS_WIDTH)
#define ZYNQ_GEM_TSR_DONE 0x00000020 /* Tx done mask */
#define ZYNQ_GEM_PCS_CTL_ANEG_ENBL 0x1000
+#define ZYNQ_GEM_DCFG_DBG6_DMA_64B BIT(23)
+
/* Use MII register 1 (MII status register) to detect PHY */
#define PHY_DETECT_REG 1
u32 stat[STAT_SIZE]; /* 0x100 - Octects transmitted Low reg */
u32 reserved9[20];
u32 pcscntrl;
- u32 reserved7[143];
+ u32 rserved12[36];
+ u32 dcfg6; /* 0x294 Design config reg6 */
+ u32 reserved7[106];
u32 transmit_q1_ptr; /* 0x440 - Transmit priority queue 1 */
u32 reserved8[15];
u32 receive_q1_ptr; /* 0x480 - Receive priority queue 1 */
+ u32 reserved10[17];
+ u32 upper_txqbase; /* 0x4C8 - Upper tx_q base addr */
+ u32 reserved11[2];
+ u32 upper_rxqbase; /* 0x4D4 - Upper rx_q base addr */
};
/* BD descriptors */
struct emac_bd {
u32 addr; /* Next descriptor pointer */
u32 status;
+#if defined(CONFIG_PHYS_64BIT)
+ u32 addr_hi;
+ u32 reserved;
+#endif
};
#define RX_BUF 32
struct clk clk;
u32 max_speed;
bool int_pcs;
+ bool dma_64bit;
};
static int phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum,
ZYNQ_GEM_PHYMNTNC_OP_W_MASK, &data);
}
-static int phy_detection(struct udevice *dev)
-{
- int i;
- u16 phyreg = 0;
- struct zynq_gem_priv *priv = dev->priv;
-
- if (priv->phyaddr != -1) {
- phyread(priv, priv->phyaddr, PHY_DETECT_REG, &phyreg);
- if ((phyreg != 0xFFFF) &&
- ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
- /* Found a valid PHY address */
- debug("Default phy address %d is valid\n",
- priv->phyaddr);
- return 0;
- } else {
- debug("PHY address is not setup correctly %d\n",
- priv->phyaddr);
- priv->phyaddr = -1;
- }
- }
-
- debug("detecting phy address\n");
- if (priv->phyaddr == -1) {
- /* detect the PHY address */
- for (i = 31; i >= 0; i--) {
- phyread(priv, i, PHY_DETECT_REG, &phyreg);
- if ((phyreg != 0xFFFF) &&
- ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
- /* Found a valid PHY address */
- priv->phyaddr = i;
- debug("Found valid phy address, %d\n", i);
- return 0;
- }
- }
- }
- printf("PHY is not detected\n");
- return -1;
-}
-
static int zynq_gem_setup_mac(struct udevice *dev)
{
u32 i, macaddrlow, macaddrhigh;
/* Enable only MDIO bus */
writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, ®s->nwctrl);
- if ((priv->interface != PHY_INTERFACE_MODE_SGMII) &&
- (priv->interface != PHY_INTERFACE_MODE_GMII)) {
- ret = phy_detection(dev);
- if (ret) {
- printf("GEM PHY init failed\n");
- return ret;
- }
- }
-
priv->phydev = phy_connect(priv->bus, priv->phyaddr, dev,
priv->interface);
if (!priv->phydev)
return -ENODEV;
- priv->phydev->supported &= supported | ADVERTISED_Pause |
- ADVERTISED_Asym_Pause;
if (priv->max_speed) {
ret = phy_set_supported(priv->phydev, priv->max_speed);
if (ret)
return ret;
}
+ priv->phydev->supported &= supported | ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause;
+
priv->phydev->advertising = priv->phydev->supported;
priv->phydev->node = priv->phy_of_node;
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];
+ if (readl(®s->dcfg6) & ZYNQ_GEM_DCFG_DBG6_DMA_64B)
+ priv->dma_64bit = true;
+ else
+ priv->dma_64bit = false;
+
+#if defined(CONFIG_PHYS_64BIT)
+ if (!priv->dma_64bit) {
+ printf("ERR: %s: Using 64-bit DMA but HW doesn't support it\n",
+ __func__);
+ return -EINVAL;
+ }
+#else
+ if (priv->dma_64bit)
+ debug("WARN: %s: Not using 64-bit dma even HW supports it\n",
+ __func__);
+#endif
+
if (!priv->init) {
/* Disable all interrupts */
writel(0xFFFFFFFF, ®s->idr);
for (i = 0; i < RX_BUF; i++) {
priv->rx_bd[i].status = 0xF0000000;
priv->rx_bd[i].addr =
- ((ulong)(priv->rxbuffers) +
- (i * PKTSIZE_ALIGN));
- }
+ (lower_32_bits((ulong)(priv->rxbuffers)
+ + (i * PKTSIZE_ALIGN)));
+#if defined(CONFIG_PHYS_64BIT)
+ priv->rx_bd[i].addr_hi =
+ (upper_32_bits((ulong)(priv->rxbuffers)
+ + (i * PKTSIZE_ALIGN)));
+#endif
+ }
/* WRAP bit to last BD */
priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK;
/* Write RxBDs to IP */
- writel((ulong)priv->rx_bd, ®s->rxqbase);
+ writel(lower_32_bits((ulong)priv->rx_bd), ®s->rxqbase);
+#if defined(CONFIG_PHYS_64BIT)
+ writel(upper_32_bits((ulong)priv->rx_bd), ®s->upper_rxqbase);
+#endif
/* Setup for DMA Configuration register */
writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr);
/* Disable the second priority queue */
dummy_tx_bd->addr = 0;
+#if defined(CONFIG_PHYS_64BIT)
+ dummy_tx_bd->addr_hi = 0;
+#endif
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;
+#if defined(CONFIG_PHYS_64BIT)
+ dummy_rx_bd->addr_hi = 0;
+#endif
dummy_rx_bd->status = 0;
writel((ulong)dummy_tx_bd, ®s->transmit_q1_ptr);
break;
}
-#if !defined(CONFIG_ARCH_VERSAL)
ret = clk_set_rate(&priv->clk, clk_rate);
if (IS_ERR_VALUE(ret) && ret != (unsigned long)-ENOSYS) {
dev_err(dev, "failed to set tx clock rate\n");
dev_err(dev, "failed to enable tx clock\n");
return ret;
}
-#else
- debug("requested clk_rate %ld\n", clk_rate);
-#endif
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK |
ZYNQ_GEM_NWCTRL_TXEN_MASK);
static int zynq_gem_send(struct udevice *dev, void *ptr, int len)
{
- u32 addr, size;
+ dma_addr_t addr;
+ u32 size;
struct zynq_gem_priv *priv = dev_get_priv(dev);
struct zynq_gem_regs *regs = priv->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->addr = lower_32_bits((ulong)ptr);
+#if defined(CONFIG_PHYS_64BIT)
+ priv->tx_bd->addr_hi = upper_32_bits((ulong)ptr);
+#endif
priv->tx_bd->status = (len & ZYNQ_GEM_TXBUF_FRMLEN_MASK) |
ZYNQ_GEM_TXBUF_LAST_MASK;
/* Dummy descriptor to mark it as the last in descriptor chain */
current_bd->addr = 0x0;
+#if defined(CONFIG_PHYS_64BIT)
+ current_bd->addr_hi = 0x0;
+#endif
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);
+ writel(lower_32_bits((ulong)priv->tx_bd), ®s->txqbase);
+#if defined(CONFIG_PHYS_64BIT)
+ writel(upper_32_bits((ulong)priv->tx_bd), ®s->upper_txqbase);
+#endif
addr = (ulong) ptr;
addr &= ~(ARCH_DMA_MINALIGN - 1);
size = roundup(len, ARCH_DMA_MINALIGN);
flush_dcache_range(addr, addr + size);
-
- addr = (ulong)priv->rxbuffers;
- addr &= ~(ARCH_DMA_MINALIGN - 1);
- size = roundup((RX_BUF * PKTSIZE_ALIGN), ARCH_DMA_MINALIGN);
- flush_dcache_range(addr, addr + size);
barrier();
/* Start transmit */
static int zynq_gem_recv(struct udevice *dev, int flags, uchar **packetp)
{
int frame_len;
- u32 addr;
+ dma_addr_t addr;
struct zynq_gem_priv *priv = dev_get_priv(dev);
struct emac_bd *current_bd = &priv->rx_bd[priv->rxbd_current];
return -1;
}
+#if defined(CONFIG_PHYS_64BIT)
+ addr = (dma_addr_t)((current_bd->addr & ZYNQ_GEM_RXBUF_ADD_MASK)
+ | ((dma_addr_t)current_bd->addr_hi << 32));
+#else
addr = current_bd->addr & ZYNQ_GEM_RXBUF_ADD_MASK;
+#endif
addr &= ~(ARCH_DMA_MINALIGN - 1);
+
*packetp = (uchar *)(uintptr_t)addr;
+ invalidate_dcache_range(addr, addr + roundup(PKTSIZE_ALIGN, ARCH_DMA_MINALIGN));
+ barrier();
+
return frame_len;
}
return -ENOMEM;
memset(priv->rxbuffers, 0, RX_BUF * PKTSIZE_ALIGN);
+ u32 addr = (ulong)priv->rxbuffers;
+ flush_dcache_range(addr, addr + roundup(RX_BUF * PKTSIZE_ALIGN, ARCH_DMA_MINALIGN));
+ barrier();
/* Align bd_space to MMU_SECTION_SHIFT */
bd_space = memalign(1 << MMU_SECTION_SHIFT, BD_SPACE);
}
static const struct udevice_id zynq_gem_ids[] = {
+ { .compatible = "cdns,versal-gem" },
{ .compatible = "cdns,zynqmp-gem" },
{ .compatible = "cdns,zynq-gem" },
{ .compatible = "cdns,gem" },