[U-Boot] [PATCH 0/5] net: altera_tse: add mSG-DMA support

The Modular Scatter-Gather DMA core is a new DMA core to work with the Altera Triple-Speed Ethernet MegaCore. It replaces the legacy Scatter-Gather Direct Memory Access (SG-DMA) controller core. Please find details on the "Embedded Peripherals IP User Guide" of Altera.
Thomas Chou (5): net: zap altera_tse_initialize prototypes net: altera_tse: factor out stop mac func net: altera_tse: wait sgdma in altera_tse_recv net: altera_tse: add priv ops to prepare msgdma support net: altera_tse: add mSG-DMA support
drivers/net/altera_tse.c | 237 +++++++++++++++++++++++++++++++++++++++++------ drivers/net/altera_tse.h | 80 +++++++++++++++- include/netdev.h | 3 - 3 files changed, 285 insertions(+), 35 deletions(-)

Zap the altera_tse_initialize() prototypes, since it is converted to driver model.
Signed-off-by: Thomas Chou thomas@wytron.com.tw --- include/netdev.h | 3 --- 1 file changed, 3 deletions(-)
diff --git a/include/netdev.h b/include/netdev.h index 3d5a54f..28eab46 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -25,9 +25,6 @@ int board_eth_init(bd_t *bis); int cpu_eth_init(bd_t *bis);
/* Driver initialization prototypes */ -int altera_tse_initialize(u8 dev_num, int mac_base, - int sgdma_rx_base, int sgdma_tx_base, - u32 sgdma_desc_base, u32 sgdma_desc_size); int at91emac_register(bd_t *bis, unsigned long iobase); int au1x00_enet_initialize(bd_t*); int ax88180_initialize(bd_t *bis);

Factor out the stop mac function to prepare msgdma support.
Signed-off-by: Thomas Chou thomas@wytron.com.tw --- drivers/net/altera_tse.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-)
diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c index b2002f4..fe8c524 100644 --- a/drivers/net/altera_tse.c +++ b/drivers/net/altera_tse.c @@ -223,16 +223,33 @@ static int altera_tse_free_pkt(struct udevice *dev, uchar *packet, return 0; }
+static void altera_tse_stop_mac(struct altera_tse_priv *priv) +{ + struct alt_tse_mac *mac_dev = priv->mac_dev; + u32 status; + ulong ctime; + + /* reset the mac */ + writel(ALTERA_TSE_CMD_SW_RESET_MSK, &mac_dev->command_config); + ctime = get_timer(0); + while (1) { + status = readl(&mac_dev->command_config); + if (!(status & ALTERA_TSE_CMD_SW_RESET_MSK)) + break; + if (get_timer(ctime) > ALT_TSE_SW_RESET_TIMEOUT) { + debug("Reset mac timeout\n"); + break; + } + } +} + static void altera_tse_stop(struct udevice *dev) { struct altera_tse_priv *priv = dev_get_priv(dev); - struct alt_tse_mac *mac_dev = priv->mac_dev; struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx; struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx; struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; - u32 status; int ret; - ulong ctime;
/* clear rx desc & wait for sgdma to complete */ rx_desc->descriptor_control = 0; @@ -248,18 +265,7 @@ static void altera_tse_stop(struct udevice *dev) writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &tx_sgdma->control);
- /* reset the mac */ - writel(ALTERA_TSE_CMD_SW_RESET_MSK, &mac_dev->command_config); - ctime = get_timer(0); - while (1) { - status = readl(&mac_dev->command_config); - if (!(status & ALTERA_TSE_CMD_SW_RESET_MSK)) - break; - if (get_timer(ctime) > ALT_TSE_SW_RESET_TIMEOUT) { - debug("Reset mac timeout\n"); - break; - } - } + altera_tse_stop_mac(priv); }
static int tse_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)

