18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* Altera TSE SGDMA and MSGDMA Linux driver
38c2ecf20Sopenharmony_ci * Copyright (C) 2014 Altera Corporation. All rights reserved
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
78c2ecf20Sopenharmony_ci#include "altera_utils.h"
88c2ecf20Sopenharmony_ci#include "altera_tse.h"
98c2ecf20Sopenharmony_ci#include "altera_msgdmahw.h"
108c2ecf20Sopenharmony_ci#include "altera_msgdma.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci/* No initialization work to do for MSGDMA */
138c2ecf20Sopenharmony_ciint msgdma_initialize(struct altera_tse_private *priv)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	return 0;
168c2ecf20Sopenharmony_ci}
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_civoid msgdma_uninitialize(struct altera_tse_private *priv)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci}
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_civoid msgdma_start_rxdma(struct altera_tse_private *priv)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci}
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_civoid msgdma_reset(struct altera_tse_private *priv)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	int counter;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	/* Reset Rx mSGDMA */
318c2ecf20Sopenharmony_ci	csrwr32(MSGDMA_CSR_STAT_MASK, priv->rx_dma_csr,
328c2ecf20Sopenharmony_ci		msgdma_csroffs(status));
338c2ecf20Sopenharmony_ci	csrwr32(MSGDMA_CSR_CTL_RESET, priv->rx_dma_csr,
348c2ecf20Sopenharmony_ci		msgdma_csroffs(control));
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	counter = 0;
378c2ecf20Sopenharmony_ci	while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
388c2ecf20Sopenharmony_ci		if (tse_bit_is_clear(priv->rx_dma_csr, msgdma_csroffs(status),
398c2ecf20Sopenharmony_ci				     MSGDMA_CSR_STAT_RESETTING))
408c2ecf20Sopenharmony_ci			break;
418c2ecf20Sopenharmony_ci		udelay(1);
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR)
458c2ecf20Sopenharmony_ci		netif_warn(priv, drv, priv->dev,
468c2ecf20Sopenharmony_ci			   "TSE Rx mSGDMA resetting bit never cleared!\n");
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	/* clear all status bits */
498c2ecf20Sopenharmony_ci	csrwr32(MSGDMA_CSR_STAT_MASK, priv->rx_dma_csr, msgdma_csroffs(status));
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	/* Reset Tx mSGDMA */
528c2ecf20Sopenharmony_ci	csrwr32(MSGDMA_CSR_STAT_MASK, priv->tx_dma_csr,
538c2ecf20Sopenharmony_ci		msgdma_csroffs(status));
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	csrwr32(MSGDMA_CSR_CTL_RESET, priv->tx_dma_csr,
568c2ecf20Sopenharmony_ci		msgdma_csroffs(control));
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	counter = 0;
598c2ecf20Sopenharmony_ci	while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
608c2ecf20Sopenharmony_ci		if (tse_bit_is_clear(priv->tx_dma_csr, msgdma_csroffs(status),
618c2ecf20Sopenharmony_ci				     MSGDMA_CSR_STAT_RESETTING))
628c2ecf20Sopenharmony_ci			break;
638c2ecf20Sopenharmony_ci		udelay(1);
648c2ecf20Sopenharmony_ci	}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR)
678c2ecf20Sopenharmony_ci		netif_warn(priv, drv, priv->dev,
688c2ecf20Sopenharmony_ci			   "TSE Tx mSGDMA resetting bit never cleared!\n");
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	/* clear all status bits */
718c2ecf20Sopenharmony_ci	csrwr32(MSGDMA_CSR_STAT_MASK, priv->tx_dma_csr, msgdma_csroffs(status));
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_civoid msgdma_disable_rxirq(struct altera_tse_private *priv)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	tse_clear_bit(priv->rx_dma_csr, msgdma_csroffs(control),
778c2ecf20Sopenharmony_ci		      MSGDMA_CSR_CTL_GLOBAL_INTR);
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_civoid msgdma_enable_rxirq(struct altera_tse_private *priv)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	tse_set_bit(priv->rx_dma_csr, msgdma_csroffs(control),
838c2ecf20Sopenharmony_ci		    MSGDMA_CSR_CTL_GLOBAL_INTR);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_civoid msgdma_disable_txirq(struct altera_tse_private *priv)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	tse_clear_bit(priv->tx_dma_csr, msgdma_csroffs(control),
898c2ecf20Sopenharmony_ci		      MSGDMA_CSR_CTL_GLOBAL_INTR);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_civoid msgdma_enable_txirq(struct altera_tse_private *priv)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	tse_set_bit(priv->tx_dma_csr, msgdma_csroffs(control),
958c2ecf20Sopenharmony_ci		    MSGDMA_CSR_CTL_GLOBAL_INTR);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_civoid msgdma_clear_rxirq(struct altera_tse_private *priv)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	csrwr32(MSGDMA_CSR_STAT_IRQ, priv->rx_dma_csr, msgdma_csroffs(status));
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_civoid msgdma_clear_txirq(struct altera_tse_private *priv)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	csrwr32(MSGDMA_CSR_STAT_IRQ, priv->tx_dma_csr, msgdma_csroffs(status));
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci/* return 0 to indicate transmit is pending */
1098c2ecf20Sopenharmony_ciint msgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	csrwr32(lower_32_bits(buffer->dma_addr), priv->tx_dma_desc,
1128c2ecf20Sopenharmony_ci		msgdma_descroffs(read_addr_lo));
1138c2ecf20Sopenharmony_ci	csrwr32(upper_32_bits(buffer->dma_addr), priv->tx_dma_desc,
1148c2ecf20Sopenharmony_ci		msgdma_descroffs(read_addr_hi));
1158c2ecf20Sopenharmony_ci	csrwr32(0, priv->tx_dma_desc, msgdma_descroffs(write_addr_lo));
1168c2ecf20Sopenharmony_ci	csrwr32(0, priv->tx_dma_desc, msgdma_descroffs(write_addr_hi));
1178c2ecf20Sopenharmony_ci	csrwr32(buffer->len, priv->tx_dma_desc, msgdma_descroffs(len));
1188c2ecf20Sopenharmony_ci	csrwr32(0, priv->tx_dma_desc, msgdma_descroffs(burst_seq_num));
1198c2ecf20Sopenharmony_ci	csrwr32(MSGDMA_DESC_TX_STRIDE, priv->tx_dma_desc,
1208c2ecf20Sopenharmony_ci		msgdma_descroffs(stride));
1218c2ecf20Sopenharmony_ci	csrwr32(MSGDMA_DESC_CTL_TX_SINGLE, priv->tx_dma_desc,
1228c2ecf20Sopenharmony_ci		msgdma_descroffs(control));
1238c2ecf20Sopenharmony_ci	return 0;
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ciu32 msgdma_tx_completions(struct altera_tse_private *priv)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	u32 ready = 0;
1298c2ecf20Sopenharmony_ci	u32 inuse;
1308c2ecf20Sopenharmony_ci	u32 status;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	/* Get number of sent descriptors */
1338c2ecf20Sopenharmony_ci	inuse = csrrd32(priv->tx_dma_csr, msgdma_csroffs(rw_fill_level))
1348c2ecf20Sopenharmony_ci			& 0xffff;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	if (inuse) { /* Tx FIFO is not empty */
1378c2ecf20Sopenharmony_ci		ready = max_t(int,
1388c2ecf20Sopenharmony_ci			      priv->tx_prod - priv->tx_cons - inuse - 1, 0);
1398c2ecf20Sopenharmony_ci	} else {
1408c2ecf20Sopenharmony_ci		/* Check for buffered last packet */
1418c2ecf20Sopenharmony_ci		status = csrrd32(priv->tx_dma_csr, msgdma_csroffs(status));
1428c2ecf20Sopenharmony_ci		if (status & MSGDMA_CSR_STAT_BUSY)
1438c2ecf20Sopenharmony_ci			ready = priv->tx_prod - priv->tx_cons - 1;
1448c2ecf20Sopenharmony_ci		else
1458c2ecf20Sopenharmony_ci			ready = priv->tx_prod - priv->tx_cons;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci	return ready;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/* Put buffer to the mSGDMA RX FIFO
1518c2ecf20Sopenharmony_ci */
1528c2ecf20Sopenharmony_civoid msgdma_add_rx_desc(struct altera_tse_private *priv,
1538c2ecf20Sopenharmony_ci			struct tse_buffer *rxbuffer)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	u32 len = priv->rx_dma_buf_sz;
1568c2ecf20Sopenharmony_ci	dma_addr_t dma_addr = rxbuffer->dma_addr;
1578c2ecf20Sopenharmony_ci	u32 control = (MSGDMA_DESC_CTL_END_ON_EOP
1588c2ecf20Sopenharmony_ci			| MSGDMA_DESC_CTL_END_ON_LEN
1598c2ecf20Sopenharmony_ci			| MSGDMA_DESC_CTL_TR_COMP_IRQ
1608c2ecf20Sopenharmony_ci			| MSGDMA_DESC_CTL_EARLY_IRQ
1618c2ecf20Sopenharmony_ci			| MSGDMA_DESC_CTL_TR_ERR_IRQ
1628c2ecf20Sopenharmony_ci			| MSGDMA_DESC_CTL_GO);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	csrwr32(0, priv->rx_dma_desc, msgdma_descroffs(read_addr_lo));
1658c2ecf20Sopenharmony_ci	csrwr32(0, priv->rx_dma_desc, msgdma_descroffs(read_addr_hi));
1668c2ecf20Sopenharmony_ci	csrwr32(lower_32_bits(dma_addr), priv->rx_dma_desc,
1678c2ecf20Sopenharmony_ci		msgdma_descroffs(write_addr_lo));
1688c2ecf20Sopenharmony_ci	csrwr32(upper_32_bits(dma_addr), priv->rx_dma_desc,
1698c2ecf20Sopenharmony_ci		msgdma_descroffs(write_addr_hi));
1708c2ecf20Sopenharmony_ci	csrwr32(len, priv->rx_dma_desc, msgdma_descroffs(len));
1718c2ecf20Sopenharmony_ci	csrwr32(0, priv->rx_dma_desc, msgdma_descroffs(burst_seq_num));
1728c2ecf20Sopenharmony_ci	csrwr32(0x00010001, priv->rx_dma_desc, msgdma_descroffs(stride));
1738c2ecf20Sopenharmony_ci	csrwr32(control, priv->rx_dma_desc, msgdma_descroffs(control));
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci/* status is returned on upper 16 bits,
1778c2ecf20Sopenharmony_ci * length is returned in lower 16 bits
1788c2ecf20Sopenharmony_ci */
1798c2ecf20Sopenharmony_ciu32 msgdma_rx_status(struct altera_tse_private *priv)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	u32 rxstatus = 0;
1828c2ecf20Sopenharmony_ci	u32 pktlength;
1838c2ecf20Sopenharmony_ci	u32 pktstatus;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (csrrd32(priv->rx_dma_csr, msgdma_csroffs(resp_fill_level))
1868c2ecf20Sopenharmony_ci	    & 0xffff) {
1878c2ecf20Sopenharmony_ci		pktlength = csrrd32(priv->rx_dma_resp,
1888c2ecf20Sopenharmony_ci				    msgdma_respoffs(bytes_transferred));
1898c2ecf20Sopenharmony_ci		pktstatus = csrrd32(priv->rx_dma_resp,
1908c2ecf20Sopenharmony_ci				    msgdma_respoffs(status));
1918c2ecf20Sopenharmony_ci		rxstatus = pktstatus;
1928c2ecf20Sopenharmony_ci		rxstatus = rxstatus << 16;
1938c2ecf20Sopenharmony_ci		rxstatus |= (pktlength & 0xffff);
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci	return rxstatus;
1968c2ecf20Sopenharmony_ci}
197