]> git.sur5r.net Git - u-boot/blobdiff - drivers/net/xilinx_axi_emac.c
net: xilinx_axi_emac: Add support for non processor mode
[u-boot] / drivers / net / xilinx_axi_emac.c
index 81274ee13bca869567ecc3986f4f90fe8c071f7d..c5feb0e2a96a3484cc800c20dc0be874e1ebe2fe 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/io.h>
 #include <phy.h>
 #include <miiphy.h>
+#include <wait_bit.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -50,6 +51,8 @@ DECLARE_GLOBAL_DATA_PTR;
 
 #define XAE_MDIO_DIV_DFT       29      /* Default MDIO clock divisor */
 
+#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */
+
 /* DMA macros */
 /* Bitmasks of XAXIDMA_CR_OFFSET register */
 #define XAXIDMA_CR_RUNSTOP_MASK        0x00000001 /* Start/stop DMA channel */
@@ -89,6 +92,7 @@ struct axidma_priv {
        phy_interface_t interface;
        struct phy_device *phydev;
        struct mii_dev *bus;
+       u8 eth_hasnobuf;
 };
 
 /* BD descriptors */
@@ -251,7 +255,7 @@ static int axiemac_phy_init(struct udevice *dev)
        }
 
        /* Interface - look at tsec */
-       phydev = phy_connect(priv->bus, priv->phyaddr, dev, 0);
+       phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface);
 
        phydev->supported &= supported;
        phydev->advertising = phydev->supported;