Move the sgdma wait from free_pkt to recv. This is the proper place to wait recv sgdma done.
Signed-off-by: Thomas Chou thomas@wytron.com.tw --- drivers/net/altera_tse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c index fe8c524..8ec0beb 100644 --- a/drivers/net/altera_tse.c +++ b/drivers/net/altera_tse.c @@ -186,6 +186,7 @@ static int altera_tse_recv(struct udevice *dev, int flags, uchar **packetp)
if (rx_desc->descriptor_status & ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) { + alt_sgdma_wait_transfer(priv->sgdma_rx); packet_length = rx_desc->actual_bytes_transferred; debug("recv %d bytes\n", packet_length); *packetp = priv->rx_buf; @@ -203,7 +204,6 @@ static int altera_tse_free_pkt(struct udevice *dev, uchar *packet, struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; unsigned long rx_buf = (unsigned long)priv->rx_buf;
- alt_sgdma_wait_transfer(priv->sgdma_rx); invalidate_dcache_range(rx_buf, rx_buf + PKTSIZE_ALIGN); alt_sgdma_construct_descriptor( rx_desc,

Add priv ops to prepare msgdma support. These ops are dma type specific.
Signed-off-by: Thomas Chou thomas@wytron.com.tw --- drivers/net/altera_tse.c | 86 ++++++++++++++++++++++++++++++++++++------------ drivers/net/altera_tse.h | 20 ++++++++--- 2 files changed, 81 insertions(+), 25 deletions(-)
diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c index 8ec0beb..3848530 100644 --- a/drivers/net/altera_tse.c +++ b/drivers/net/altera_tse.c @@ -152,13 +152,11 @@ static void tse_adjust_link(struct altera_tse_priv *priv, writel(refvar, &mac_dev->command_config); }
-static int altera_tse_send(struct udevice *dev, void *packet, int length) +static int altera_tse_send_sgdma(struct udevice *dev, void *packet, int length) { struct altera_tse_priv *priv = dev_get_priv(dev); struct alt_sgdma_descriptor *tx_desc = priv->tx_desc; - unsigned long tx_buf = (unsigned long)packet;
- flush_dcache_range(tx_buf, tx_buf + length); alt_sgdma_construct_descriptor( tx_desc, tx_desc + 1, @@ -178,7 +176,8 @@ static int altera_tse_send(struct udevice *dev, void *packet, int length) return tx_desc->actual_bytes_transferred; }
-static int altera_tse_recv(struct udevice *dev, int flags, uchar **packetp) +static int altera_tse_recv_sgdma(struct udevice *dev, int flags, + uchar **packetp) { struct altera_tse_priv *priv = dev_get_priv(dev); struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; @@ -197,14 +196,12 @@ static int altera_tse_recv(struct udevice *dev, int flags, uchar **packetp) return -EAGAIN; }
-static int altera_tse_free_pkt(struct udevice *dev, uchar *packet, - int length) +static int altera_tse_free_pkt_sgdma(struct udevice *dev, uchar *packet, + int length) { struct altera_tse_priv *priv = dev_get_priv(dev); struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; - unsigned long rx_buf = (unsigned long)priv->rx_buf;
- invalidate_dcache_range(rx_buf, rx_buf + PKTSIZE_ALIGN); alt_sgdma_construct_descriptor( rx_desc, rx_desc + 1, @@ -243,7 +240,7 @@ static void altera_tse_stop_mac(struct altera_tse_priv *priv) } }
-static void altera_tse_stop(struct udevice *dev) +static void altera_tse_stop_sgdma(struct udevice *dev) { struct altera_tse_priv *priv = dev_get_priv(dev); struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx; @@ -264,8 +261,6 @@ static void altera_tse_stop(struct udevice *dev) if (ret == -ETIMEDOUT) writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &tx_sgdma->control); - - altera_tse_stop_mac(priv); }
static int tse_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) @@ -364,6 +359,42 @@ static int altera_tse_write_hwaddr(struct udevice *dev) return 0; }
+static int altera_tse_send(struct udevice *dev, void *packet, int length) +{ + struct altera_tse_priv *priv = dev_get_priv(dev); + unsigned long tx_buf = (unsigned long)packet; + + flush_dcache_range(tx_buf, tx_buf + length); + + return priv->ops->send(dev, packet, length); +} + +static int altera_tse_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct altera_tse_priv *priv = dev_get_priv(dev); + + return priv->ops->recv(dev, flags, packetp); +} + +static int altera_tse_free_pkt(struct udevice *dev, uchar *packet, + int length) +{ + struct altera_tse_priv *priv = dev_get_priv(dev); + unsigned long rx_buf = (unsigned long)priv->rx_buf; + + invalidate_dcache_range(rx_buf, rx_buf + PKTSIZE_ALIGN); + + return priv->ops->free_pkt(dev, packet, length); +} + +static void altera_tse_stop(struct udevice *dev) +{ + struct altera_tse_priv *priv = dev_get_priv(dev); + + priv->ops->stop(dev); + altera_tse_stop_mac(priv); +} + static int altera_tse_start(struct udevice *dev) { struct altera_tse_priv *priv = dev_get_priv(dev); @@ -411,6 +442,13 @@ static int altera_tse_start(struct udevice *dev) return 0; }
+static const struct tse_ops tse_sgdma_ops = { + .send = altera_tse_send_sgdma, + .recv = altera_tse_recv_sgdma, + .free_pkt = altera_tse_free_pkt_sgdma, + .stop = altera_tse_stop_sgdma, +}; + static int altera_tse_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); @@ -425,6 +463,9 @@ static int altera_tse_probe(struct udevice *dev) int len, idx; int ret;
+ priv->dma_type = dev_get_driver_data(dev); + if (priv->dma_type == ALT_SGDMA) + priv->ops = &tse_sgdma_ops; /* * decode regs. there are multiple reg tuples, and they need to * match with reg-names. @@ -468,15 +509,18 @@ static int altera_tse_probe(struct udevice *dev) priv->phyaddr = fdtdec_get_int(blob, addr, "reg", 0); /* init desc */ - len = sizeof(struct alt_sgdma_descriptor) * 4; - if (!desc_mem) { - desc_mem = dma_alloc_coherent(len, &addr); - if (!desc_mem) - return -ENOMEM; + if (priv->dma_type == ALT_SGDMA) { + len = sizeof(struct alt_sgdma_descriptor) * 4; + if (!desc_mem) { + desc_mem = dma_alloc_coherent(len, &addr); + if (!desc_mem) + return -ENOMEM; + } + memset(desc_mem, 0, len); + priv->tx_desc = desc_mem; + priv->rx_desc = priv->tx_desc + + 2 * sizeof(struct alt_sgdma_descriptor); } - memset(desc_mem, 0, len); - priv->tx_desc = desc_mem; - priv->rx_desc = priv->tx_desc + 2; /* allocate recv packet buffer */ priv->rx_buf = malloc_cache_aligned(PKTSIZE_ALIGN); if (!priv->rx_buf) @@ -523,8 +567,8 @@ static const struct eth_ops altera_tse_ops = { };
static const struct udevice_id altera_tse_ids[] = { - { .compatible = "altr,tse-1.0", }, - { } + { .compatible = "altr,tse-1.0", .data = ALT_SGDMA }, + {} };
U_BOOT_DRIVER(altera_tse) = { diff --git a/drivers/net/altera_tse.h b/drivers/net/altera_tse.h index 471a880..fae2378 100644 --- a/drivers/net/altera_tse.h +++ b/drivers/net/altera_tse.h @@ -13,6 +13,9 @@
#define __packed_1_ __packed __aligned(1)
+/* dma type */ +#define ALT_SGDMA 0 + /* SGDMA Stuff */ #define ALT_SGDMA_STATUS_BUSY_MSK BIT(4)
@@ -141,19 +144,28 @@ struct alt_tse_mac { u32 reserved3[0x38]; };
+struct tse_ops { + int (*send)(struct udevice *dev, void *packet, int length); + int (*recv)(struct udevice *dev, int flags, uchar **packetp); + int (*free_pkt)(struct udevice *dev, uchar *packet, int length); + void (*stop)(struct udevice *dev); +}; + struct altera_tse_priv { struct alt_tse_mac *mac_dev; - struct alt_sgdma_registers *sgdma_rx; - struct alt_sgdma_registers *sgdma_tx; + void *sgdma_rx; + void *sgdma_tx; unsigned int rx_fifo_depth; unsigned int tx_fifo_depth; - struct alt_sgdma_descriptor *rx_desc; - struct alt_sgdma_descriptor *tx_desc; + void *rx_desc; + void *tx_desc; unsigned char *rx_buf; unsigned int phyaddr; unsigned int interface; struct phy_device *phydev; struct mii_dev *bus; + const struct tse_ops *ops; + int dma_type; };
#endif /* _ALTERA_TSE_H_ */

The Modular Scatter-Gather DMA core is a new DMA core to work with the Altera Triple-Speed Ethernet MegaCore. It replaces the legacy Scatter-Gather Direct Memory Access (SG-DMA) controller core. Please find details on the "Embedded Peripherals IP User Guide" of Altera.
Signed-off-by: Thomas Chou thomas@wytron.com.tw --- drivers/net/altera_tse.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/altera_tse.h | 60 ++++++++++++++++++++++ 2 files changed, 191 insertions(+)
diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c index 3848530..5692fe9 100644 --- a/drivers/net/altera_tse.c +++ b/drivers/net/altera_tse.c @@ -263,6 +263,121 @@ static void altera_tse_stop_sgdma(struct udevice *dev) &tx_sgdma->control); }
+static void msgdma_reset(struct msgdma_csr *csr) +{ + u32 status; + ulong ctime; + + /* Reset mSGDMA */ + writel(MSGDMA_CSR_STAT_MASK, &csr->status); + writel(MSGDMA_CSR_CTL_RESET, &csr->control); + ctime = get_timer(0); + while (1) { + status = readl(&csr->status); + if (!(status & MSGDMA_CSR_STAT_RESETTING)) + break; + if (get_timer(ctime) > ALT_TSE_SW_RESET_TIMEOUT) { + debug("Reset msgdma timeout\n"); + break; + } + } + /* Clear status */ + writel(MSGDMA_CSR_STAT_MASK, &csr->status); +} + +static u32 msgdma_wait(struct msgdma_csr *csr) +{ + u32 status; + ulong ctime; + + /* Wait for the descriptor to complete */ + ctime = get_timer(0); + while (1) { + status = readl(&csr->status); + if (!(status & MSGDMA_CSR_STAT_BUSY)) + break; + if (get_timer(ctime) > ALT_TSE_SGDMA_BUSY_TIMEOUT) { + debug("sgdma timeout\n"); + break; + } + } + /* Clear status */ + writel(MSGDMA_CSR_STAT_MASK, &csr->status); + + return status; +} + +static int altera_tse_send_msgdma(struct udevice *dev, void *packet, + int length) +{ + struct altera_tse_priv *priv = dev_get_priv(dev); + struct msgdma_extended_desc *desc = priv->tx_desc; + u32 tx_buf = virt_to_phys(packet); + u32 status; + + writel(tx_buf, &desc->read_addr_lo); + writel(0, &desc->read_addr_hi); + writel(0, &desc->write_addr_lo); + writel(0, &desc->write_addr_hi); + writel(length, &desc->len); + writel(0, &desc->burst_seq_num); + writel(MSGDMA_DESC_TX_STRIDE, &desc->stride); + writel(MSGDMA_DESC_CTL_TX_SINGLE, &desc->control); + status = msgdma_wait(priv->sgdma_tx); + debug("sent %d bytes, status %08x\n", length, status); + + return 0; +} + +static int altera_tse_recv_msgdma(struct udevice *dev, int flags, + uchar **packetp) +{ + struct altera_tse_priv *priv = dev_get_priv(dev); + struct msgdma_csr *csr = priv->sgdma_rx; + struct msgdma_response *resp = priv->rx_resp; + u32 level, length, status; + + level = readl(&csr->resp_fill_level); + if (level & 0xffff) { + length = readl(&resp->bytes_transferred); + status = readl(&resp->status); + debug("recv %d bytes, status %08x\n", length, status); + *packetp = priv->rx_buf; + + return length; + } + + return -EAGAIN; +} + +static int altera_tse_free_pkt_msgdma(struct udevice *dev, uchar *packet, + int length) +{ + struct altera_tse_priv *priv = dev_get_priv(dev); + struct msgdma_extended_desc *desc = priv->rx_desc; + u32 rx_buf = virt_to_phys(priv->rx_buf); + + writel(0, &desc->read_addr_lo); + writel(0, &desc->read_addr_hi); + writel(rx_buf, &desc->write_addr_lo); + writel(0, &desc->write_addr_hi); + writel(PKTSIZE_ALIGN, &desc->len); + writel(0, &desc->burst_seq_num); + writel(MSGDMA_DESC_RX_STRIDE, &desc->stride); + writel(MSGDMA_DESC_CTL_RX_SINGLE, &desc->control); + debug("recv setup\n"); + + return 0; +} + +static void altera_tse_stop_msgdma(struct udevice *dev) +{ + struct altera_tse_priv *priv = dev_get_priv(dev); + + msgdma_reset(priv->sgdma_rx); + msgdma_reset(priv->sgdma_tx); +} + static int tse_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) { struct altera_tse_priv *priv = bus->priv; @@ -449,6 +564,13 @@ static const struct tse_ops tse_sgdma_ops = { .stop = altera_tse_stop_sgdma, };
+static const struct tse_ops tse_msgdma_ops = { + .send = altera_tse_send_msgdma, + .recv = altera_tse_recv_msgdma, + .free_pkt = altera_tse_free_pkt_msgdma, + .stop = altera_tse_stop_msgdma, +}; + static int altera_tse_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); @@ -466,6 +588,8 @@ static int altera_tse_probe(struct udevice *dev) priv->dma_type = dev_get_driver_data(dev); if (priv->dma_type == ALT_SGDMA) priv->ops = &tse_sgdma_ops; + else + priv->ops = &tse_msgdma_ops; /* * decode regs. there are multiple reg tuples, and they need to * match with reg-names. @@ -490,8 +614,14 @@ static int altera_tse_probe(struct udevice *dev) priv->mac_dev = base; else if (strcmp(list, "rx_csr") == 0) priv->sgdma_rx = base; + else if (strcmp(list, "rx_desc") == 0) + priv->rx_desc = base; + else if (strcmp(list, "rx_resp") == 0) + priv->rx_resp = base; else if (strcmp(list, "tx_csr") == 0) priv->sgdma_tx = base; + else if (strcmp(list, "tx_desc") == 0) + priv->tx_desc = base; else if (strcmp(list, "s1") == 0) desc_mem = base; idx += addrc + sizec; @@ -567,6 +697,7 @@ static const struct eth_ops altera_tse_ops = { };
static const struct udevice_id altera_tse_ids[] = { + { .compatible = "altr,tse-msgdma-1.0", .data = ALT_MSGDMA }, { .compatible = "altr,tse-1.0", .data = ALT_SGDMA }, {} }; diff --git a/drivers/net/altera_tse.h b/drivers/net/altera_tse.h index fae2378..2b1af81 100644 --- a/drivers/net/altera_tse.h +++ b/drivers/net/altera_tse.h @@ -15,6 +15,7 @@
/* dma type */ #define ALT_SGDMA 0 +#define ALT_MSGDMA 1
/* SGDMA Stuff */ #define ALT_SGDMA_STATUS_BUSY_MSK BIT(4) @@ -87,6 +88,64 @@ struct alt_sgdma_registers { u32 descriptor_pad[3]; };
+/* mSGDMA Stuff */ + +/* mSGDMA extended descriptor format */ +struct msgdma_extended_desc { + u32 read_addr_lo; /* data buffer source address low bits */ + u32 write_addr_lo; /* data buffer destination address low bits */ + u32 len; + u32 burst_seq_num; + u32 stride; + u32 read_addr_hi; /* data buffer source address high bits */ + u32 write_addr_hi; /* data buffer destination address high bits */ + u32 control; /* characteristics of the transfer */ +}; + +/* mSGDMA descriptor control field bit definitions */ +#define MSGDMA_DESC_CTL_GEN_SOP BIT(8) +#define MSGDMA_DESC_CTL_GEN_EOP BIT(9) +#define MSGDMA_DESC_CTL_END_ON_EOP BIT(12) +#define MSGDMA_DESC_CTL_END_ON_LEN BIT(13) +#define MSGDMA_DESC_CTL_GO BIT(31) + +/* Tx buffer control flags */ +#define MSGDMA_DESC_CTL_TX_SINGLE (MSGDMA_DESC_CTL_GEN_SOP | \ + MSGDMA_DESC_CTL_GEN_EOP | \ + MSGDMA_DESC_CTL_GO) + +#define MSGDMA_DESC_CTL_RX_SINGLE (MSGDMA_DESC_CTL_END_ON_EOP | \ + MSGDMA_DESC_CTL_END_ON_LEN | \ + MSGDMA_DESC_CTL_GO) + +/* mSGDMA extended descriptor stride definitions */ +#define MSGDMA_DESC_TX_STRIDE 0x00010001 +#define MSGDMA_DESC_RX_STRIDE 0x00010001 + +/* mSGDMA dispatcher control and status register map */ +struct msgdma_csr { + u32 status; /* Read/Clear */ + u32 control; /* Read/Write */ + u32 rw_fill_level; + u32 resp_fill_level; /* bit 15:0 */ + u32 rw_seq_num; + u32 pad[3]; /* reserved */ +}; + +/* mSGDMA CSR status register bit definitions */ +#define MSGDMA_CSR_STAT_BUSY BIT(0) +#define MSGDMA_CSR_STAT_RESETTING BIT(6) +#define MSGDMA_CSR_STAT_MASK 0x3FF + +/* mSGDMA CSR control register bit definitions */ +#define MSGDMA_CSR_CTL_RESET BIT(1) + +/* mSGDMA response register map */ +struct msgdma_response { + u32 bytes_transferred; + u32 status; +}; + /* TSE Stuff */ #define ALTERA_TSE_CMD_TX_ENA_MSK BIT(0) #define ALTERA_TSE_CMD_RX_ENA_MSK BIT(1) @@ -159,6 +218,7 @@ struct altera_tse_priv { unsigned int tx_fifo_depth; void *rx_desc; void *tx_desc; + void *rx_resp; unsigned char *rx_buf; unsigned int phyaddr; unsigned int interface;

On Monday, November 09, 2015 at 07:37:50 AM, Thomas Chou wrote:
The Modular Scatter-Gather DMA core is a new DMA core to work with the Altera Triple-Speed Ethernet MegaCore. It replaces the legacy Scatter-Gather Direct Memory Access (SG-DMA) controller core. Please find details on the "Embedded Peripherals IP User Guide" of Altera.
Thomas Chou (5): net: zap altera_tse_initialize prototypes net: altera_tse: factor out stop mac func net: altera_tse: wait sgdma in altera_tse_recv net: altera_tse: add priv ops to prepare msgdma support net: altera_tse: add mSG-DMA support
drivers/net/altera_tse.c | 237 +++++++++++++++++++++++++++++++++++++++++------ drivers/net/altera_tse.h | 80 +++++++++++++++- include/netdev.h | 3 - 3 files changed, 285 insertions(+), 35 deletions(-)
Reviewed-by: Marek Vasut marex@denx.de
Best regards, Marek Vasut
participants (2)
-
Marek Vasut
-
Thomas Chou