diff options
Diffstat (limited to 'drivers/net/macb.c')
-rw-r--r-- | drivers/net/macb.c | 363 |
1 files changed, 272 insertions, 91 deletions
diff --git a/drivers/net/macb.c b/drivers/net/macb.c index c4ab9efb63..f5b2fa74dc 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -52,6 +52,10 @@ #define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE) #define GEM_Q1_DESC_BYTES (sizeof(struct macb_dma_desc) * GEM_Q1_DESCS) +struct macb_config { + int (*txclk_init)(struct device *dev, struct clk **tx_clk); +}; + struct macb_device { void __iomem *regs; @@ -59,9 +63,13 @@ struct macb_device { unsigned int tx_head; void *rx_buffer; + dma_addr_t rx_buffer_phys; void *tx_buffer; + void *rx_packet_buf; struct macb_dma_desc *rx_ring; + dma_addr_t rx_ring_phys; struct macb_dma_desc *tx_ring; + dma_addr_t tx_ring_phys; struct macb_dma_desc *gem_q1_descs; int rx_buffer_size; @@ -69,8 +77,8 @@ struct macb_device { int phy_addr; - struct clk *pclk; - const struct device_d *dev; + struct clk *pclk, *hclk, *txclk, *rxclk; + struct device *dev; struct eth_device netdev; phy_interface_t interface; @@ -100,6 +108,7 @@ static int macb_send(struct eth_device *edev, void *packet, int ret = 0; uint64_t start; unsigned int tx_head = macb->tx_head; + dma_addr_t packet_dma; ctrl = MACB_BF(TX_FRMLEN, length); ctrl |= MACB_BIT(TX_LAST); @@ -111,23 +120,25 @@ static int macb_send(struct eth_device *edev, void *packet, macb->tx_head++; } - macb->tx_ring[tx_head].ctrl = ctrl; - macb->tx_ring[tx_head].addr = (ulong)packet; - barrier(); - dma_sync_single_for_device((unsigned long)packet, length, DMA_TO_DEVICE); + packet_dma = dma_map_single(macb->dev, packet, length, DMA_TO_DEVICE); + if (dma_mapping_error(macb->dev, packet_dma)) + return -EFAULT; + + writel(ctrl, &macb->tx_ring[tx_head].ctrl); + writel(packet_dma, &macb->tx_ring[tx_head].addr); macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART)); start = get_time_ns(); ret = -ETIMEDOUT; do { - barrier(); - ctrl = macb->tx_ring[0].ctrl; + ctrl = readl(&macb->tx_ring[0].ctrl); if (ctrl & MACB_BIT(TX_USED)) { ret = 0; break; } } while (!is_timeout(start, 100 * MSECOND)); - dma_sync_single_for_cpu((unsigned long)packet, length, DMA_TO_DEVICE); + + dma_unmap_single(macb->dev, packet_dma, length, DMA_TO_DEVICE); if (ctrl & MACB_BIT(TX_UNDERRUN)) dev_err(macb->dev, "TX underrun\n"); @@ -144,50 +155,42 @@ static void reclaim_rx_buffers(struct macb_device *macb, { unsigned int i; - dev_dbg(macb->dev, "%s\n", __func__); - i = macb->rx_tail; while (i > new_tail) { - macb->rx_ring[i].addr &= ~MACB_BIT(RX_USED); + clrbits_le32(&macb->rx_ring[i].addr, MACB_BIT(RX_USED)); i++; if (i > macb->rx_ring_size) i = 0; } while (i < new_tail) { - macb->rx_ring[i].addr &= ~MACB_BIT(RX_USED); + clrbits_le32(&macb->rx_ring[i].addr, MACB_BIT(RX_USED)); i++; } - barrier(); macb->rx_tail = new_tail; } static int gem_recv(struct eth_device *edev) { struct macb_device *macb = edev->priv; - void *buffer; + dma_addr_t buffer; int length; u32 status; - dev_dbg(macb->dev, "%s\n", __func__); - for (;;) { - barrier(); - if (!(macb->rx_ring[macb->rx_tail].addr & MACB_BIT(RX_USED))) + if (!(readl(&macb->rx_ring[macb->rx_tail].addr) & MACB_BIT(RX_USED))) return -1; - barrier(); - status = macb->rx_ring[macb->rx_tail].ctrl; + status = readl(&macb->rx_ring[macb->rx_tail].ctrl); length = MACB_BFEXT(RX_FRMLEN, status); - buffer = macb->rx_buffer + macb->rx_buffer_size * macb->rx_tail; - dma_sync_single_for_cpu((unsigned long)buffer, length, - DMA_FROM_DEVICE); - net_receive(edev, buffer, length); - dma_sync_single_for_device((unsigned long)buffer, length, - DMA_FROM_DEVICE); - macb->rx_ring[macb->rx_tail].addr &= ~MACB_BIT(RX_USED); - barrier(); + buffer = macb->rx_buffer_phys + macb->rx_buffer_size * macb->rx_tail; + dma_sync_single_for_cpu(macb->dev, buffer, length, DMA_FROM_DEVICE); + net_receive(edev, + macb->rx_buffer + macb->rx_buffer_size * macb->rx_tail, + length); + dma_sync_single_for_device(macb->dev, buffer, length, DMA_FROM_DEVICE); + clrbits_le32(&macb->rx_ring[macb->rx_tail].addr, MACB_BIT(RX_USED)); macb->rx_tail++; if (macb->rx_tail >= macb->rx_ring_size) @@ -201,20 +204,16 @@ static int macb_recv(struct eth_device *edev) { struct macb_device *macb = edev->priv; unsigned int rx_tail = macb->rx_tail; - void *buffer; + dma_addr_t buffer; int length; int wrapped = 0; u32 status; - dev_dbg(macb->dev, "%s\n", __func__); - for (;;) { - barrier(); - if (!(macb->rx_ring[rx_tail].addr & MACB_BIT(RX_USED))) + if (!(readl(&macb->rx_ring[rx_tail].addr) & MACB_BIT(RX_USED))) return -1; - barrier(); - status = macb->rx_ring[rx_tail].ctrl; + status = readl(&macb->rx_ring[rx_tail].ctrl); if (status & MACB_BIT(RX_SOF)) { if (rx_tail != macb->rx_tail) reclaim_rx_buffers(macb, rx_tail); @@ -222,7 +221,7 @@ static int macb_recv(struct eth_device *edev) } if (status & MACB_BIT(RX_EOF)) { - buffer = macb->rx_buffer + macb->rx_buffer_size * macb->rx_tail; + buffer = macb->rx_buffer_phys + macb->rx_buffer_size * macb->rx_tail; length = MACB_BFEXT(RX_FRMLEN, status); if (wrapped) { unsigned int headlen, taillen; @@ -230,26 +229,24 @@ static int macb_recv(struct eth_device *edev) headlen = macb->rx_buffer_size * (macb->rx_ring_size - macb->rx_tail); taillen = length - headlen; - dma_sync_single_for_cpu((unsigned long)buffer, - headlen, DMA_FROM_DEVICE); - memcpy((void *)NetRxPackets[0], buffer, headlen); - dma_sync_single_for_cpu((unsigned long)macb->rx_buffer, + dma_sync_single_for_cpu(macb->dev, buffer, headlen, DMA_FROM_DEVICE); + memcpy(macb->rx_packet_buf, + macb->rx_buffer + macb->rx_buffer_size * macb->rx_tail, + headlen); + dma_sync_single_for_cpu(macb->dev, macb->rx_buffer_phys, taillen, DMA_FROM_DEVICE); - memcpy((void *)NetRxPackets[0] + headlen, - macb->rx_buffer, taillen); - dma_sync_single_for_device((unsigned long)buffer, - headlen, DMA_FROM_DEVICE); - dma_sync_single_for_device((unsigned long)macb->rx_buffer, + memcpy(macb->rx_packet_buf + headlen, macb->rx_buffer, taillen); + dma_sync_single_for_device(macb->dev, buffer, headlen, DMA_FROM_DEVICE); + dma_sync_single_for_device(macb->dev, macb->rx_buffer_phys, taillen, DMA_FROM_DEVICE); - net_receive(edev, NetRxPackets[0], length); + net_receive(edev, macb->rx_packet_buf, length); } else { - dma_sync_single_for_cpu((unsigned long)buffer, length, - DMA_FROM_DEVICE); - net_receive(edev, buffer, length); - dma_sync_single_for_device((unsigned long)buffer, length, - DMA_FROM_DEVICE); + dma_sync_single_for_cpu(macb->dev, buffer, length, DMA_FROM_DEVICE); + net_receive(edev, + macb->rx_buffer + macb->rx_buffer_size * macb->rx_tail, + length); + dma_sync_single_for_device(macb->dev, buffer, length, DMA_FROM_DEVICE); } - barrier(); if (++rx_tail >= macb->rx_ring_size) rx_tail = 0; reclaim_rx_buffers(macb, rx_tail); @@ -264,9 +261,41 @@ static int macb_recv(struct eth_device *edev) return 0; } +static int macb_set_tx_clk(struct macb_device *macb, int speed) +{ + int rate; + int rate_rounded; + + if (!macb->txclk) { + dev_dbg(macb->dev, "txclk not available\n"); + return 0; + } + + switch (speed) { + case SPEED_10: + rate = 2500000; + break; + case SPEED_100: + rate = 25000000; + break; + case SPEED_1000: + rate = 125000000; + break; + default: + return -EINVAL; + } + + rate_rounded = clk_round_rate(macb->txclk, rate); + if (rate_rounded <= 0) + return -EINVAL; + + return clk_set_rate(macb->txclk, rate_rounded); +} + static void macb_adjust_link(struct eth_device *edev) { struct macb_device *macb = edev->priv; + int err; u32 reg; reg = macb_readl(macb, NCFGR); @@ -282,14 +311,16 @@ static void macb_adjust_link(struct eth_device *edev) reg |= GEM_BIT(GBE); macb_or_gem_writel(macb, NCFGR, reg); + + err = macb_set_tx_clk(macb, edev->phydev->speed); + if (err) + dev_warn(macb->dev, "cannot set txclk\n"); } static int macb_open(struct eth_device *edev) { struct macb_device *macb = edev->priv; - dev_dbg(macb->dev, "%s\n", __func__); - /* Enable TX and RX */ macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE)); @@ -335,42 +366,45 @@ static int gmac_init_dummy_tx_queues(struct macb_device *macb) if (queue_mask & (1 << i)) num_queues++; - macb->gem_q1_descs[0].addr = 0; - macb->gem_q1_descs[0].ctrl = MACB_BIT(TX_WRAP) | - MACB_BIT(TX_LAST) | MACB_BIT(TX_USED); + writel(0, &macb->gem_q1_descs[0].addr); + writel(MACB_BIT(TX_WRAP) | MACB_BIT(TX_LAST) | MACB_BIT(TX_USED), + &macb->gem_q1_descs[0].ctrl); for (i = 1; i < num_queues; i++) - gem_writel_queue_TBQP(macb, &macb->gem_q1_descs[0], i - 1); + gem_writel_queue_TBQP(macb, (ulong)macb->gem_q1_descs, i - 1); return 0; } -static void macb_init(struct macb_device *macb) +static int macb_init(struct macb_device *macb) { unsigned long paddr, val = 0; int i; - dev_dbg(macb->dev, "%s\n", __func__); - /* * macb_halt should have been called at some point before now, * so we'll assume the controller is idle. */ + macb->rx_buffer_phys = dma_map_single(macb->dev, macb->rx_buffer, + macb->rx_buffer_size * macb->rx_ring_size, + DMA_FROM_DEVICE); + if (dma_mapping_error(macb->dev, macb->rx_buffer_phys)) + return -EFAULT; /* initialize DMA descriptors */ paddr = (ulong)macb->rx_buffer; for (i = 0; i < macb->rx_ring_size; i++) { - macb->rx_ring[i].addr = paddr; - macb->rx_ring[i].ctrl = 0; + writel(paddr, &macb->rx_ring[i].addr); + writel(0, &macb->rx_ring[i].ctrl); paddr += macb->rx_buffer_size; } - macb->rx_ring[macb->rx_ring_size - 1].addr |= MACB_BIT(RX_WRAP); + setbits_le32(&macb->rx_ring[macb->rx_ring_size - 1].addr, MACB_BIT(RX_WRAP)); for (i = 0; i < TX_RING_SIZE; i++) { - macb->tx_ring[i].addr = 0; - macb->tx_ring[i].ctrl = MACB_BIT(TX_USED); + writel(0, &macb->tx_ring[i].addr); + writel(MACB_BIT(TX_USED), &macb->tx_ring[i].ctrl); } - macb->tx_ring[TX_RING_SIZE - 1].addr |= MACB_BIT(TX_WRAP); + setbits_le32(&macb->tx_ring[TX_RING_SIZE - 1].addr, MACB_BIT(TX_WRAP)); macb->rx_tail = macb->tx_head = 0; @@ -383,9 +417,8 @@ static void macb_init(struct macb_device *macb) gmac_init_dummy_tx_queues(macb); /* Disable the second priority rx queue */ - macb->gem_q1_descs[1].addr = MACB_BIT(RX_USED) | - MACB_BIT(RX_WRAP); - macb->gem_q1_descs[1].ctrl = 0; + writel(MACB_BIT(RX_USED) | MACB_BIT(RX_WRAP), &macb->gem_q1_descs[1].addr); + writel(0, &macb->gem_q1_descs[1].ctrl); gem_writel(macb, RQ1, (ulong)&macb->gem_q1_descs[1]); } @@ -412,6 +445,7 @@ static void macb_init(struct macb_device *macb) macb_or_gem_writel(macb, USRIO, val); + return 0; } static void macb_halt(struct eth_device *edev) @@ -430,6 +464,13 @@ static void macb_halt(struct eth_device *edev) /* Disable TX and RX, and clear statistics */ macb_writel(macb, NCR, MACB_BIT(CLRSTAT)); + + dma_unmap_single(macb->dev, macb->rx_buffer_phys, + macb->rx_buffer_size * macb->rx_ring_size, + DMA_FROM_DEVICE); + free(macb->rx_buffer); + dma_free_coherent((void *)macb->rx_ring, macb->rx_ring_phys, RX_RING_BYTES(macb)); + dma_free_coherent((void *)macb->tx_ring, macb->tx_ring_phys, TX_RING_BYTES); } static int macb_phy_read(struct mii_bus *bus, int addr, int reg) @@ -441,8 +482,6 @@ static int macb_phy_read(struct mii_bus *bus, int addr, int reg) int value; uint64_t start; - dev_dbg(macb->dev, "%s\n", __func__); - netctl = macb_readl(macb, NCR); netctl |= MACB_BIT(MPE); macb_writel(macb, NCR, netctl); @@ -478,8 +517,6 @@ static int macb_phy_write(struct mii_bus *bus, int addr, int reg, u16 value) unsigned long netctl; unsigned long frame; - dev_dbg(macb->dev, "%s\n", __func__); - netctl = macb_readl(macb, NCR); netctl |= MACB_BIT(MPE); macb_writel(macb, NCR, netctl); @@ -510,8 +547,6 @@ static int macb_get_ethaddr(struct eth_device *edev, unsigned char *adr) u8 addr[6]; int i; - dev_dbg(macb->dev, "%s\n", __func__); - /* Check all 4 address register for vaild address */ for (i = 0; i < 4; i++) { bottom = macb_or_gem_readl(macb, SA1B + i * 8); @@ -537,8 +572,6 @@ static int macb_set_ethaddr(struct eth_device *edev, const unsigned char *adr) { struct macb_device *macb = edev->priv; - dev_dbg(macb->dev, "%s\n", __func__); - /* set hardware address */ macb_or_gem_writel(macb, SA1B, adr[0] | adr[1] << 8 | adr[2] << 16 | adr[3] << 24); macb_or_gem_writel(macb, SA1T, adr[4] | adr[5] << 8); @@ -648,13 +681,117 @@ static void macb_init_rx_buffer_size(struct macb_device *bp, size_t size) size, bp->rx_buffer_size); } -static int macb_probe(struct device_d *dev) +#ifdef CONFIG_COMMON_CLK +/* This structure is only used for MACB on SiFive FU540 devices */ +struct sifive_fu540_macb_mgmt { + void __iomem *reg; + unsigned long rate; + struct clk clk; +}; + +static struct sifive_fu540_macb_mgmt *mgmt; + +static unsigned long fu540_macb_tx_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return mgmt->rate; +} + +static long fu540_macb_tx_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + if (WARN_ON(rate < 2500000)) + return 2500000; + else if (rate == 2500000) + return 2500000; + else if (WARN_ON(rate < 13750000)) + return 2500000; + else if (WARN_ON(rate < 25000000)) + return 25000000; + else if (rate == 25000000) + return 25000000; + else if (WARN_ON(rate < 75000000)) + return 25000000; + else if (WARN_ON(rate < 125000000)) + return 125000000; + else if (rate == 125000000) + return 125000000; + + WARN_ON(rate > 125000000); + + return 125000000; +} + +static int fu540_macb_tx_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + rate = fu540_macb_tx_round_rate(hw, rate, &parent_rate); + if (rate != 125000000) + iowrite32(1, mgmt->reg); + else + iowrite32(0, mgmt->reg); + mgmt->rate = rate; + + return 0; +} + +static const struct clk_ops fu540_c000_ops = { + .recalc_rate = fu540_macb_tx_recalc_rate, + .round_rate = fu540_macb_tx_round_rate, + .set_rate = fu540_macb_tx_set_rate, +}; + +static int fu540_c000_txclk_init(struct device *dev, struct clk **tx_clk) +{ + struct clk *clk; + struct resource *res; + int err = 0; + + mgmt = xzalloc(sizeof(*mgmt)); + + res = dev_request_mem_resource(dev, 1); + if (IS_ERR(res)) + return PTR_ERR(res); + + mgmt->reg = IOMEM(res->start); + + clk = &mgmt->clk; + + clk->name = "sifive-gemgxl-mgmt"; + clk->ops = &fu540_c000_ops; + + err = bclk_register(&mgmt->clk); + if (err) + return err; + + *tx_clk = &mgmt->clk; + + err = clk_enable(*tx_clk); + if (err) { + dev_err(dev, "failed to enable tx_clk (%u)\n", err); + *tx_clk = NULL; + return err; + } + + dev_info(dev, "Registered clk switch '%s'\n", clk->name); + return 0; +} +#else +static int fu540_c000_txclk_init(struct device *dev, struct clk **tx_clk) +{ + return -ENOSYS; +} +#endif + +static int macb_probe(struct device *dev) { struct resource *iores; struct eth_device *edev; struct macb_device *macb; - const char *pclk_name; + const char *pclk_name, *hclk_name; + const struct macb_config *config = NULL; u32 ncfgr; + int ret; macb = xzalloc(sizeof(*macb)); edev = &macb->netdev; @@ -689,22 +826,26 @@ static int macb_probe(struct device_d *dev) macb->phy_addr = pdata->phy_addr; macb->phy_flags = pdata->phy_flags; pclk_name = "macb_clk"; - } else if (IS_ENABLED(CONFIG_OFDEVICE) && dev->device_node) { + hclk_name = NULL; + } else if (IS_ENABLED(CONFIG_OFDEVICE) && dev->of_node) { int ret; struct device_node *mdiobus; - ret = of_get_phy_mode(dev->device_node); + ret = of_get_phy_mode(dev->of_node); if (ret < 0) macb->interface = PHY_INTERFACE_MODE_MII; else macb->interface = ret; - mdiobus = of_get_child_by_name(dev->device_node, "mdio"); + mdiobus = of_get_child_by_name(dev->of_node, "mdio"); if (mdiobus) - macb->miibus.dev.device_node = mdiobus; + macb->miibus.dev.of_node = mdiobus; macb->phy_addr = -1; pclk_name = "pclk"; + hclk_name = "hclk"; + + config = device_get_match_data(dev); } else { dev_err(dev, "macb: no platform_data\n"); return -ENODEV; @@ -727,6 +868,32 @@ static int macb_probe(struct device_d *dev) clk_enable(macb->pclk); + if (hclk_name) { + macb->hclk = clk_get(dev, pclk_name); + if (IS_ERR(macb->hclk)) { + dev_err(dev, "no hclk\n"); + return PTR_ERR(macb->hclk); + } + + clk_enable(macb->hclk); + } + + macb->txclk = clk_get(dev, "tx_clk"); + if (!IS_ERR(macb->txclk)) + clk_enable(macb->txclk); + else + macb->txclk = NULL; + + macb->rxclk = clk_get(dev, "rx_clk"); + if (!IS_ERR(macb->rxclk)) + clk_enable(macb->rxclk); + + if (config) { + ret = config->txclk_init(dev, &macb->txclk); + if (ret) + return ret; + } + macb->is_gem = read_is_gem(macb); if (macb_is_gem(macb)) @@ -736,13 +903,15 @@ static int macb_probe(struct device_d *dev) macb_init_rx_buffer_size(macb, PKTSIZE); macb->rx_buffer = dma_alloc(macb->rx_buffer_size * macb->rx_ring_size); - macb->rx_ring = dma_alloc_coherent(RX_RING_BYTES(macb), DMA_ADDRESS_BROKEN); - macb->tx_ring = dma_alloc_coherent(TX_RING_BYTES, DMA_ADDRESS_BROKEN); + macb->rx_ring = dma_alloc_coherent(RX_RING_BYTES(macb), &macb->rx_ring_phys); + macb->tx_ring = dma_alloc_coherent(TX_RING_BYTES, &macb->tx_ring_phys); if (macb->is_gem) macb->gem_q1_descs = dma_alloc_coherent(GEM_Q1_DESC_BYTES, DMA_ADDRESS_BROKEN); + macb->rx_packet_buf = xmalloc(PKTSIZE); + macb_reset_hw(macb); ncfgr = macb_mdc_clk_div(macb); ncfgr |= MACB_BIT(PAE); /* PAuse Enable */ @@ -750,7 +919,9 @@ static int macb_probe(struct device_d *dev) ncfgr |= macb_dbw(macb); macb_writel(macb, NCFGR, ncfgr); - macb_init(macb); + ret = macb_init(macb); + if (ret) + return ret; mdiobus_register(&macb->miibus); eth_register(edev); @@ -761,22 +932,32 @@ static int macb_probe(struct device_d *dev) return 0; } -static void macb_remove(struct device_d *dev) +static void macb_remove(struct device *dev) { struct macb_device *macb = dev->priv; macb_halt(&macb->netdev); + + free(macb->rx_packet_buf); } +static const struct macb_config fu540_c000_config = { + .txclk_init = fu540_c000_txclk_init, +}; + static const struct of_device_id macb_dt_ids[] = { { .compatible = "cdns,at91sam9260-macb",}, { .compatible = "atmel,sama5d2-gem",}, { .compatible = "atmel,sama5d3-gem",}, - { .compatible = "cdns,zynqmp-gem",}, + { .compatible = "atmel,sama5d4-gem",}, + { .compatible = "xlnx,zynq-gem",}, + { .compatible = "xlnx,zynqmp-gem",}, + { .compatible = "sifive,fu540-c000-gem", .data = &fu540_c000_config }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, macb_dt_ids); -static struct driver_d macb_driver = { +static struct driver macb_driver = { .name = "macb", .probe = macb_probe, .remove = macb_remove, |