Merge https://gitlab.denx.de/u-boot/custodians/u-boot-spi into next
[platform/kernel/u-boot.git] / drivers / net / rtl8139.c
index dff77de..8a6f305 100644 (file)
@@ -70,6 +70,7 @@
 
 #include <common.h>
 #include <cpu_func.h>
+#include <dm.h>
 #include <log.h>
 #include <malloc.h>
 #include <net.h>
 #define DEBUG_TX       0       /* set to 1 to enable debug code */
 #define DEBUG_RX       0       /* set to 1 to enable debug code */
 
+#ifdef CONFIG_DM_ETH
+#define bus_to_phys(devno, a)  dm_pci_mem_to_phys((devno), (a))
+#define phys_to_bus(devno, a)  dm_pci_phys_to_mem((devno), (a))
+#else
 #define bus_to_phys(devno, a)  pci_mem_to_phys((pci_dev_t)(devno), (a))
 #define phys_to_bus(devno, a)  pci_phys_to_mem((pci_dev_t)(devno), (a))
+#endif
 
 /* Symbolic offsets to registers. */
 /* Ethernet hardware address. */
 #define RTL_STS_RXSTATUSOK                     BIT(0)
 
 struct rtl8139_priv {
+#ifndef CONFIG_DM_ETH
        struct eth_device       dev;
+       pci_dev_t               devno;
+#else
+       struct udevice          *devno;
+#endif
+       unsigned int            rxstatus;
        unsigned int            cur_rx;
        unsigned int            cur_tx;
        unsigned long           ioaddr;
-       pci_dev_t               devno;
        unsigned char           enetaddr[6];
 };
 
@@ -220,13 +231,13 @@ static unsigned char rx_ring[RX_BUF_LEN + 16] __aligned(4);
 #define EE_READ_CMD    6
 #define EE_ERASE_CMD   7
 
-static void rtl8139_eeprom_delay(uintptr_t regbase)
+static void rtl8139_eeprom_delay(struct rtl8139_priv *priv)
 {
        /*
         * Delay between EEPROM clock transitions.
         * No extra delay is needed with 33MHz PCI, but 66MHz may change this.
         */
-       inl(regbase + RTL_REG_CFG9346);
+       inl(priv->ioaddr + RTL_REG_CFG9346);
 }
 
 static int rtl8139_read_eeprom(struct rtl8139_priv *priv,
@@ -240,32 +251,32 @@ static int rtl8139_read_eeprom(struct rtl8139_priv *priv,
 
        outb(EE_ENB & ~EE_CS, ee_addr);
        outb(EE_ENB, ee_addr);
-       rtl8139_eeprom_delay(priv->ioaddr);
+       rtl8139_eeprom_delay(priv);
 
        /* Shift the read command bits out. */
        for (i = 4 + addr_len; i >= 0; i--) {
                dataval = (read_cmd & BIT(i)) ? EE_DATA_WRITE : 0;
                outb(EE_ENB | dataval, ee_addr);
-               rtl8139_eeprom_delay(priv->ioaddr);
+               rtl8139_eeprom_delay(priv);
                outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
-               rtl8139_eeprom_delay(priv->ioaddr);
+               rtl8139_eeprom_delay(priv);
        }
 
        outb(EE_ENB, ee_addr);
-       rtl8139_eeprom_delay(priv->ioaddr);
+       rtl8139_eeprom_delay(priv);
 
        for (i = 16; i > 0; i--) {
                outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
-               rtl8139_eeprom_delay(priv->ioaddr);
+               rtl8139_eeprom_delay(priv);
                retval <<= 1;
                retval |= inb(ee_addr) & EE_DATA_READ;
                outb(EE_ENB, ee_addr);
-               rtl8139_eeprom_delay(priv->ioaddr);
+               rtl8139_eeprom_delay(priv);
        }
 
        /* Terminate the EEPROM access. */
        outb(~EE_CS, ee_addr);
-       rtl8139_eeprom_delay(priv->ioaddr);
+       rtl8139_eeprom_delay(priv);
 
        return retval;
 }
@@ -360,9 +371,9 @@ static void rtl8139_reset(struct rtl8139_priv *priv)
        outw(0, priv->ioaddr + RTL_REG_INTRMASK);
 }
 
