net: macb: Add DMA 64-bit address support for macb
Enable 32-bit or 64-bit DMA in the macb driver based on the macb
hardware compatibility and it is configured with structure macb_config
in the driver.
The Microchip PolarFire SoC Memory Protection Unit(MPU) gives the 64-bit
DMA access with the GEM, the MPU transactions on the AXI bus is 64-bit
not 32-bit So 64-bit DMA is enabled for the Microchip PolarFire SoC GEM.
Signed-off-by: Padmarao Begari <padmarao.begari@microchip.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Tested-by: Bin Meng <bin.meng@windriver.com>
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index e287c29..0c2ac81 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -83,7 +83,16 @@
u32 ctrl;
};
-#define DMA_DESC_BYTES(n) (n * sizeof(struct macb_dma_desc))
+struct macb_dma_desc_64 {
+ u32 addrh;
+ u32 unused;
+};
+
+#define HW_DMA_CAP_32B 0
+#define HW_DMA_CAP_64B 1
+
+#define DMA_DESC_SIZE 16
+#define DMA_DESC_BYTES(n) ((n) * DMA_DESC_SIZE)
#define MACB_TX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_TX_RING_SIZE))
#define MACB_RX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_RX_RING_SIZE))
#define MACB_TX_DUMMY_DMA_DESC_SIZE (DMA_DESC_BYTES(1))
@@ -137,6 +146,7 @@
struct macb_config {
unsigned int dma_burst_length;
+ unsigned int hw_dma_cap;
int (*clk_init)(struct udevice *dev, ulong rate);
};
@@ -307,6 +317,24 @@
#if defined(CONFIG_CMD_NET)
+static struct macb_dma_desc_64 *macb_64b_desc(struct macb_dma_desc *desc)
+{
+ return (struct macb_dma_desc_64 *)((void *)desc
+ + sizeof(struct macb_dma_desc));
+}
+
+static void macb_set_addr(struct macb_device *macb, struct macb_dma_desc *desc,
+ ulong addr)
+{
+ struct macb_dma_desc_64 *desc_64;
+
+ if (macb->config->hw_dma_cap & HW_DMA_CAP_64B) {
+ desc_64 = macb_64b_desc(desc);
+ desc_64->addrh = upper_32_bits(addr);
+ }
+ desc->addr = lower_32_bits(addr);
+}
+
static int _macb_send(struct macb_device *macb, const char *name, void *packet,
int length)
{
@@ -325,8 +353,12 @@
macb->tx_head++;
}
+ if (macb->config->hw_dma_cap & HW_DMA_CAP_64B)
+ tx_head = tx_head * 2;
+
macb->tx_ring[tx_head].ctrl = ctrl;
- macb->tx_ring[tx_head].addr = paddr;
+ macb_set_addr(macb, &macb->tx_ring[tx_head], paddr);
+
barrier();
macb_flush_ring_desc(macb, TX);
macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART));
@@ -363,19 +395,28 @@
unsigned int new_tail)
{
unsigned int i;
+ unsigned int count;
i = macb->rx_tail;
macb_invalidate_ring_desc(macb, RX);
while (i > new_tail) {
- macb->rx_ring[i].addr &= ~MACB_BIT(RX_USED);
+ if (macb->config->hw_dma_cap & HW_DMA_CAP_64B)
+ count = i * 2;
+ else
+ count = i;
+ macb->rx_ring[count].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);
+ if (macb->config->hw_dma_cap & HW_DMA_CAP_64B)
+ count = i * 2;
+ else
+ count = i;
+ macb->rx_ring[count].addr &= ~MACB_BIT(RX_USED);
i++;
}
@@ -390,16 +431,25 @@
void *buffer;
int length;
u32 status;
+ u8 flag = false;
macb->wrapped = false;
for (;;) {
macb_invalidate_ring_desc(macb, RX);
+ if (macb->config->hw_dma_cap & HW_DMA_CAP_64B)
+ next_rx_tail = next_rx_tail * 2;
+
if (!(macb->rx_ring[next_rx_tail].addr & MACB_BIT(RX_USED)))
return -EAGAIN;
status = macb->rx_ring[next_rx_tail].ctrl;
if (status & MACB_BIT(RX_SOF)) {
+ if (macb->config->hw_dma_cap & HW_DMA_CAP_64B) {
+ next_rx_tail = next_rx_tail / 2;
+ flag = true;
+ }
+
if (next_rx_tail != macb->rx_tail)
reclaim_rx_buffers(macb, next_rx_tail);
macb->wrapped = false;
@@ -426,11 +476,22 @@
*packetp = buffer;
}
+ if (macb->config->hw_dma_cap & HW_DMA_CAP_64B) {
+ if (!flag)
+ next_rx_tail = next_rx_tail / 2;
+ }
+
if (++next_rx_tail >= MACB_RX_RING_SIZE)
next_rx_tail = 0;
macb->next_rx_tail = next_rx_tail;
return length;
} else {
+ if (macb->config->hw_dma_cap & HW_DMA_CAP_64B) {
+ if (!flag)
+ next_rx_tail = next_rx_tail / 2;
+ flag = false;
+ }
+
if (++next_rx_tail >= MACB_RX_RING_SIZE) {
macb->wrapped = true;
next_rx_tail = 0;
@@ -718,6 +779,7 @@
{
int i, num_queues = 1;
u32 queue_mask;
+ unsigned long paddr;
/* bit 0 is never set but queue 0 always exists */
queue_mask = gem_readl(macb, DCFG6) & 0xff;
@@ -731,10 +793,18 @@
macb->dummy_desc->addr = 0;
flush_dcache_range(macb->dummy_desc_dma, macb->dummy_desc_dma +
ALIGN(MACB_TX_DUMMY_DMA_DESC_SIZE, PKTALIGN));
+ paddr = macb->dummy_desc_dma;
- for (i = 1; i < num_queues; i++)
- gem_writel_queue_TBQP(macb, macb->dummy_desc_dma, i - 1);
-
+ for (i = 1; i < num_queues; i++) {
+ gem_writel_queue_TBQP(macb, lower_32_bits(paddr), i - 1);
+ gem_writel_queue_RBQP(macb, lower_32_bits(paddr), i - 1);
+ if (macb->config->hw_dma_cap & HW_DMA_CAP_64B) {
+ gem_writel_queue_TBQPH(macb, upper_32_bits(paddr),
+ i - 1);
+ gem_writel_queue_RBQPH(macb, upper_32_bits(paddr),
+ i - 1);
+ }
+ }
return 0;
}
@@ -760,6 +830,9 @@
dmacfg &= ~GEM_BIT(ENDIA_DESC);
dmacfg &= ~GEM_BIT(ADDR64);
+ if (macb->config->hw_dma_cap & HW_DMA_CAP_64B)
+ dmacfg |= GEM_BIT(ADDR64);
+
gem_writel(macb, DMACFG, dmacfg);
}
@@ -775,6 +848,7 @@
unsigned long paddr;
int ret;
int i;
+ int count;
/*
* macb_halt should have been called at some point before now,
@@ -786,20 +860,28 @@
for (i = 0; i < MACB_RX_RING_SIZE; i++) {
if (i == (MACB_RX_RING_SIZE - 1))
paddr |= MACB_BIT(RX_WRAP);
- macb->rx_ring[i].addr = paddr;
- macb->rx_ring[i].ctrl = 0;
+ if (macb->config->hw_dma_cap & HW_DMA_CAP_64B)
+ count = i * 2;
+ else
+ count = i;
+ macb->rx_ring[count].ctrl = 0;
+ macb_set_addr(macb, &macb->rx_ring[count], paddr);
paddr += macb->rx_buffer_size;
}
macb_flush_ring_desc(macb, RX);
macb_flush_rx_buffer(macb);
for (i = 0; i < MACB_TX_RING_SIZE; i++) {
- macb->tx_ring[i].addr = 0;
+ if (macb->config->hw_dma_cap & HW_DMA_CAP_64B)
+ count = i * 2;
+ else
+ count = i;
+ macb_set_addr(macb, &macb->tx_ring[count], 0);
if (i == (MACB_TX_RING_SIZE - 1))
- macb->tx_ring[i].ctrl = MACB_BIT(TX_USED) |
+ macb->tx_ring[count].ctrl = MACB_BIT(TX_USED) |
MACB_BIT(TX_WRAP);
else
- macb->tx_ring[i].ctrl = MACB_BIT(TX_USED);
+ macb->tx_ring[count].ctrl = MACB_BIT(TX_USED);
}
macb_flush_ring_desc(macb, TX);
@@ -812,8 +894,12 @@
gem_writel(macb, DMACFG, MACB_ZYNQ_GEM_DMACR_INIT);
#endif
- macb_writel(macb, RBQP, macb->rx_ring_dma);
- macb_writel(macb, TBQP, macb->tx_ring_dma);
+ macb_writel(macb, RBQP, lower_32_bits(macb->rx_ring_dma));
+ macb_writel(macb, TBQP, lower_32_bits(macb->tx_ring_dma));
+ if (macb->config->hw_dma_cap & HW_DMA_CAP_64B) {
+ macb_writel(macb, RBQPH, upper_32_bits(macb->rx_ring_dma));
+ macb_writel(macb, TBQPH, upper_32_bits(macb->tx_ring_dma));
+ }
if (macb_is_gem(macb)) {
/* Initialize DMA properties */
@@ -1217,6 +1303,7 @@
static const struct macb_config default_gem_config = {
.dma_burst_length = 16,
+ .hw_dma_cap = HW_DMA_CAP_32B,
.clk_init = NULL,
};
@@ -1227,8 +1314,8 @@
const char *phy_mode;
int ret;
- phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode",
- NULL);
+ phy_mode = dev_read_prop(dev, "phy-mode", NULL);
+
if (phy_mode)
macb->phy_interface = phy_get_interface_by_name(phy_mode);
if (macb->phy_interface == -1) {
@@ -1304,13 +1391,21 @@
return macb_late_eth_of_to_plat(dev);
}
+static const struct macb_config microchip_config = {
+ .dma_burst_length = 16,
+ .hw_dma_cap = HW_DMA_CAP_64B,
+ .clk_init = NULL,
+};
+
static const struct macb_config sama5d4_config = {
.dma_burst_length = 4,
+ .hw_dma_cap = HW_DMA_CAP_32B,
.clk_init = NULL,
};
static const struct macb_config sifive_config = {
.dma_burst_length = 16,
+ .hw_dma_cap = HW_DMA_CAP_32B,
.clk_init = macb_sifive_clk_init,
};
@@ -1324,6 +1419,8 @@
{ .compatible = "cdns,zynq-gem" },
{ .compatible = "sifive,fu540-c000-gem",
.data = (ulong)&sifive_config },
+ { .compatible = "microchip,mpfs-mss-gem",
+ .data = (ulong)µchip_config },
{ }
};
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 9b16383..72b84ae 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -768,5 +768,11 @@
#define GEM_RX_CSUM_CHECKED_MASK 2
#define gem_writel_queue_TBQP(port, value, queue_num) \
writel((value), (port)->regs + GEM_TBQP(queue_num))
+#define gem_writel_queue_TBQPH(port, value, queue_num) \
+ writel((value), (port)->regs + GEM_TBQPH(queue_num))
+#define gem_writel_queue_RBQP(port, value, queue_num) \
+ writel((value), (port)->regs + GEM_RBQP(queue_num))
+#define gem_writel_queue_RBQPH(port, value, queue_num) \
+ writel((value), (port)->regs + GEM_RBQPH(queue_num))
#endif /* __DRIVERS_MACB_H__ */