]> 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 51c74266637cc9c5747c289f07ab3adf58c1ecb3..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 */
@@ -350,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
@@ -358,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);
@@ -379,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 */
@@ -580,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
@@ -682,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;
@@ -705,12 +719,11 @@ 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) {
@@ -719,6 +732,9 @@ static int axi_emac_ofdata_to_platdata(struct udevice *dev)
        }
        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));