-static int rtl8139_send(struct eth_device *dev, void *packet, int length)
+static int rtl8139_send_common(struct rtl8139_priv *priv,
+                              void *packet, int length)
 {
-       struct rtl8139_priv *priv = container_of(dev, struct rtl8139_priv, dev);
        unsigned int len = length;
        unsigned long txstatus;
        unsigned int status;
@@ -422,25 +433,24 @@ static int rtl8139_send(struct eth_device *dev, void *packet, int length)
        return length;
 }
 
-static int rtl8139_recv(struct eth_device *dev)
+static int rtl8139_recv_common(struct rtl8139_priv *priv, unsigned char *rxdata,
+                              uchar **packetp)
 {
-       struct rtl8139_priv *priv = container_of(dev, struct rtl8139_priv, dev);
        const unsigned int rxstat = RTL_REG_INTRSTATUS_RXFIFOOVER |
                                    RTL_REG_INTRSTATUS_RXOVERFLOW |
                                    RTL_REG_INTRSTATUS_RXOK;
        unsigned int rx_size, rx_status;
        unsigned int ring_offs;
-       unsigned int status;
        int length = 0;
 
        if (inb(priv->ioaddr + RTL_REG_CHIPCMD) & RTL_REG_CHIPCMD_RXBUFEMPTY)
                return 0;
 
-       status = inw(priv->ioaddr + RTL_REG_INTRSTATUS);
+       priv->rxstatus = inw(priv->ioaddr + RTL_REG_INTRSTATUS);
        /* See below for the rest of the interrupt acknowledges.  */
-       outw(status & ~rxstat, priv->ioaddr + RTL_REG_INTRSTATUS);
+       outw(priv->rxstatus & ~rxstat, priv->ioaddr + RTL_REG_INTRSTATUS);
 
-       debug_cond(DEBUG_RX, "%s: int %hX ", __func__, status);
+       debug_cond(DEBUG_RX, "%s: int %hX ", __func__, priv->rxstatus);
 
        ring_offs = priv->cur_rx % RX_BUF_LEN;
        /* ring_offs is guaranteed being 4-byte aligned */
@@ -462,20 +472,30 @@ static int rtl8139_recv(struct eth_device *dev)
        /* Received a good packet */
        length = rx_size - 4;   /* no one cares about the FCS */
        if (ring_offs + 4 + rx_size - 4 > RX_BUF_LEN) {
-               unsigned char rxdata[RX_BUF_LEN];
                int semi_count = RX_BUF_LEN - ring_offs - 4;
 
                memcpy(rxdata, rx_ring + ring_offs + 4, semi_count);
                memcpy(&rxdata[semi_count], rx_ring,
                       rx_size - 4 - semi_count);
 
-               net_process_received_packet(rxdata, length);
+               *packetp = rxdata;
                debug_cond(DEBUG_RX, "rx packet %d+%d bytes",
                           semi_count, rx_size - 4 - semi_count);
        } else {
-               net_process_received_packet(rx_ring + ring_offs + 4, length);
+               *packetp = rx_ring + ring_offs + 4;
                debug_cond(DEBUG_RX, "rx packet %d bytes", rx_size - 4);
        }
+
+       return length;
+}
+
+static int rtl8139_free_pkt_common(struct rtl8139_priv *priv, unsigned int len)
+{
+       const unsigned int rxstat = RTL_REG_INTRSTATUS_RXFIFOOVER |
+                                   RTL_REG_INTRSTATUS_RXOVERFLOW |
+                                   RTL_REG_INTRSTATUS_RXOK;
+       unsigned int rx_size = len + 4;
+
        flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
 
        priv->cur_rx = ROUND(priv->cur_rx + rx_size + 4, 4);
@@ -485,25 +505,18 @@ static int rtl8139_recv(struct eth_device *dev)
         * Rx overflow situations. The document itself contains basically
         * no usable information, except for a few exception handling rules.
         */
-       outw(status & rxstat, priv->ioaddr + RTL_REG_INTRSTATUS);
+       outw(priv->rxstatus & rxstat, priv->ioaddr + RTL_REG_INTRSTATUS);
 
-       return length;
+       return 0;
 }
 
