From d0a5a0b2d800ddf248a7a843e5efba72d19059cc Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 6 Jul 2015 16:47:45 -0600 Subject: dm: eth: Add driver-model support to the rtl8169 driver This driver is used by the Intel Minnowmax board. Convert it to driver model so it can use the new Ethernet implementation. Signed-off-by: Simon Glass --- drivers/net/rtl8169.c | 236 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 187 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 958488c..7b6e20f 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -41,10 +41,13 @@ * Modified to use le32_to_cpu and cpu_to_le32 properly */ #include +#include #include #include #include +#ifndef CONFIG_DM_ETH #include +#endif #include #include @@ -281,6 +284,8 @@ struct RxDesc { u32 buf_Haddr; }; +static unsigned char rxdata[RX_BUF_LEN]; + #define RTL8169_DESC_SIZE 16 #if ARCH_DMA_MINALIGN > 256 @@ -299,7 +304,8 @@ struct RxDesc { * the driver to allocate descriptors from a pool of non-cached memory. */ #if RTL8169_DESC_SIZE < ARCH_DMA_MINALIGN -#if !defined(CONFIG_SYS_NONCACHED_MEMORY) && !defined(CONFIG_SYS_DCACHE_OFF) +#if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \ + !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86) #warning cache-line size is larger than descriptor size #endif #endif @@ -317,6 +323,7 @@ DEFINE_ALIGN_BUFFER(u8, txb, NUM_TX_DESC * RX_BUF_SIZE, RTL8169_ALIGN); DEFINE_ALIGN_BUFFER(u8, rxb, NUM_RX_DESC * RX_BUF_SIZE, RTL8169_ALIGN); struct rtl8169_private { + ulong iobase; void *mmio_addr; /* memory map physical address */ int chipset; unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ @@ -338,9 +345,9 @@ static const unsigned int rtl8169_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); static struct pci_device_id supported[] = { - {PCI_VENDOR_ID_REALTEK, 0x8167}, - {PCI_VENDOR_ID_REALTEK, 0x8168}, - {PCI_VENDOR_ID_REALTEK, 0x8169}, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167) }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168) }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169) }, {} }; @@ -380,7 +387,7 @@ int mdio_read(int RegAddr) return value; } -static int rtl8169_init_board(struct eth_device *dev) +static int rtl8169_init_board(unsigned long dev_iobase, const char *name) { int i; u32 tmp; @@ -388,7 +395,7 @@ static int rtl8169_init_board(struct eth_device *dev) #ifdef DEBUG_RTL8169 printf ("%s\n", __FUNCTION__); #endif - ioaddr = dev->iobase; + ioaddr = dev_iobase; /* Soft reset the chip. */ RTL_W8(ChipCmd, CmdReset); @@ -412,7 +419,8 @@ static int rtl8169_init_board(struct eth_device *dev) } /* if unknown chip, assume array element #0, original RTL-8169 in this case */ - printf("PCI device %s: unknown chip version, assuming RTL-8169\n", dev->name); + printf("PCI device %s: unknown chip version, assuming RTL-8169\n", + name); printf("PCI device: TxConfig = 0x%lX\n", (unsigned long) RTL_R32(TxConfig)); tpc->chipset = 0; @@ -504,7 +512,8 @@ static void rtl_flush_buffer(void *buf, size_t size) /************************************************************************** RECV - Receive a frame ***************************************************************************/ -static int rtl_recv(struct eth_device *dev) +static int rtl_recv_common(pci_dev_t bdf, unsigned long dev_iobase, + uchar **packetp) { /* return true if there's an ethernet packet ready to read */ /* nic->packet should contain data on return */ @@ -515,7 +524,7 @@ static int rtl_recv(struct eth_device *dev) #ifdef DEBUG_RTL8169_RX printf ("%s\n", __FUNCTION__); #endif - ioaddr = dev->iobase; + ioaddr = dev_iobase; cur_rx = tpc->cur_rx; @@ -523,7 +532,6 @@ static int rtl_recv(struct eth_device *dev) if ((le32_to_cpu(tpc->RxDescArray[cur_rx].status) & OWNbit) == 0) { if (!(le32_to_cpu(tpc->RxDescArray[cur_rx].status) & RxRES)) { - unsigned char rxdata[RX_BUF_LEN]; length = (int) (le32_to_cpu(tpc->RxDescArray[cur_rx]. status) & 0x00001FFF) - 4; @@ -536,17 +544,22 @@ static int rtl_recv(struct eth_device *dev) else tpc->RxDescArray[cur_rx].status = cpu_to_le32(OWNbit + RX_BUF_SIZE); - tpc->RxDescArray[cur_rx].buf_addr = - cpu_to_le32(bus_to_phys(tpc->RxBufferRing[cur_rx])); + tpc->RxDescArray[cur_rx].buf_addr = cpu_to_le32( + pci_mem_to_phys(bdf, (pci_addr_t)(unsigned long) + tpc->RxBufferRing[cur_rx])); rtl_flush_rx_desc(&tpc->RxDescArray[cur_rx]); - +#ifdef CONFIG_DM_ETH + *packetp = rxdata; +#else net_process_received_packet(rxdata, length); +#endif } else { puts("Error Rx"); + length = -EIO; } cur_rx = (cur_rx + 1) % NUM_RX_DESC; tpc->cur_rx = cur_rx; - return 1; + return length; } else { ushort sts = RTL_R8(IntrStatus); @@ -557,11 +570,26 @@ static int rtl_recv(struct eth_device *dev) return (0); /* initially as this is called to flush the input */ } +#ifdef CONFIG_DM_ETH +int rtl8169_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct rtl8169_private *priv = dev_get_priv(dev); + + return rtl_recv_common(pci_get_bdf(dev), priv->iobase, packetp); +} +#else +static int rtl_recv(struct eth_device *dev) +{ + return rtl_recv_common((pci_dev_t)dev->priv, dev->iobase, NULL); +} +#endif /* nCONFIG_DM_ETH */ + #define HZ 1000 /************************************************************************** SEND - Transmit a frame ***************************************************************************/ -static int rtl_send(struct eth_device *dev, void *packet, int length) +static int rtl_send_common(pci_dev_t bdf, unsigned long dev_iobase, + void *packet, int length) { /* send the packet to destination */ @@ -577,7 +605,7 @@ static int rtl_send(struct eth_device *dev, void *packet, int length) printf("sending %d bytes\n", len); #endif - ioaddr = dev->iobase; + ioaddr = dev_iobase; /* point to the current txb incase multiple tx_rings are used */ ptxb = tpc->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE]; @@ -588,7 +616,8 @@ static int rtl_send(struct eth_device *dev, void *packet, int length) ptxb[len++] = '\0'; tpc->TxDescArray[entry].buf_Haddr = 0; - tpc->TxDescArray[entry].buf_addr = cpu_to_le32(bus_to_phys(ptxb)); + tpc->TxDescArray[entry].buf_addr = cpu_to_le32( + pci_mem_to_phys(bdf, (pci_addr_t)(unsigned long)ptxb)); if (entry != (NUM_TX_DESC - 1)) { tpc->TxDescArray[entry].status = cpu_to_le32((OWNbit | FSbit | LSbit) | @@ -625,7 +654,23 @@ static int rtl_send(struct eth_device *dev, void *packet, int length) return ret; } -static void rtl8169_set_rx_mode(struct eth_device *dev) +#ifdef CONFIG_DM_ETH +int rtl8169_eth_send(struct udevice *dev, void *packet, int length) +{ + struct rtl8169_private *priv = dev_get_priv(dev); + + return rtl_send_common(pci_get_bdf(dev), priv->iobase, packet, length); +} + +#else +static int rtl_send(struct eth_device *dev, void *packet, int length) +{ + return rtl_send_common((pci_dev_t)dev->priv, dev->iobase, packet, + length); +} +#endif + +static void rtl8169_set_rx_mode(void) { u32 mc_filter[2]; /* Multicast hash filter */ int rx_mode; @@ -648,7 +693,7 @@ static void rtl8169_set_rx_mode(struct eth_device *dev) RTL_W32(MAR0 + 4, mc_filter[1]); } -static void rtl8169_hw_start(struct eth_device *dev) +static void rtl8169_hw_start(pci_dev_t bdf) { u32 i; @@ -693,9 +738,11 @@ static void rtl8169_hw_start(struct eth_device *dev) tpc->cur_rx = 0; - RTL_W32(TxDescStartAddrLow, bus_to_phys(tpc->TxDescArray)); + RTL_W32(TxDescStartAddrLow, pci_mem_to_phys(bdf, + (pci_addr_t)(unsigned long)tpc->TxDescArray)); RTL_W32(TxDescStartAddrHigh, (unsigned long)0); - RTL_W32(RxDescStartAddrLow, bus_to_phys(tpc->RxDescArray)); + RTL_W32(RxDescStartAddrLow, pci_mem_to_phys( + bdf, (pci_addr_t)(unsigned long)tpc->RxDescArray)); RTL_W32(RxDescStartAddrHigh, (unsigned long)0); /* RTL-8169sc/8110sc or later version */ @@ -707,7 +754,7 @@ static void rtl8169_hw_start(struct eth_device *dev) RTL_W32(RxMissed, 0); - rtl8169_set_rx_mode(dev); + rtl8169_set_rx_mode(); /* no early-rx interrupts */ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); @@ -717,7 +764,7 @@ static void rtl8169_hw_start(struct eth_device *dev) #endif } -static void rtl8169_init_ring(struct eth_device *dev) +static void rtl8169_init_ring(pci_dev_t bdf) { int i; @@ -745,8 +792,8 @@ static void rtl8169_init_ring(struct eth_device *dev) cpu_to_le32(OWNbit + RX_BUF_SIZE); tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE]; - tpc->RxDescArray[i].buf_addr = - cpu_to_le32(bus_to_phys(tpc->RxBufferRing[i])); + tpc->RxDescArray[i].buf_addr = cpu_to_le32(pci_mem_to_phys( + bdf, (pci_addr_t)(unsigned long)tpc->RxBufferRing[i])); rtl_flush_rx_desc(&tpc->RxDescArray[i]); } @@ -755,10 +802,7 @@ static void rtl8169_init_ring(struct eth_device *dev) #endif } -/************************************************************************** -RESET - Finish setting up the ethernet interface -***************************************************************************/ -static int rtl_reset(struct eth_device *dev, bd_t *bis) +static void rtl8169_common_start(pci_dev_t bdf, unsigned char *enetaddr) { int i; @@ -767,30 +811,47 @@ static int rtl_reset(struct eth_device *dev, bd_t *bis) printf ("%s\n", __FUNCTION__); #endif - rtl8169_init_ring(dev); - rtl8169_hw_start(dev); + rtl8169_init_ring(bdf); + rtl8169_hw_start(bdf); /* Construct a perfect filter frame with the mac address as first match * and broadcast for all others */ for (i = 0; i < 192; i++) txb[i] = 0xFF; - txb[0] = dev->enetaddr[0]; - txb[1] = dev->enetaddr[1]; - txb[2] = dev->enetaddr[2]; - txb[3] = dev->enetaddr[3]; - txb[4] = dev->enetaddr[4]; - txb[5] = dev->enetaddr[5]; + txb[0] = enetaddr[0]; + txb[1] = enetaddr[1]; + txb[2] = enetaddr[2]; + txb[3] = enetaddr[3]; + txb[4] = enetaddr[4]; + txb[5] = enetaddr[5]; #ifdef DEBUG_RTL8169 printf("%s elapsed time : %lu\n", __func__, currticks()-stime); #endif - return 0; } +#ifdef CONFIG_DM_ETH +static int rtl8169_eth_start(struct udevice *dev) +{ + struct eth_pdata *plat = dev_get_platdata(dev); + + rtl8169_common_start(pci_get_bdf(dev), plat->enetaddr); + + return 0; +} +#else /************************************************************************** -HALT - Turn off ethernet interface +RESET - Finish setting up the ethernet interface ***************************************************************************/ -static void rtl_halt(struct eth_device *dev) +static int rtl_reset(struct eth_device *dev, bd_t *bis) +{ + rtl8169_common_start((pci_dev_t)dev->priv, dev->enetaddr); + + return 0; +} +#endif /* nCONFIG_DM_ETH */ + +static void rtl_halt_common(unsigned long dev_iobase) { int i; @@ -798,7 +859,7 @@ static void rtl_halt(struct eth_device *dev) printf ("%s\n", __FUNCTION__); #endif - ioaddr = dev->iobase; + ioaddr = dev_iobase; /* Stop the chip's Tx and Rx DMA processes. */ RTL_W8(ChipCmd, 0x00); @@ -813,13 +874,31 @@ static void rtl_halt(struct eth_device *dev) } } +#ifdef CONFIG_DM_ETH +void rtl8169_eth_stop(struct udevice *dev) +{ + struct rtl8169_private *priv = dev_get_priv(dev); + + rtl_halt_common(priv->iobase); +} +#else +/************************************************************************** +HALT - Turn off ethernet interface +***************************************************************************/ +static void rtl_halt(struct eth_device *dev) +{ + rtl_halt_common(dev->iobase); +} +#endif + /************************************************************************** INIT - Look for an adapter, this routine's visible to the outside ***************************************************************************/ #define board_found 1 #define valid_link 0 -static int rtl_init(struct eth_device *dev, bd_t *bis) +static int rtl_init(unsigned long dev_ioaddr, const char *name, + unsigned char *enetaddr) { static int board_idx = -1; int i, rc; @@ -828,33 +907,32 @@ static int rtl_init(struct eth_device *dev, bd_t *bis) #ifdef DEBUG_RTL8169 printf ("%s\n", __FUNCTION__); #endif - - ioaddr = dev->iobase; + ioaddr = dev_ioaddr; board_idx++; /* point to private storage */ tpc = &tpx; - rc = rtl8169_init_board(dev); + rc = rtl8169_init_board(ioaddr, name); if (rc) return rc; /* Get MAC address. FIXME: read EEPROM */ for (i = 0; i < MAC_ADDR_LEN; i++) - dev->enetaddr[i] = RTL_R8(MAC0 + i); + enetaddr[i] = RTL_R8(MAC0 + i); #ifdef DEBUG_RTL8169 printf("chipset = %d\n", tpc->chipset); printf("MAC Address"); for (i = 0; i < MAC_ADDR_LEN; i++) - printf(":%02x", dev->enetaddr[i]); + printf(":%02x", enetaddr[i]); putc('\n'); #endif #ifdef DEBUG_RTL8169 /* Print out some hardware info */ - printf("%s: at ioaddr 0x%lx\n", dev->name, ioaddr); + printf("%s: at ioaddr 0x%lx\n", name, ioaddr); #endif /* if TBI is not endbled */ @@ -964,6 +1042,7 @@ static int rtl_init(struct eth_device *dev, bd_t *bis) return 0; } +#ifndef CONFIG_DM_ETH int rtl8169_initialize(bd_t *bis) { pci_dev_t devno; @@ -1014,7 +1093,7 @@ int rtl8169_initialize(bd_t *bis) dev->send = rtl_send; dev->recv = rtl_recv; - err = rtl_init(dev, bis); + err = rtl_init(dev->iobase, dev->name, dev->enetaddr); if (err < 0) { printf(pr_fmt("failed to initialize card: %d\n"), err); free(dev); @@ -1027,3 +1106,62 @@ int rtl8169_initialize(bd_t *bis) } return card_number; } +#endif + +#ifdef CONFIG_DM_ETH +static int rtl8169_eth_probe(struct udevice *dev) +{ + struct pci_child_platdata *pplat = dev_get_parent_platdata(dev); + struct rtl8169_private *priv = dev_get_priv(dev); + struct eth_pdata *plat = dev_get_platdata(dev); + u32 iobase; + int region; + int ret; + + debug("rtl8169: REALTEK RTL8169 @0x%x\n", iobase); + switch (pplat->device) { + case 0x8168: + region = 2; + break; + default: + region = 1; + break; + } + pci_read_config32(pci_get_bdf(dev), PCI_BASE_ADDRESS_0 + region * 4, + &iobase); + iobase &= ~0xf; + priv->iobase = (int)pci_mem_to_phys(pci_get_bdf(dev), iobase); + + ret = rtl_init(priv->iobase, dev->name, plat->enetaddr); + if (ret < 0) { + printf(pr_fmt("failed to initialize card: %d\n"), ret); + return ret; + } + + return 0; +} + +static const struct eth_ops rtl8169_eth_ops = { + .start = rtl8169_eth_start, + .send = rtl8169_eth_send, + .recv = rtl8169_eth_recv, + .stop = rtl8169_eth_stop, +}; + +static const struct udevice_id rtl8169_eth_ids[] = { + { .compatible = "realtek,rtl8169" }, + { } +}; + +U_BOOT_DRIVER(eth_rtl8169) = { + .name = "eth_rtl8169", + .id = UCLASS_ETH, + .of_match = rtl8169_eth_ids, + .probe = rtl8169_eth_probe, + .ops = &rtl8169_eth_ops, + .priv_auto_alloc_size = sizeof(struct rtl8169_private), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; + +U_BOOT_PCI_DEVICE(eth_rtl8169, supported); +#endif -- cgit v1.1