@@ -264,11 +268,29 @@ static int axiemac_phy_init(struct udevice *dev)
 /* Setting axi emac and phy to proper setting */
 static int setup_phy(struct udevice *dev)
 {
-       u32 speed, emmc_reg;
+       u16 temp;
+       u32 speed, emmc_reg, ret;
        struct axidma_priv *priv = dev_get_priv(dev);
        struct axi_regs *regs = priv->iobase;
        struct phy_device *phydev = priv->phydev;
 
+       if (priv->interface == PHY_INTERFACE_MODE_SGMII) {
+               /*
+                * In SGMII cases the isolate bit might set
+                * after DMA and ethernet resets and hence
+                * check and clear if set.
+                */
+               ret = phyread(priv, priv->phyaddr, MII_BMCR, &temp);
+               if (ret)
+                       return 0;
+               if (temp & BMCR_ISOLATE) {
+                       temp &= ~BMCR_ISOLATE;
+                       ret = phywrite(priv, priv->phyaddr, MII_BMCR, temp);
+                       if (ret)
+                               return 0;
+               }
+       }
+
        if (phy_startup(phydev)) {
                printf("axiemac: could not initialize PHY %s\n",
                       phydev->dev->name);
@@ -332,7 +354,7 @@ static void axiemac_stop(struct udevice *dev)
 static int axi_ethernet_init(struct axidma_priv *priv)
 {
        struct axi_regs *regs = priv->iobase;
-       u32 timeout = 200;
+       int err;
 
        /*
         * Check the status of the MgtRdy bit in the interrupt status
@@ -340,19 +362,23 @@ static int axi_ethernet_init(struct axidma_priv *priv)
         * for the Sgmii and 1000BaseX PHY interfaces. No other register reads
         * will be valid until this bit is valid.
         * The bit is always a 1 for all other PHY interfaces.
+        * Interrupt status and enable registers are not available in non
+        * processor mode and hence bypass in this mode
         */
-       while (timeout && (!(in_be32(&regs->is) & XAE_INT_MGTRDY_MASK))) {
-               timeout--;
-               udelay(1);
-       }
-       if (!timeout) {
-               printf("%s: Timeout\n", __func__);
-               return 1;
-       }
+       if (!priv->eth_hasnobuf) {
+               err = wait_for_bit(__func__, (const u32 *)&regs->is,
+                                  XAE_INT_MGTRDY_MASK, true, 200, false);
+               if (err) {
+                       printf("%s: Timeout\n", __func__);
+                       return 1;
+               }
 
-       /* Stop the device and reset HW */
-       /* Disable interrupts */
-       out_be32(&regs->ie, 0);
+               /*
+                * Stop the device and reset HW
+                * Disable interrupts
+                */
+               out_be32(&regs->ie, 0);
+       }
 
        /* Disable the receiver */
        out_be32(&regs->rcw1, in_be32(&regs->rcw1) & ~XAE_RCW1_RX_MASK);
@@ -361,8 +387,10 @@ static int axi_ethernet_init(struct axidma_priv *priv)
         * Stopping the receiver in mid-packet causes a dropped packet
         * indication from HW. Clear it.
         */
-       /* Set the interrupt status register to clear the interrupt */
-       out_be32(&regs->is, XAE_INT_RXRJECT_MASK);
+       if (!priv->eth_hasnobuf) {
+               /* Set the interrupt status register to clear the interrupt */
+               out_be32(&regs->is, XAE_INT_RXRJECT_MASK);
+       }
 
        /* Setup HW */
        /* Set default MDIO divisor */
@@ -562,8 +590,11 @@ static int axiemac_recv(struct udevice *dev, int flags, uchar **packetp)
        temp = in_be32(&priv->dmarx->control);
        temp &= ~XAXIDMA_IRQ_ALL_MASK;
        out_be32(&priv->dmarx->control, temp);
+       if (!priv->eth_hasnobuf)
+               length = rx_bd.app4 & 0xFFFF; /* max length mask */
+       else
+               length = rx_bd.status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
 
-       length = rx_bd.app4 & 0xFFFF; /* max length mask */
 #ifdef DEBUG
        print_buffer(&rxframe, &rxframe[0], 1, length, 16);
 #endif
@@ -630,9 +661,8 @@ static int axi_emac_probe(struct udevice *dev)
        priv->bus->read = axiemac_miiphy_read;
        priv->bus->write = axiemac_miiphy_write;
        priv->bus->priv = priv;
-       strcpy(priv->bus->name, "axi_emac");
 
-       ret = mdio_register(priv->bus);
+       ret = mdio_register_seq(priv->bus, dev->seq);
        if (ret)
                return ret;
 
@@ -665,20 +695,21 @@ static int axi_emac_ofdata_to_platdata(struct udevice *dev)
 {
        struct eth_pdata *pdata = dev_get_platdata(dev);
        struct axidma_priv *priv = dev_get_priv(dev);
+       int node = dev_of_offset(dev);
        int offset = 0;
        const char *phy_mode;
 
-       pdata->iobase = (phys_addr_t)dev_get_addr(dev);
+       pdata->iobase = (phys_addr_t)devfdt_get_addr(dev);
        priv->iobase = (struct axi_regs *)pdata->iobase;
 
-       offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+       offset = fdtdec_lookup_phandle(gd->fdt_blob, node,
                                       "axistream-connected");
        if (offset <= 0) {
                printf("%s: axistream is not found\n", __func__);
                return -EINVAL;
        }
-       priv->dmatx = (struct axidma_reg *)fdtdec_get_int(gd->fdt_blob,
-                                                         offset, "reg", 0);
+       priv->dmatx = (struct axidma_reg *)fdtdec_get_addr(gd->fdt_blob,
+                                                         offset, "reg");
        if (!priv->dmatx) {
                printf("%s: axi_dma register space not found\n", __func__);
                return -EINVAL;
@@ -688,20 +719,22 @@ static int axi_emac_ofdata_to_platdata(struct udevice *dev)
 
        priv->phyaddr = -1;
 
-       offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
-                                      "phy-handle");
+       offset = fdtdec_lookup_phandle(gd->fdt_blob, node, "phy-handle");
        if (offset > 0)
                priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -1);
 
-       phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL);
+       phy_mode = fdt_getprop(gd->fdt_blob, node, "phy-mode", NULL);
        if (phy_mode)
                pdata->phy_interface = phy_get_interface_by_name(phy_mode);
        if (pdata->phy_interface == -1) {
-               debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
+               printf("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
                return -EINVAL;
        }
        priv->interface = pdata->phy_interface;
 
+       priv->eth_hasnobuf = fdtdec_get_bool(gd->fdt_blob, node,
+                                            "xlnx,eth-hasnobuf");
+
        printf("AXI EMAC: %lx, phyaddr %d, interface %s\n", (ulong)priv->iobase,
               priv->phyaddr, phy_string_for_interface(priv->interface));