162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Altera TSE SGDMA and MSGDMA Linux driver
362306a36Sopenharmony_ci * Copyright (C) 2014 Altera Corporation. All rights reserved
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/netdevice.h>
762306a36Sopenharmony_ci#include "altera_utils.h"
862306a36Sopenharmony_ci#include "altera_tse.h"
962306a36Sopenharmony_ci#include "altera_msgdmahw.h"
1062306a36Sopenharmony_ci#include "altera_msgdma.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/* No initialization work to do for MSGDMA */
1362306a36Sopenharmony_ciint msgdma_initialize(struct altera_tse_private *priv)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	return 0;
1662306a36Sopenharmony_ci}
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_civoid msgdma_uninitialize(struct altera_tse_private *priv)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci}
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_civoid msgdma_start_rxdma(struct altera_tse_private *priv)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_civoid msgdma_reset(struct altera_tse_private *priv)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	int counter;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	/* Reset Rx mSGDMA */
3162306a36Sopenharmony_ci	csrwr32(MSGDMA_CSR_STAT_MASK, priv->rx_dma_csr,
3262306a36Sopenharmony_ci		msgdma_csroffs(status));
3362306a36Sopenharmony_ci	csrwr32(MSGDMA_CSR_CTL_RESET, priv->rx_dma_csr,
3462306a36Sopenharmony_ci		msgdma_csroffs(control));
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	counter = 0;
3762306a36Sopenharmony_ci	while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
3862306a36Sopenharmony_ci		if (tse_bit_is_clear(priv->rx_dma_csr, msgdma_csroffs(status),
3962306a36Sopenharmony_ci				     MSGDMA_CSR_STAT_RESETTING))
4062306a36Sopenharmony_ci			break;
4162306a36Sopenharmony_ci		udelay(1);
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR)
4562306a36Sopenharmony_ci		netif_warn(priv, drv, priv->dev,
4662306a36Sopenharmony_ci			   "TSE Rx mSGDMA resetting bit never cleared!\n");
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	/* clear all status bits */
4962306a36Sopenharmony_ci	csrwr32(MSGDMA_CSR_STAT_MASK, priv->rx_dma_csr, msgdma_csroffs(status));
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/* Reset Tx mSGDMA */
5262306a36Sopenharmony_ci	csrwr32(MSGDMA_CSR_STAT_MASK, priv->tx_dma_csr,
5362306a36Sopenharmony_ci		msgdma_csroffs(status));
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	csrwr32(MSGDMA_CSR_CTL_RESET, priv->tx_dma_csr,
5662306a36Sopenharmony_ci		msgdma_csroffs(control));
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	counter = 0;
5962306a36Sopenharmony_ci	while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
6062306a36Sopenharmony_ci		if (tse_bit_is_clear(priv->tx_dma_csr, msgdma_csroffs(status),
6162306a36Sopenharmony_ci				     MSGDMA_CSR_STAT_RESETTING))
6262306a36Sopenharmony_ci			break;
6362306a36Sopenharmony_ci		udelay(1);
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR)
6762306a36Sopenharmony_ci		netif_warn(priv, drv, priv->dev,
6862306a36Sopenharmony_ci			   "TSE Tx mSGDMA resetting bit never cleared!\n");
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* clear all status bits */
7162306a36Sopenharmony_ci	csrwr32(MSGDMA_CSR_STAT_MASK, priv->tx_dma_csr, msgdma_csroffs(status));
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_civoid msgdma_disable_rxirq(struct altera_tse_private *priv)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	tse_clear_bit(priv->rx_dma_csr, msgdma_csroffs(control),
7762306a36Sopenharmony_ci		      MSGDMA_CSR_CTL_GLOBAL_INTR);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_civoid msgdma_enable_rxirq(struct altera_tse_private *priv)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	tse_set_bit(priv->rx_dma_csr, msgdma_csroffs(control),
8362306a36Sopenharmony_ci		    MSGDMA_CSR_CTL_GLOBAL_INTR);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_civoid msgdma_disable_txirq(struct altera_tse_private *priv)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	tse_clear_bit(priv->tx_dma_csr, msgdma_csroffs(control),
8962306a36Sopenharmony_ci		      MSGDMA_CSR_CTL_GLOBAL_INTR);
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_civoid msgdma_enable_txirq(struct altera_tse_private *priv)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	tse_set_bit(priv->tx_dma_csr, msgdma_csroffs(control),
9562306a36Sopenharmony_ci		    MSGDMA_CSR_CTL_GLOBAL_INTR);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_civoid msgdma_clear_rxirq(struct altera_tse_private *priv)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	csrwr32(MSGDMA_CSR_STAT_IRQ, priv->rx_dma_csr, msgdma_csroffs(status));
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_civoid msgdma_clear_txirq(struct altera_tse_private *priv)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	csrwr32(MSGDMA_CSR_STAT_IRQ, priv->tx_dma_csr, msgdma_csroffs(status));
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/* return 0 to indicate transmit is pending */
10962306a36Sopenharmony_ciint msgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	csrwr32(lower_32_bits(buffer->dma_addr), priv->tx_dma_desc,
11262306a36Sopenharmony_ci		msgdma_descroffs(read_addr_lo));
11362306a36Sopenharmony_ci	csrwr32(upper_32_bits(buffer->dma_addr), priv->tx_dma_desc,
11462306a36Sopenharmony_ci		msgdma_descroffs(read_addr_hi));
11562306a36Sopenharmony_ci	csrwr32(0, priv->tx_dma_desc, msgdma_descroffs(write_addr_lo));
11662306a36Sopenharmony_ci	csrwr32(0, priv->tx_dma_desc, msgdma_descroffs(write_addr_hi));
11762306a36Sopenharmony_ci	csrwr32(buffer->len, priv->tx_dma_desc, msgdma_descroffs(len));
11862306a36Sopenharmony_ci	csrwr32(0, priv->tx_dma_desc, msgdma_descroffs(burst_seq_num));
11962306a36Sopenharmony_ci	csrwr32(MSGDMA_DESC_TX_STRIDE, priv->tx_dma_desc,
12062306a36Sopenharmony_ci		msgdma_descroffs(stride));
12162306a36Sopenharmony_ci	csrwr32(MSGDMA_DESC_CTL_TX_SINGLE, priv->tx_dma_desc,
12262306a36Sopenharmony_ci		msgdma_descroffs(control));
12362306a36Sopenharmony_ci	return 0;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciu32 msgdma_tx_completions(struct altera_tse_private *priv)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	u32 ready = 0;
12962306a36Sopenharmony_ci	u32 inuse;
13062306a36Sopenharmony_ci	u32 status;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* Get number of sent descriptors */
13362306a36Sopenharmony_ci	inuse = csrrd32(priv->tx_dma_csr, msgdma_csroffs(rw_fill_level))
13462306a36Sopenharmony_ci			& 0xffff;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (inuse) { /* Tx FIFO is not empty */
13762306a36Sopenharmony_ci		ready = max_t(int,
13862306a36Sopenharmony_ci			      priv->tx_prod - priv->tx_cons - inuse - 1, 0);
13962306a36Sopenharmony_ci	} else {
14062306a36Sopenharmony_ci		/* Check for buffered last packet */
14162306a36Sopenharmony_ci		status = csrrd32(priv->tx_dma_csr, msgdma_csroffs(status));
14262306a36Sopenharmony_ci		if (status & MSGDMA_CSR_STAT_BUSY)
14362306a36Sopenharmony_ci			ready = priv->tx_prod - priv->tx_cons - 1;
14462306a36Sopenharmony_ci		else
14562306a36Sopenharmony_ci			ready = priv->tx_prod - priv->tx_cons;
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci	return ready;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/* Put buffer to the mSGDMA RX FIFO
15162306a36Sopenharmony_ci */
15262306a36Sopenharmony_civoid msgdma_add_rx_desc(struct altera_tse_private *priv,
15362306a36Sopenharmony_ci			struct tse_buffer *rxbuffer)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	u32 len = priv->rx_dma_buf_sz;
15662306a36Sopenharmony_ci	dma_addr_t dma_addr = rxbuffer->dma_addr;
15762306a36Sopenharmony_ci	u32 control = (MSGDMA_DESC_CTL_END_ON_EOP
15862306a36Sopenharmony_ci			| MSGDMA_DESC_CTL_END_ON_LEN
15962306a36Sopenharmony_ci			| MSGDMA_DESC_CTL_TR_COMP_IRQ
16062306a36Sopenharmony_ci			| MSGDMA_DESC_CTL_EARLY_IRQ
16162306a36Sopenharmony_ci			| MSGDMA_DESC_CTL_TR_ERR_IRQ
16262306a36Sopenharmony_ci			| MSGDMA_DESC_CTL_GO);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	csrwr32(0, priv->rx_dma_desc, msgdma_descroffs(read_addr_lo));
16562306a36Sopenharmony_ci	csrwr32(0, priv->rx_dma_desc, msgdma_descroffs(read_addr_hi));
16662306a36Sopenharmony_ci	csrwr32(lower_32_bits(dma_addr), priv->rx_dma_desc,
16762306a36Sopenharmony_ci		msgdma_descroffs(write_addr_lo));
16862306a36Sopenharmony_ci	csrwr32(upper_32_bits(dma_addr), priv->rx_dma_desc,
16962306a36Sopenharmony_ci		msgdma_descroffs(write_addr_hi));
17062306a36Sopenharmony_ci	csrwr32(len, priv->rx_dma_desc, msgdma_descroffs(len));
17162306a36Sopenharmony_ci	csrwr32(0, priv->rx_dma_desc, msgdma_descroffs(burst_seq_num));
17262306a36Sopenharmony_ci	csrwr32(0x00010001, priv->rx_dma_desc, msgdma_descroffs(stride));
17362306a36Sopenharmony_ci	csrwr32(control, priv->rx_dma_desc, msgdma_descroffs(control));
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/* status is returned on upper 16 bits,
17762306a36Sopenharmony_ci * length is returned in lower 16 bits
17862306a36Sopenharmony_ci */
17962306a36Sopenharmony_ciu32 msgdma_rx_status(struct altera_tse_private *priv)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	u32 rxstatus = 0;
18262306a36Sopenharmony_ci	u32 pktlength;
18362306a36Sopenharmony_ci	u32 pktstatus;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (csrrd32(priv->rx_dma_csr, msgdma_csroffs(resp_fill_level))
18662306a36Sopenharmony_ci	    & 0xffff) {
18762306a36Sopenharmony_ci		pktlength = csrrd32(priv->rx_dma_resp,
18862306a36Sopenharmony_ci				    msgdma_respoffs(bytes_transferred));
18962306a36Sopenharmony_ci		pktstatus = csrrd32(priv->rx_dma_resp,
19062306a36Sopenharmony_ci				    msgdma_respoffs(status));
19162306a36Sopenharmony_ci		rxstatus = pktstatus;
19262306a36Sopenharmony_ci		rxstatus = rxstatus << 16;
19362306a36Sopenharmony_ci		rxstatus |= (pktlength & 0xffff);
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci	return rxstatus;
19662306a36Sopenharmony_ci}
197