-static int rtl8139_init(struct eth_device *dev, bd_t *bis)
+static int rtl8139_init_common(struct rtl8139_priv *priv)
 {
-       struct rtl8139_priv *priv = container_of(dev, struct rtl8139_priv, dev);
-       unsigned short *ap = (unsigned short *)priv->enetaddr;
-       int addr_len, i;
        u8 reg;
 
        /* Bring the chip out of low-power mode. */
        outb(0x00, priv->ioaddr + RTL_REG_CONFIG1);
 
-       addr_len = rtl8139_read_eeprom(priv, 0, 8) == 0x8129 ? 8 : 6;
-       for (i = 0; i < 3; i++)
-               *ap++ = le16_to_cpu(rtl8139_read_eeprom(priv, i + 7, addr_len));
-
        rtl8139_reset(priv);
 
        reg = inb(priv->ioaddr + RTL_REG_MEDIASTATUS);
@@ -512,23 +525,25 @@ static int rtl8139_init(struct eth_device *dev, bd_t *bis)
                return -1;
        }
 
-       /* Non-DM compatibility */
-       memcpy(priv->dev.enetaddr, priv->enetaddr, 6);
-
        return 0;
 }
 
-static void rtl8139_stop(struct eth_device *dev)
+static void rtl8139_stop_common(struct rtl8139_priv *priv)
 {
-       struct rtl8139_priv *priv = container_of(dev, struct rtl8139_priv, dev);
-
        rtl8139_hw_reset(priv);
 }
 
-static int rtl8139_bcast_addr(struct eth_device *dev, const u8 *bcast_mac,
-                             int join)
+static void rtl8139_get_hwaddr(struct rtl8139_priv *priv)
 {
-       return 0;
+       unsigned short *ap = (unsigned short *)priv->enetaddr;
+       int i, addr_len;
+
+       /* Bring the chip out of low-power mode. */
+       outb(0x00, priv->ioaddr + RTL_REG_CONFIG1);
+
+       addr_len = rtl8139_read_eeprom(priv, 0, 8) == 0x8129 ? 8 : 6;
+       for (i = 0; i < 3; i++)
+               *ap++ = le16_to_cpu(rtl8139_read_eeprom(priv, i + 7, addr_len));
 }
 
 static void rtl8139_name(char *str, int card_number)
@@ -537,11 +552,55 @@ static void rtl8139_name(char *str, int card_number)
 }
 
 static struct pci_device_id supported[] = {
-       { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139 },
-       { PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_8139 },
+       { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139) },
+       { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_8139) },
        { }
 };
 
+#ifndef CONFIG_DM_ETH
+static int rtl8139_bcast_addr(struct eth_device *dev, const u8 *bcast_mac,
+                             int join)
+{
+       return 0;
+}
+
+static int rtl8139_init(struct eth_device *dev, bd_t *bis)
+{
+       struct rtl8139_priv *priv = container_of(dev, struct rtl8139_priv, dev);
+
+       return rtl8139_init_common(priv);
+}
+
+static void rtl8139_stop(struct eth_device *dev)
+{
+       struct rtl8139_priv *priv = container_of(dev, struct rtl8139_priv, dev);
+
+       return rtl8139_stop_common(priv);
+}
+
+static int rtl8139_send(struct eth_device *dev, void *packet, int length)
+{
+       struct rtl8139_priv *priv = container_of(dev, struct rtl8139_priv, dev);
+
+       return rtl8139_send_common(priv, packet, length);
+}
+
+static int rtl8139_recv(struct eth_device *dev)
+{
+       struct rtl8139_priv *priv = container_of(dev, struct rtl8139_priv, dev);
+       unsigned char rxdata[RX_BUF_LEN];
+       uchar *packet;
+       int ret;
+
+       ret = rtl8139_recv_common(priv, rxdata, &packet);
+       if (ret) {
+               net_process_received_packet(packet, ret);
+               rtl8139_free_pkt_common(priv, ret);
+       }
+
+       return ret;
+}
+
 int rtl8139_initialize(bd_t *bis)
 {
        struct rtl8139_priv *priv;
@@ -582,6 +641,11 @@ int rtl8139_initialize(bd_t *bis)
                dev->recv = rtl8139_recv;
                dev->mcast = rtl8139_bcast_addr;
 
+               rtl8139_get_hwaddr(priv);
+
+               /* Non-DM compatibility */
+               memcpy(priv->dev.enetaddr, priv->enetaddr, 6);
+
                eth_register(dev);
 
                card_number++;
@@ -593,3 +657,123 @@ int rtl8139_initialize(bd_t *bis)
 
        return card_number;
 }
+#else /* DM_ETH */
+static int rtl8139_start(struct udevice *dev)
+{
+       struct eth_pdata *plat = dev_get_platdata(dev);
+       struct rtl8139_priv *priv = dev_get_priv(dev);
+
+       memcpy(priv->enetaddr, plat->enetaddr, sizeof(plat->enetaddr));
+
+       return rtl8139_init_common(priv);
+}
+
+static void rtl8139_stop(struct udevice *dev)
+{
+       struct rtl8139_priv *priv = dev_get_priv(dev);
+
+       rtl8139_stop_common(priv);
+}
+
+static int rtl8139_send(struct udevice *dev, void *packet, int length)
+{
+       struct rtl8139_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       ret = rtl8139_send_common(priv, packet, length);
+
+       return ret ? 0 : -ETIMEDOUT;
+}
+
+static int rtl8139_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+       struct rtl8139_priv *priv = dev_get_priv(dev);
+       static unsigned char rxdata[RX_BUF_LEN];
+
+       return rtl8139_recv_common(priv, rxdata, packetp);
+}
+
+static int rtl8139_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+       struct rtl8139_priv *priv = dev_get_priv(dev);
+
+       rtl8139_free_pkt_common(priv, length);
+
+       return 0;
+}
+
+static int rtl8139_write_hwaddr(struct udevice *dev)
+{
+       struct eth_pdata *plat = dev_get_platdata(dev);
+       struct rtl8139_priv *priv = dev_get_priv(dev);
+
+       memcpy(priv->enetaddr, plat->enetaddr, sizeof(plat->enetaddr));
+
+       rtl8139_reset(priv);
+
+       return 0;
+}
+
+static int rtl8139_read_rom_hwaddr(struct udevice *dev)
+{
+       struct rtl8139_priv *priv = dev_get_priv(dev);
+
+       rtl8139_get_hwaddr(priv);
+
+       return 0;
+}
+
+static int rtl8139_bind(struct udevice *dev)
+{
+       static int card_number;
+       char name[16];
+
+       rtl8139_name(name, card_number++);
+
+       return device_set_name(dev, name);
+}
+
+static int rtl8139_probe(struct udevice *dev)
+{
+       struct eth_pdata *plat = dev_get_platdata(dev);
+       struct rtl8139_priv *priv = dev_get_priv(dev);
+       u32 iobase;
+
+       dm_pci_read_config32(dev, PCI_BASE_ADDRESS_1, &iobase);
+       iobase &= ~0xf;
+
+       debug("rtl8139: REALTEK RTL8139 @0x%x\n", iobase);
+
+       priv->devno = dev;
+       priv->ioaddr = (unsigned long)bus_to_phys(dev, iobase);
+
+       rtl8139_get_hwaddr(priv);
+       memcpy(plat->enetaddr, priv->enetaddr, sizeof(priv->enetaddr));
+
+       dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x20);
+
+       return 0;
+}
+
+static const struct eth_ops rtl8139_ops = {
+       .start          = rtl8139_start,
+       .send           = rtl8139_send,
+       .recv           = rtl8139_recv,
+       .stop           = rtl8139_stop,
+       .free_pkt       = rtl8139_free_pkt,
+       .write_hwaddr   = rtl8139_write_hwaddr,
+       .read_rom_hwaddr = rtl8139_read_rom_hwaddr,
+};
+
+U_BOOT_DRIVER(eth_rtl8139) = {
+       .name   = "eth_rtl8139",
+       .id     = UCLASS_ETH,
+       .bind   = rtl8139_bind,
+       .probe  = rtl8139_probe,
+       .ops    = &rtl8139_ops,
+       .priv_auto_alloc_size = sizeof(struct rtl8139_priv),
+       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+
+U_BOOT_PCI_DEVICE(eth_rtl8139, supported);
+#endif