parent
8b10f32ab3
commit
5e060a5d7e
11
configure.ac
11
configure.ac
|
|
@ -730,9 +730,20 @@ if test "x${enablestmmac}" = "x1"; then
|
|||
fi
|
||||
|
||||
AC_MSG_RESULT([$kernelstmmac])
|
||||
|
||||
AC_MSG_CHECKING([for stmmac_est.c])
|
||||
|
||||
if test -r "${srcdir}/devices/stmmac/stmmac_est-${kernelstmmac}-ethercat.c"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
has_stmmac_est=1
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
has_stmmac_est=0
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(KERNEL_STMMAC,[$kernelstmmac])
|
||||
AC_SUBST(HAS_STMMAC_EST,[$has_stmmac_est])
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# CCAT driver
|
||||
|
|
|
|||
|
|
@ -76,6 +76,10 @@ EC_STMMAC_OBJS := \
|
|||
stmmac_xdp-@KERNEL_STMMAC@-ethercat.o \
|
||||
$(ec_stmmac-y)
|
||||
|
||||
ifeq (@HAS_STMMAC_EST@,1)
|
||||
EC_STMMAC_OBJS += stmmac_est-@KERNEL_STMMAC@-ethercat.o
|
||||
endif
|
||||
|
||||
ec_stmmac-$(CONFIG_STMMAC_SELFTESTS) = \
|
||||
stmmac_selftests-@KERNEL_STMMAC@-ethercat.o
|
||||
|
||||
|
|
|
|||
|
|
@ -26,50 +26,38 @@ EXTRA_DIST = \
|
|||
chain_mode-6.1-orig.c \
|
||||
chain_mode-6.4-ethercat.c \
|
||||
chain_mode-6.4-orig.c \
|
||||
chain_mode-6.12-ethercat.c \
|
||||
chain_mode-6.12-orig.c \
|
||||
common-6.1-ethercat.h \
|
||||
common-6.1-orig.h \
|
||||
common-6.4-ethercat.h \
|
||||
common-6.4-orig.h \
|
||||
common-6.12-ethercat.h \
|
||||
common-6.12-orig.h \
|
||||
descs-6.1-ethercat.h \
|
||||
descs-6.1-orig.h \
|
||||
descs-6.4-ethercat.h \
|
||||
descs-6.4-orig.h \
|
||||
descs-6.12-ethercat.h \
|
||||
descs-6.12-orig.h \
|
||||
descs_com-6.1-ethercat.h \
|
||||
descs_com-6.1-orig.h \
|
||||
descs_com-6.4-ethercat.h \
|
||||
descs_com-6.4-orig.h \
|
||||
dwmac1000-6.1-ethercat.h \
|
||||
dwmac1000-6.1-orig.h \
|
||||
dwmac1000-6.4-ethercat.h \
|
||||
dwmac1000-6.4-orig.h \
|
||||
dwmac1000_core-6.1-ethercat.c \
|
||||
dwmac1000_core-6.1-orig.c \
|
||||
dwmac1000_core-6.4-ethercat.c \
|
||||
dwmac1000_core-6.4-orig.c \
|
||||
dwmac1000_dma-6.1-ethercat.c \
|
||||
dwmac1000_dma-6.1-orig.c \
|
||||
dwmac1000_dma-6.4-ethercat.c \
|
||||
dwmac1000_dma-6.4-orig.c \
|
||||
dwmac100-6.1-ethercat.h \
|
||||
dwmac100-6.1-orig.h \
|
||||
dwmac100-6.4-ethercat.h \
|
||||
dwmac100-6.4-orig.h \
|
||||
dwmac100_core-6.1-ethercat.c \
|
||||
dwmac100_core-6.1-orig.c \
|
||||
dwmac100_core-6.4-ethercat.c \
|
||||
dwmac100_core-6.4-orig.c \
|
||||
dwmac100_dma-6.1-ethercat.c \
|
||||
dwmac100_dma-6.1-orig.c \
|
||||
dwmac100_dma-6.4-ethercat.c \
|
||||
dwmac100_dma-6.4-orig.c \
|
||||
descs_com-6.12-ethercat.h \
|
||||
descs_com-6.12-orig.h \
|
||||
dwmac4-6.1-ethercat.h \
|
||||
dwmac4-6.1-orig.h \
|
||||
dwmac4-6.4-ethercat.h \
|
||||
dwmac4-6.4-orig.h \
|
||||
dwmac4-6.12-ethercat.h \
|
||||
dwmac4-6.12-orig.h \
|
||||
dwmac4_core-6.1-ethercat.c \
|
||||
dwmac4_core-6.1-orig.c \
|
||||
dwmac4_core-6.4-ethercat.c \
|
||||
dwmac4_core-6.4-orig.c \
|
||||
dwmac4_core-6.12-ethercat.c \
|
||||
dwmac4_core-6.12-orig.c \
|
||||
dwmac4_descs-6.1-ethercat.c \
|
||||
dwmac4_descs-6.1-ethercat.h \
|
||||
dwmac4_descs-6.1-orig.c \
|
||||
|
|
@ -78,6 +66,10 @@ EXTRA_DIST = \
|
|||
dwmac4_descs-6.4-ethercat.h \
|
||||
dwmac4_descs-6.4-orig.c \
|
||||
dwmac4_descs-6.4-orig.h \
|
||||
dwmac4_descs-6.12-ethercat.c \
|
||||
dwmac4_descs-6.12-ethercat.h \
|
||||
dwmac4_descs-6.12-orig.c \
|
||||
dwmac4_descs-6.12-orig.h \
|
||||
dwmac4_dma-6.1-ethercat.c \
|
||||
dwmac4_dma-6.1-ethercat.h \
|
||||
dwmac4_dma-6.1-orig.c \
|
||||
|
|
@ -86,10 +78,16 @@ EXTRA_DIST = \
|
|||
dwmac4_dma-6.4-ethercat.h \
|
||||
dwmac4_dma-6.4-orig.c \
|
||||
dwmac4_dma-6.4-orig.h \
|
||||
dwmac4_dma-6.12-ethercat.c \
|
||||
dwmac4_dma-6.12-ethercat.h \
|
||||
dwmac4_dma-6.12-orig.c \
|
||||
dwmac4_dma-6.12-orig.h \
|
||||
dwmac4_lib-6.1-ethercat.c \
|
||||
dwmac4_lib-6.1-orig.c \
|
||||
dwmac4_lib-6.4-ethercat.c \
|
||||
dwmac4_lib-6.4-orig.c \
|
||||
dwmac4_lib-6.12-ethercat.c \
|
||||
dwmac4_lib-6.12-orig.c \
|
||||
dwmac5-6.1-ethercat.c \
|
||||
dwmac5-6.1-ethercat.h \
|
||||
dwmac5-6.1-orig.c \
|
||||
|
|
@ -98,10 +96,46 @@ EXTRA_DIST = \
|
|||
dwmac5-6.4-ethercat.h \
|
||||
dwmac5-6.4-orig.c \
|
||||
dwmac5-6.4-orig.h \
|
||||
dwmac_dma-6.1-ethercat.h \
|
||||
dwmac_dma-6.1-orig.h \
|
||||
dwmac_dma-6.4-ethercat.h \
|
||||
dwmac_dma-6.4-orig.h \
|
||||
dwmac5-6.12-ethercat.c \
|
||||
dwmac5-6.12-ethercat.h \
|
||||
dwmac5-6.12-orig.c \
|
||||
dwmac5-6.12-orig.h \
|
||||
dwmac100-6.1-ethercat.h \
|
||||
dwmac100-6.1-orig.h \
|
||||
dwmac100-6.4-ethercat.h \
|
||||
dwmac100-6.4-orig.h \
|
||||
dwmac100-6.12-ethercat.h \
|
||||
dwmac100-6.12-orig.h \
|
||||
dwmac100_core-6.1-ethercat.c \
|
||||
dwmac100_core-6.1-orig.c \
|
||||
dwmac100_core-6.4-ethercat.c \
|
||||
dwmac100_core-6.4-orig.c \
|
||||
dwmac100_core-6.12-ethercat.c \
|
||||
dwmac100_core-6.12-orig.c \
|
||||
dwmac100_dma-6.1-ethercat.c \
|
||||
dwmac100_dma-6.1-orig.c \
|
||||
dwmac100_dma-6.4-ethercat.c \
|
||||
dwmac100_dma-6.4-orig.c \
|
||||
dwmac100_dma-6.12-ethercat.c \
|
||||
dwmac100_dma-6.12-orig.c \
|
||||
dwmac1000-6.1-ethercat.h \
|
||||
dwmac1000-6.1-orig.h \
|
||||
dwmac1000-6.4-ethercat.h \
|
||||
dwmac1000-6.4-orig.h \
|
||||
dwmac1000-6.12-ethercat.h \
|
||||
dwmac1000-6.12-orig.h \
|
||||
dwmac1000_core-6.1-ethercat.c \
|
||||
dwmac1000_core-6.1-orig.c \
|
||||
dwmac1000_core-6.4-ethercat.c \
|
||||
dwmac1000_core-6.4-orig.c \
|
||||
dwmac1000_core-6.12-ethercat.c \
|
||||
dwmac1000_core-6.12-orig.c \
|
||||
dwmac1000_dma-6.1-ethercat.c \
|
||||
dwmac1000_dma-6.1-orig.c \
|
||||
dwmac1000_dma-6.4-ethercat.c \
|
||||
dwmac1000_dma-6.4-orig.c \
|
||||
dwmac1000_dma-6.12-ethercat.c \
|
||||
dwmac1000_dma-6.12-orig.c \
|
||||
dwmac-intel-6.1-ethercat.c \
|
||||
dwmac-intel-6.1-ethercat.h \
|
||||
dwmac-intel-6.1-orig.c \
|
||||
|
|
@ -110,34 +144,58 @@ EXTRA_DIST = \
|
|||
dwmac-intel-6.4-ethercat.h \
|
||||
dwmac-intel-6.4-orig.c \
|
||||
dwmac-intel-6.4-orig.h \
|
||||
dwmac-intel-6.12-ethercat.c \
|
||||
dwmac-intel-6.12-ethercat.h \
|
||||
dwmac-intel-6.12-orig.c \
|
||||
dwmac-intel-6.12-orig.h \
|
||||
dwmac_dma-6.1-ethercat.h \
|
||||
dwmac_dma-6.1-orig.h \
|
||||
dwmac_dma-6.4-ethercat.h \
|
||||
dwmac_dma-6.4-orig.h \
|
||||
dwmac_dma-6.12-ethercat.h \
|
||||
dwmac_dma-6.12-orig.h \
|
||||
dwmac_lib-6.1-ethercat.c \
|
||||
dwmac_lib-6.1-orig.c \
|
||||
dwmac_lib-6.4-ethercat.c \
|
||||
dwmac_lib-6.4-orig.c \
|
||||
dwmac_lib-6.12-ethercat.c \
|
||||
dwmac_lib-6.12-orig.c \
|
||||
dwxgmac2-6.1-ethercat.h \
|
||||
dwxgmac2-6.1-orig.h \
|
||||
dwxgmac2-6.4-ethercat.h \
|
||||
dwxgmac2-6.4-orig.h \
|
||||
dwxgmac2-6.12-ethercat.h \
|
||||
dwxgmac2-6.12-orig.h \
|
||||
dwxgmac2_core-6.1-ethercat.c \
|
||||
dwxgmac2_core-6.1-orig.c \
|
||||
dwxgmac2_core-6.4-ethercat.c \
|
||||
dwxgmac2_core-6.4-orig.c \
|
||||
dwxgmac2_core-6.12-ethercat.c \
|
||||
dwxgmac2_core-6.12-orig.c \
|
||||
dwxgmac2_descs-6.1-ethercat.c \
|
||||
dwxgmac2_descs-6.1-orig.c \
|
||||
dwxgmac2_descs-6.4-ethercat.c \
|
||||
dwxgmac2_descs-6.4-orig.c \
|
||||
dwxgmac2_descs-6.12-ethercat.c \
|
||||
dwxgmac2_descs-6.12-orig.c \
|
||||
dwxgmac2_dma-6.1-ethercat.c \
|
||||
dwxgmac2_dma-6.1-orig.c \
|
||||
dwxgmac2_dma-6.4-ethercat.c \
|
||||
dwxgmac2_dma-6.4-orig.c \
|
||||
dwxgmac2_dma-6.12-ethercat.c \
|
||||
dwxgmac2_dma-6.12-orig.c \
|
||||
dwxlgmac2-6.1-ethercat.h \
|
||||
dwxlgmac2-6.1-orig.h \
|
||||
dwxlgmac2-6.4-ethercat.h \
|
||||
dwxlgmac2-6.4-orig.h \
|
||||
dwxlgmac2-6.12-ethercat.h \
|
||||
dwxlgmac2-6.12-orig.h \
|
||||
enh_desc-6.1-ethercat.c \
|
||||
enh_desc-6.1-orig.c \
|
||||
enh_desc-6.4-ethercat.c \
|
||||
enh_desc-6.4-orig.c \
|
||||
enh_desc-6.12-ethercat.c \
|
||||
enh_desc-6.12-orig.c \
|
||||
hwif-6.1-ethercat.c \
|
||||
hwif-6.1-ethercat.h \
|
||||
hwif-6.1-orig.c \
|
||||
|
|
@ -146,50 +204,80 @@ EXTRA_DIST = \
|
|||
hwif-6.4-ethercat.h \
|
||||
hwif-6.4-orig.c \
|
||||
hwif-6.4-orig.h \
|
||||
hwif-6.12-ethercat.c \
|
||||
hwif-6.12-ethercat.h \
|
||||
hwif-6.12-orig.c \
|
||||
hwif-6.12-orig.h \
|
||||
mmc-6.1-ethercat.h \
|
||||
mmc-6.1-orig.h \
|
||||
mmc-6.4-ethercat.h \
|
||||
mmc-6.4-orig.h \
|
||||
mmc-6.12-ethercat.h \
|
||||
mmc-6.12-orig.h \
|
||||
mmc_core-6.1-ethercat.c \
|
||||
mmc_core-6.1-orig.c \
|
||||
mmc_core-6.4-ethercat.c \
|
||||
mmc_core-6.4-orig.c \
|
||||
mmc_core-6.12-ethercat.c \
|
||||
mmc_core-6.12-orig.c \
|
||||
norm_desc-6.1-ethercat.c \
|
||||
norm_desc-6.1-orig.c \
|
||||
norm_desc-6.4-ethercat.c \
|
||||
norm_desc-6.4-orig.c \
|
||||
norm_desc-6.12-ethercat.c \
|
||||
norm_desc-6.12-orig.c \
|
||||
ring_mode-6.1-ethercat.c \
|
||||
ring_mode-6.1-orig.c \
|
||||
ring_mode-6.4-ethercat.c \
|
||||
ring_mode-6.4-orig.c \
|
||||
ring_mode-6.12-ethercat.c \
|
||||
ring_mode-6.12-orig.c \
|
||||
stmmac-6.1-ethercat.h \
|
||||
stmmac-6.1-orig.h \
|
||||
stmmac-6.4-ethercat.h \
|
||||
stmmac-6.4-orig.h \
|
||||
stmmac-6.12-ethercat.h \
|
||||
stmmac-6.12-orig.h \
|
||||
stmmac_est-6.12-ethercat.c \
|
||||
stmmac_est-6.12-ethercat.h \
|
||||
stmmac_est-6.12-orig.c \
|
||||
stmmac_est-6.12-orig.h \
|
||||
stmmac_ethtool-6.1-ethercat.c \
|
||||
stmmac_ethtool-6.1-orig.c \
|
||||
stmmac_ethtool-6.4-ethercat.c \
|
||||
stmmac_ethtool-6.4-orig.c \
|
||||
stmmac_ethtool-6.12-ethercat.c \
|
||||
stmmac_ethtool-6.12-orig.c \
|
||||
stmmac_hwtstamp-6.1-ethercat.c \
|
||||
stmmac_hwtstamp-6.1-orig.c \
|
||||
stmmac_hwtstamp-6.4-ethercat.c \
|
||||
stmmac_hwtstamp-6.4-orig.c \
|
||||
stmmac_hwtstamp-6.12-ethercat.c \
|
||||
stmmac_hwtstamp-6.12-orig.c \
|
||||
stmmac_main-6.1-ethercat.c \
|
||||
stmmac_main-6.1-orig.c \
|
||||
stmmac_main-6.4-ethercat.c \
|
||||
stmmac_main-6.4-orig.c \
|
||||
stmmac_main-6.12-ethercat.c \
|
||||
stmmac_main-6.12-orig.c \
|
||||
stmmac_mdio-6.1-ethercat.c \
|
||||
stmmac_mdio-6.1-orig.c \
|
||||
stmmac_mdio-6.4-ethercat.c \
|
||||
stmmac_mdio-6.4-orig.c \
|
||||
stmmac_mdio-6.12-ethercat.c \
|
||||
stmmac_mdio-6.12-orig.c \
|
||||
stmmac_pci-6.1-ethercat.c \
|
||||
stmmac_pci-6.1-orig.c \
|
||||
stmmac_pci-6.4-ethercat.c \
|
||||
stmmac_pci-6.4-orig.c \
|
||||
stmmac_pci-6.12-ethercat.c \
|
||||
stmmac_pci-6.12-orig.c \
|
||||
stmmac_pcs-6.1-ethercat.h \
|
||||
stmmac_pcs-6.1-orig.h \
|
||||
stmmac_pcs-6.4-ethercat.h \
|
||||
stmmac_pcs-6.4-orig.h \
|
||||
stmmac_pcs-6.12-ethercat.h \
|
||||
stmmac_pcs-6.12-orig.h \
|
||||
stmmac_ptp-6.1-ethercat.c \
|
||||
stmmac_ptp-6.1-ethercat.h \
|
||||
stmmac_ptp-6.1-orig.c \
|
||||
|
|
@ -198,10 +286,16 @@ EXTRA_DIST = \
|
|||
stmmac_ptp-6.4-ethercat.h \
|
||||
stmmac_ptp-6.4-orig.c \
|
||||
stmmac_ptp-6.4-orig.h \
|
||||
stmmac_ptp-6.12-ethercat.c \
|
||||
stmmac_ptp-6.12-ethercat.h \
|
||||
stmmac_ptp-6.12-orig.c \
|
||||
stmmac_ptp-6.12-orig.h \
|
||||
stmmac_tc-6.1-ethercat.c \
|
||||
stmmac_tc-6.1-orig.c \
|
||||
stmmac_tc-6.4-ethercat.c \
|
||||
stmmac_tc-6.4-orig.c \
|
||||
stmmac_tc-6.12-ethercat.c \
|
||||
stmmac_tc-6.12-orig.c \
|
||||
stmmac_xdp-6.1-ethercat.c \
|
||||
stmmac_xdp-6.1-ethercat.h \
|
||||
stmmac_xdp-6.1-orig.c \
|
||||
|
|
@ -210,6 +304,10 @@ EXTRA_DIST = \
|
|||
stmmac_xdp-6.4-ethercat.h \
|
||||
stmmac_xdp-6.4-orig.c \
|
||||
stmmac_xdp-6.4-orig.h \
|
||||
stmmac_xdp-6.12-ethercat.c \
|
||||
stmmac_xdp-6.12-ethercat.h \
|
||||
stmmac_xdp-6.12-orig.c \
|
||||
stmmac_xdp-6.12-orig.h \
|
||||
update.sh
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -0,0 +1,166 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
Specialised functions for managing Chained mode
|
||||
|
||||
Copyright(C) 2011 STMicroelectronics Ltd
|
||||
|
||||
It defines all the functions used to handle the normal/enhanced
|
||||
descriptors in case of the DMA is configured to work in chained or
|
||||
in ring mode.
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
|
||||
static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
|
||||
int csum)
|
||||
{
|
||||
unsigned int nopaged_len = skb_headlen(skb);
|
||||
struct stmmac_priv *priv = tx_q->priv_data;
|
||||
unsigned int entry = tx_q->cur_tx;
|
||||
unsigned int bmax, des2;
|
||||
unsigned int i = 1, len;
|
||||
struct dma_desc *desc;
|
||||
|
||||
desc = tx_q->dma_tx + entry;
|
||||
|
||||
if (priv->plat->enh_desc)
|
||||
bmax = BUF_SIZE_8KiB;
|
||||
else
|
||||
bmax = BUF_SIZE_2KiB;
|
||||
|
||||
len = nopaged_len - bmax;
|
||||
|
||||
des2 = dma_map_single(priv->device, skb->data,
|
||||
bmax, DMA_TO_DEVICE);
|
||||
desc->des2 = cpu_to_le32(des2);
|
||||
if (dma_mapping_error(priv->device, des2))
|
||||
return -1;
|
||||
tx_q->tx_skbuff_dma[entry].buf = des2;
|
||||
tx_q->tx_skbuff_dma[entry].len = bmax;
|
||||
/* do not close the descriptor and do not set own bit */
|
||||
stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum, STMMAC_CHAIN_MODE,
|
||||
0, false, skb->len);
|
||||
|
||||
while (len != 0) {
|
||||
tx_q->tx_skbuff[entry] = NULL;
|
||||
entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
|
||||
desc = tx_q->dma_tx + entry;
|
||||
|
||||
if (len > bmax) {
|
||||
des2 = dma_map_single(priv->device,
|
||||
(skb->data + bmax * i),
|
||||
bmax, DMA_TO_DEVICE);
|
||||
desc->des2 = cpu_to_le32(des2);
|
||||
if (dma_mapping_error(priv->device, des2))
|
||||
return -1;
|
||||
tx_q->tx_skbuff_dma[entry].buf = des2;
|
||||
tx_q->tx_skbuff_dma[entry].len = bmax;
|
||||
stmmac_prepare_tx_desc(priv, desc, 0, bmax, csum,
|
||||
STMMAC_CHAIN_MODE, 1, false, skb->len);
|
||||
len -= bmax;
|
||||
i++;
|
||||
} else {
|
||||
des2 = dma_map_single(priv->device,
|
||||
(skb->data + bmax * i), len,
|
||||
DMA_TO_DEVICE);
|
||||
desc->des2 = cpu_to_le32(des2);
|
||||
if (dma_mapping_error(priv->device, des2))
|
||||
return -1;
|
||||
tx_q->tx_skbuff_dma[entry].buf = des2;
|
||||
tx_q->tx_skbuff_dma[entry].len = len;
|
||||
/* last descriptor can be set now */
|
||||
stmmac_prepare_tx_desc(priv, desc, 0, len, csum,
|
||||
STMMAC_CHAIN_MODE, 1, true, skb->len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
tx_q->cur_tx = entry;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static unsigned int is_jumbo_frm(int len, int enh_desc)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
if ((enh_desc && (len > BUF_SIZE_8KiB)) ||
|
||||
(!enh_desc && (len > BUF_SIZE_2KiB))) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void init_dma_chain(void *des, dma_addr_t phy_addr,
|
||||
unsigned int size, unsigned int extend_desc)
|
||||
{
|
||||
/*
|
||||
* In chained mode the des3 points to the next element in the ring.
|
||||
* The latest element has to point to the head.
|
||||
*/
|
||||
int i;
|
||||
dma_addr_t dma_phy = phy_addr;
|
||||
|
||||
if (extend_desc) {
|
||||
struct dma_extended_desc *p = (struct dma_extended_desc *)des;
|
||||
for (i = 0; i < (size - 1); i++) {
|
||||
dma_phy += sizeof(struct dma_extended_desc);
|
||||
p->basic.des3 = cpu_to_le32((unsigned int)dma_phy);
|
||||
p++;
|
||||
}
|
||||
p->basic.des3 = cpu_to_le32((unsigned int)phy_addr);
|
||||
|
||||
} else {
|
||||
struct dma_desc *p = (struct dma_desc *)des;
|
||||
for (i = 0; i < (size - 1); i++) {
|
||||
dma_phy += sizeof(struct dma_desc);
|
||||
p->des3 = cpu_to_le32((unsigned int)dma_phy);
|
||||
p++;
|
||||
}
|
||||
p->des3 = cpu_to_le32((unsigned int)phy_addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void refill_desc3(struct stmmac_rx_queue *rx_q, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = rx_q->priv_data;
|
||||
|
||||
if (priv->hwts_rx_en && !priv->extend_desc)
|
||||
/* NOTE: Device will overwrite des3 with timestamp value if
|
||||
* 1588-2002 time stamping is enabled, hence reinitialize it
|
||||
* to keep explicit chaining in the descriptor.
|
||||
*/
|
||||
p->des3 = cpu_to_le32((unsigned int)(rx_q->dma_rx_phy +
|
||||
(((rx_q->dirty_rx) + 1) %
|
||||
priv->dma_conf.dma_rx_size) *
|
||||
sizeof(struct dma_desc)));
|
||||
}
|
||||
|
||||
static void clean_desc3(struct stmmac_tx_queue *tx_q, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = tx_q->priv_data;
|
||||
unsigned int entry = tx_q->dirty_tx;
|
||||
|
||||
if (tx_q->tx_skbuff_dma[entry].last_segment && !priv->extend_desc &&
|
||||
priv->hwts_tx_en)
|
||||
/* NOTE: Device will overwrite des3 with timestamp value if
|
||||
* 1588-2002 time stamping is enabled, hence reinitialize it
|
||||
* to keep explicit chaining in the descriptor.
|
||||
*/
|
||||
p->des3 = cpu_to_le32((unsigned int)((tx_q->dma_tx_phy +
|
||||
((tx_q->dirty_tx + 1) %
|
||||
priv->dma_conf.dma_tx_size))
|
||||
* sizeof(struct dma_desc)));
|
||||
}
|
||||
|
||||
const struct stmmac_mode_ops chain_mode_ops = {
|
||||
.init = init_dma_chain,
|
||||
.is_jumbo_frm = is_jumbo_frm,
|
||||
.jumbo_frm = jumbo_frm,
|
||||
.refill_desc3 = refill_desc3,
|
||||
.clean_desc3 = clean_desc3,
|
||||
};
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
Specialised functions for managing Chained mode
|
||||
|
||||
Copyright(C) 2011 STMicroelectronics Ltd
|
||||
|
||||
It defines all the functions used to handle the normal/enhanced
|
||||
descriptors in case of the DMA is configured to work in chained or
|
||||
in ring mode.
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include "stmmac.h"
|
||||
|
||||
static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
|
||||
int csum)
|
||||
{
|
||||
unsigned int nopaged_len = skb_headlen(skb);
|
||||
struct stmmac_priv *priv = tx_q->priv_data;
|
||||
unsigned int entry = tx_q->cur_tx;
|
||||
unsigned int bmax, des2;
|
||||
unsigned int i = 1, len;
|
||||
struct dma_desc *desc;
|
||||
|
||||
desc = tx_q->dma_tx + entry;
|
||||
|
||||
if (priv->plat->enh_desc)
|
||||
bmax = BUF_SIZE_8KiB;
|
||||
else
|
||||
bmax = BUF_SIZE_2KiB;
|
||||
|
||||
len = nopaged_len - bmax;
|
||||
|
||||
des2 = dma_map_single(priv->device, skb->data,
|
||||
bmax, DMA_TO_DEVICE);
|
||||
desc->des2 = cpu_to_le32(des2);
|
||||
if (dma_mapping_error(priv->device, des2))
|
||||
return -1;
|
||||
tx_q->tx_skbuff_dma[entry].buf = des2;
|
||||
tx_q->tx_skbuff_dma[entry].len = bmax;
|
||||
/* do not close the descriptor and do not set own bit */
|
||||
stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum, STMMAC_CHAIN_MODE,
|
||||
0, false, skb->len);
|
||||
|
||||
while (len != 0) {
|
||||
tx_q->tx_skbuff[entry] = NULL;
|
||||
entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
|
||||
desc = tx_q->dma_tx + entry;
|
||||
|
||||
if (len > bmax) {
|
||||
des2 = dma_map_single(priv->device,
|
||||
(skb->data + bmax * i),
|
||||
bmax, DMA_TO_DEVICE);
|
||||
desc->des2 = cpu_to_le32(des2);
|
||||
if (dma_mapping_error(priv->device, des2))
|
||||
return -1;
|
||||
tx_q->tx_skbuff_dma[entry].buf = des2;
|
||||
tx_q->tx_skbuff_dma[entry].len = bmax;
|
||||
stmmac_prepare_tx_desc(priv, desc, 0, bmax, csum,
|
||||
STMMAC_CHAIN_MODE, 1, false, skb->len);
|
||||
len -= bmax;
|
||||
i++;
|
||||
} else {
|
||||
des2 = dma_map_single(priv->device,
|
||||
(skb->data + bmax * i), len,
|
||||
DMA_TO_DEVICE);
|
||||
desc->des2 = cpu_to_le32(des2);
|
||||
if (dma_mapping_error(priv->device, des2))
|
||||
return -1;
|
||||
tx_q->tx_skbuff_dma[entry].buf = des2;
|
||||
tx_q->tx_skbuff_dma[entry].len = len;
|
||||
/* last descriptor can be set now */
|
||||
stmmac_prepare_tx_desc(priv, desc, 0, len, csum,
|
||||
STMMAC_CHAIN_MODE, 1, true, skb->len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
tx_q->cur_tx = entry;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static unsigned int is_jumbo_frm(int len, int enh_desc)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
if ((enh_desc && (len > BUF_SIZE_8KiB)) ||
|
||||
(!enh_desc && (len > BUF_SIZE_2KiB))) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void init_dma_chain(void *des, dma_addr_t phy_addr,
|
||||
unsigned int size, unsigned int extend_desc)
|
||||
{
|
||||
/*
|
||||
* In chained mode the des3 points to the next element in the ring.
|
||||
* The latest element has to point to the head.
|
||||
*/
|
||||
int i;
|
||||
dma_addr_t dma_phy = phy_addr;
|
||||
|
||||
if (extend_desc) {
|
||||
struct dma_extended_desc *p = (struct dma_extended_desc *)des;
|
||||
for (i = 0; i < (size - 1); i++) {
|
||||
dma_phy += sizeof(struct dma_extended_desc);
|
||||
p->basic.des3 = cpu_to_le32((unsigned int)dma_phy);
|
||||
p++;
|
||||
}
|
||||
p->basic.des3 = cpu_to_le32((unsigned int)phy_addr);
|
||||
|
||||
} else {
|
||||
struct dma_desc *p = (struct dma_desc *)des;
|
||||
for (i = 0; i < (size - 1); i++) {
|
||||
dma_phy += sizeof(struct dma_desc);
|
||||
p->des3 = cpu_to_le32((unsigned int)dma_phy);
|
||||
p++;
|
||||
}
|
||||
p->des3 = cpu_to_le32((unsigned int)phy_addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void refill_desc3(struct stmmac_rx_queue *rx_q, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = rx_q->priv_data;
|
||||
|
||||
if (priv->hwts_rx_en && !priv->extend_desc)
|
||||
/* NOTE: Device will overwrite des3 with timestamp value if
|
||||
* 1588-2002 time stamping is enabled, hence reinitialize it
|
||||
* to keep explicit chaining in the descriptor.
|
||||
*/
|
||||
p->des3 = cpu_to_le32((unsigned int)(rx_q->dma_rx_phy +
|
||||
(((rx_q->dirty_rx) + 1) %
|
||||
priv->dma_conf.dma_rx_size) *
|
||||
sizeof(struct dma_desc)));
|
||||
}
|
||||
|
||||
static void clean_desc3(struct stmmac_tx_queue *tx_q, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = tx_q->priv_data;
|
||||
unsigned int entry = tx_q->dirty_tx;
|
||||
|
||||
if (tx_q->tx_skbuff_dma[entry].last_segment && !priv->extend_desc &&
|
||||
priv->hwts_tx_en)
|
||||
/* NOTE: Device will overwrite des3 with timestamp value if
|
||||
* 1588-2002 time stamping is enabled, hence reinitialize it
|
||||
* to keep explicit chaining in the descriptor.
|
||||
*/
|
||||
p->des3 = cpu_to_le32((unsigned int)((tx_q->dma_tx_phy +
|
||||
((tx_q->dirty_tx + 1) %
|
||||
priv->dma_conf.dma_tx_size))
|
||||
* sizeof(struct dma_desc)));
|
||||
}
|
||||
|
||||
const struct stmmac_mode_ops chain_mode_ops = {
|
||||
.init = init_dma_chain,
|
||||
.is_jumbo_frm = is_jumbo_frm,
|
||||
.jumbo_frm = jumbo_frm,
|
||||
.refill_desc3 = refill_desc3,
|
||||
.clean_desc3 = clean_desc3,
|
||||
};
|
||||
|
|
@ -0,0 +1,643 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
STMMAC Common Header File
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __COMMON_H__
|
||||
#define __COMMON_H__
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/pcs/pcs-xpcs.h>
|
||||
#include <linux/module.h>
|
||||
#if IS_ENABLED(CONFIG_VLAN_8021Q)
|
||||
#define STMMAC_VLAN_TAG_USED
|
||||
#include <linux/if_vlan.h>
|
||||
#endif
|
||||
|
||||
#include "descs-6.12-ethercat.h"
|
||||
#include "hwif-6.12-ethercat.h"
|
||||
#include "mmc-6.12-ethercat.h"
|
||||
|
||||
/* Synopsys Core versions */
|
||||
#define DWMAC_CORE_3_40 0x34
|
||||
#define DWMAC_CORE_3_50 0x35
|
||||
#define DWMAC_CORE_3_70 0x37
|
||||
#define DWMAC_CORE_4_00 0x40
|
||||
#define DWMAC_CORE_4_10 0x41
|
||||
#define DWMAC_CORE_5_00 0x50
|
||||
#define DWMAC_CORE_5_10 0x51
|
||||
#define DWMAC_CORE_5_20 0x52
|
||||
#define DWXGMAC_CORE_2_10 0x21
|
||||
#define DWXGMAC_CORE_2_20 0x22
|
||||
#define DWXLGMAC_CORE_2_00 0x20
|
||||
|
||||
/* Device ID */
|
||||
#define DWXGMAC_ID 0x76
|
||||
#define DWXLGMAC_ID 0x27
|
||||
|
||||
#define STMMAC_CHAN0 0 /* Always supported and default for all chips */
|
||||
|
||||
/* TX and RX Descriptor Length, these need to be power of two.
|
||||
* TX descriptor length less than 64 may cause transmit queue timed out error.
|
||||
* RX descriptor length less than 64 may cause inconsistent Rx chain error.
|
||||
*/
|
||||
#define DMA_MIN_TX_SIZE 64
|
||||
#define DMA_MAX_TX_SIZE 1024
|
||||
#define DMA_DEFAULT_TX_SIZE 512
|
||||
#define DMA_MIN_RX_SIZE 64
|
||||
#define DMA_MAX_RX_SIZE 1024
|
||||
#define DMA_DEFAULT_RX_SIZE 512
|
||||
#define STMMAC_GET_ENTRY(x, size) ((x + 1) & (size - 1))
|
||||
|
||||
#undef FRAME_FILTER_DEBUG
|
||||
/* #define FRAME_FILTER_DEBUG */
|
||||
|
||||
struct stmmac_q_tx_stats {
|
||||
u64_stats_t tx_bytes;
|
||||
u64_stats_t tx_set_ic_bit;
|
||||
u64_stats_t tx_tso_frames;
|
||||
u64_stats_t tx_tso_nfrags;
|
||||
};
|
||||
|
||||
struct stmmac_napi_tx_stats {
|
||||
u64_stats_t tx_packets;
|
||||
u64_stats_t tx_pkt_n;
|
||||
u64_stats_t poll;
|
||||
u64_stats_t tx_clean;
|
||||
u64_stats_t tx_set_ic_bit;
|
||||
};
|
||||
|
||||
struct stmmac_txq_stats {
|
||||
/* Updates protected by tx queue lock. */
|
||||
struct u64_stats_sync q_syncp;
|
||||
struct stmmac_q_tx_stats q;
|
||||
|
||||
/* Updates protected by NAPI poll logic. */
|
||||
struct u64_stats_sync napi_syncp;
|
||||
struct stmmac_napi_tx_stats napi;
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
struct stmmac_napi_rx_stats {
|
||||
u64_stats_t rx_bytes;
|
||||
u64_stats_t rx_packets;
|
||||
u64_stats_t rx_pkt_n;
|
||||
u64_stats_t poll;
|
||||
};
|
||||
|
||||
struct stmmac_rxq_stats {
|
||||
/* Updates protected by NAPI poll logic. */
|
||||
struct u64_stats_sync napi_syncp;
|
||||
struct stmmac_napi_rx_stats napi;
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
/* Updates on each CPU protected by not allowing nested irqs. */
|
||||
struct stmmac_pcpu_stats {
|
||||
struct u64_stats_sync syncp;
|
||||
u64_stats_t rx_normal_irq_n[MTL_MAX_TX_QUEUES];
|
||||
u64_stats_t tx_normal_irq_n[MTL_MAX_RX_QUEUES];
|
||||
};
|
||||
|
||||
/* Extra statistic and debug information exposed by ethtool */
|
||||
struct stmmac_extra_stats {
|
||||
/* Transmit errors */
|
||||
unsigned long tx_underflow ____cacheline_aligned;
|
||||
unsigned long tx_carrier;
|
||||
unsigned long tx_losscarrier;
|
||||
unsigned long vlan_tag;
|
||||
unsigned long tx_deferred;
|
||||
unsigned long tx_vlan;
|
||||
unsigned long tx_jabber;
|
||||
unsigned long tx_frame_flushed;
|
||||
unsigned long tx_payload_error;
|
||||
unsigned long tx_ip_header_error;
|
||||
unsigned long tx_collision;
|
||||
/* Receive errors */
|
||||
unsigned long rx_desc;
|
||||
unsigned long sa_filter_fail;
|
||||
unsigned long overflow_error;
|
||||
unsigned long ipc_csum_error;
|
||||
unsigned long rx_collision;
|
||||
unsigned long rx_crc_errors;
|
||||
unsigned long dribbling_bit;
|
||||
unsigned long rx_length;
|
||||
unsigned long rx_mii;
|
||||
unsigned long rx_multicast;
|
||||
unsigned long rx_gmac_overflow;
|
||||
unsigned long rx_watchdog;
|
||||
unsigned long da_rx_filter_fail;
|
||||
unsigned long sa_rx_filter_fail;
|
||||
unsigned long rx_missed_cntr;
|
||||
unsigned long rx_overflow_cntr;
|
||||
unsigned long rx_vlan;
|
||||
unsigned long rx_split_hdr_pkt_n;
|
||||
/* Tx/Rx IRQ error info */
|
||||
unsigned long tx_undeflow_irq;
|
||||
unsigned long tx_process_stopped_irq;
|
||||
unsigned long tx_jabber_irq;
|
||||
unsigned long rx_overflow_irq;
|
||||
unsigned long rx_buf_unav_irq;
|
||||
unsigned long rx_process_stopped_irq;
|
||||
unsigned long rx_watchdog_irq;
|
||||
unsigned long tx_early_irq;
|
||||
unsigned long fatal_bus_error_irq;
|
||||
/* Tx/Rx IRQ Events */
|
||||
unsigned long rx_early_irq;
|
||||
unsigned long threshold;
|
||||
unsigned long irq_receive_pmt_irq_n;
|
||||
/* MMC info */
|
||||
unsigned long mmc_tx_irq_n;
|
||||
unsigned long mmc_rx_irq_n;
|
||||
unsigned long mmc_rx_csum_offload_irq_n;
|
||||
/* EEE */
|
||||
unsigned long irq_tx_path_in_lpi_mode_n;
|
||||
unsigned long irq_tx_path_exit_lpi_mode_n;
|
||||
unsigned long irq_rx_path_in_lpi_mode_n;
|
||||
unsigned long irq_rx_path_exit_lpi_mode_n;
|
||||
unsigned long phy_eee_wakeup_error_n;
|
||||
/* Extended RDES status */
|
||||
unsigned long ip_hdr_err;
|
||||
unsigned long ip_payload_err;
|
||||
unsigned long ip_csum_bypassed;
|
||||
unsigned long ipv4_pkt_rcvd;
|
||||
unsigned long ipv6_pkt_rcvd;
|
||||
unsigned long no_ptp_rx_msg_type_ext;
|
||||
unsigned long ptp_rx_msg_type_sync;
|
||||
unsigned long ptp_rx_msg_type_follow_up;
|
||||
unsigned long ptp_rx_msg_type_delay_req;
|
||||
unsigned long ptp_rx_msg_type_delay_resp;
|
||||
unsigned long ptp_rx_msg_type_pdelay_req;
|
||||
unsigned long ptp_rx_msg_type_pdelay_resp;
|
||||
unsigned long ptp_rx_msg_type_pdelay_follow_up;
|
||||
unsigned long ptp_rx_msg_type_announce;
|
||||
unsigned long ptp_rx_msg_type_management;
|
||||
unsigned long ptp_rx_msg_pkt_reserved_type;
|
||||
unsigned long ptp_frame_type;
|
||||
unsigned long ptp_ver;
|
||||
unsigned long timestamp_dropped;
|
||||
unsigned long av_pkt_rcvd;
|
||||
unsigned long av_tagged_pkt_rcvd;
|
||||
unsigned long vlan_tag_priority_val;
|
||||
unsigned long l3_filter_match;
|
||||
unsigned long l4_filter_match;
|
||||
unsigned long l3_l4_filter_no_match;
|
||||
/* PCS */
|
||||
unsigned long irq_pcs_ane_n;
|
||||
unsigned long irq_pcs_link_n;
|
||||
unsigned long irq_rgmii_n;
|
||||
unsigned long pcs_link;
|
||||
unsigned long pcs_duplex;
|
||||
unsigned long pcs_speed;
|
||||
/* debug register */
|
||||
unsigned long mtl_tx_status_fifo_full;
|
||||
unsigned long mtl_tx_fifo_not_empty;
|
||||
unsigned long mmtl_fifo_ctrl;
|
||||
unsigned long mtl_tx_fifo_read_ctrl_write;
|
||||
unsigned long mtl_tx_fifo_read_ctrl_wait;
|
||||
unsigned long mtl_tx_fifo_read_ctrl_read;
|
||||
unsigned long mtl_tx_fifo_read_ctrl_idle;
|
||||
unsigned long mac_tx_in_pause;
|
||||
unsigned long mac_tx_frame_ctrl_xfer;
|
||||
unsigned long mac_tx_frame_ctrl_idle;
|
||||
unsigned long mac_tx_frame_ctrl_wait;
|
||||
unsigned long mac_tx_frame_ctrl_pause;
|
||||
unsigned long mac_gmii_tx_proto_engine;
|
||||
unsigned long mtl_rx_fifo_fill_level_full;
|
||||
unsigned long mtl_rx_fifo_fill_above_thresh;
|
||||
unsigned long mtl_rx_fifo_fill_below_thresh;
|
||||
unsigned long mtl_rx_fifo_fill_level_empty;
|
||||
unsigned long mtl_rx_fifo_read_ctrl_flush;
|
||||
unsigned long mtl_rx_fifo_read_ctrl_read_data;
|
||||
unsigned long mtl_rx_fifo_read_ctrl_status;
|
||||
unsigned long mtl_rx_fifo_read_ctrl_idle;
|
||||
unsigned long mtl_rx_fifo_ctrl_active;
|
||||
unsigned long mac_rx_frame_ctrl_fifo;
|
||||
unsigned long mac_gmii_rx_proto_engine;
|
||||
/* EST */
|
||||
unsigned long mtl_est_cgce;
|
||||
unsigned long mtl_est_hlbs;
|
||||
unsigned long mtl_est_hlbf;
|
||||
unsigned long mtl_est_btre;
|
||||
unsigned long mtl_est_btrlm;
|
||||
unsigned long max_sdu_txq_drop[MTL_MAX_TX_QUEUES];
|
||||
unsigned long mtl_est_txq_hlbf[MTL_MAX_TX_QUEUES];
|
||||
/* per queue statistics */
|
||||
struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES];
|
||||
struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES];
|
||||
struct stmmac_pcpu_stats __percpu *pcpu_stats;
|
||||
unsigned long rx_dropped;
|
||||
unsigned long rx_errors;
|
||||
unsigned long tx_dropped;
|
||||
unsigned long tx_errors;
|
||||
};
|
||||
|
||||
/* Safety Feature statistics exposed by ethtool */
|
||||
struct stmmac_safety_stats {
|
||||
unsigned long mac_errors[32];
|
||||
unsigned long mtl_errors[32];
|
||||
unsigned long dma_errors[32];
|
||||
unsigned long dma_dpp_errors[32];
|
||||
};
|
||||
|
||||
/* Number of fields in Safety Stats */
|
||||
#define STMMAC_SAFETY_FEAT_SIZE \
|
||||
(sizeof(struct stmmac_safety_stats) / sizeof(unsigned long))
|
||||
|
||||
/* CSR Frequency Access Defines*/
|
||||
#define CSR_F_35M 35000000
|
||||
#define CSR_F_60M 60000000
|
||||
#define CSR_F_100M 100000000
|
||||
#define CSR_F_150M 150000000
|
||||
#define CSR_F_250M 250000000
|
||||
#define CSR_F_300M 300000000
|
||||
|
||||
#define MAC_CSR_H_FRQ_MASK 0x20
|
||||
|
||||
#define HASH_TABLE_SIZE 64
|
||||
#define PAUSE_TIME 0xffff
|
||||
|
||||
/* Flow Control defines */
|
||||
#define FLOW_OFF 0
|
||||
#define FLOW_RX 1
|
||||
#define FLOW_TX 2
|
||||
#define FLOW_AUTO (FLOW_TX | FLOW_RX)
|
||||
|
||||
/* PCS defines */
|
||||
#define STMMAC_PCS_RGMII (1 << 0)
|
||||
#define STMMAC_PCS_SGMII (1 << 1)
|
||||
|
||||
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
|
||||
|
||||
/* DMA HW feature register fields */
|
||||
#define DMA_HW_FEAT_MIISEL 0x00000001 /* 10/100 Mbps Support */
|
||||
#define DMA_HW_FEAT_GMIISEL 0x00000002 /* 1000 Mbps Support */
|
||||
#define DMA_HW_FEAT_HDSEL 0x00000004 /* Half-Duplex Support */
|
||||
#define DMA_HW_FEAT_EXTHASHEN 0x00000008 /* Expanded DA Hash Filter */
|
||||
#define DMA_HW_FEAT_HASHSEL 0x00000010 /* HASH Filter */
|
||||
#define DMA_HW_FEAT_ADDMAC 0x00000020 /* Multiple MAC Addr Reg */
|
||||
#define DMA_HW_FEAT_PCSSEL 0x00000040 /* PCS registers */
|
||||
#define DMA_HW_FEAT_L3L4FLTREN 0x00000080 /* Layer 3 & Layer 4 Feature */
|
||||
#define DMA_HW_FEAT_SMASEL 0x00000100 /* SMA(MDIO) Interface */
|
||||
#define DMA_HW_FEAT_RWKSEL 0x00000200 /* PMT Remote Wakeup */
|
||||
#define DMA_HW_FEAT_MGKSEL 0x00000400 /* PMT Magic Packet */
|
||||
#define DMA_HW_FEAT_MMCSEL 0x00000800 /* RMON Module */
|
||||
#define DMA_HW_FEAT_TSVER1SEL 0x00001000 /* Only IEEE 1588-2002 */
|
||||
#define DMA_HW_FEAT_TSVER2SEL 0x00002000 /* IEEE 1588-2008 PTPv2 */
|
||||
#define DMA_HW_FEAT_EEESEL 0x00004000 /* Energy Efficient Ethernet */
|
||||
#define DMA_HW_FEAT_AVSEL 0x00008000 /* AV Feature */
|
||||
#define DMA_HW_FEAT_TXCOESEL 0x00010000 /* Checksum Offload in Tx */
|
||||
#define DMA_HW_FEAT_RXTYP1COE 0x00020000 /* IP COE (Type 1) in Rx */
|
||||
#define DMA_HW_FEAT_RXTYP2COE 0x00040000 /* IP COE (Type 2) in Rx */
|
||||
#define DMA_HW_FEAT_RXFIFOSIZE 0x00080000 /* Rx FIFO > 2048 Bytes */
|
||||
#define DMA_HW_FEAT_RXCHCNT 0x00300000 /* No. additional Rx Channels */
|
||||
#define DMA_HW_FEAT_TXCHCNT 0x00c00000 /* No. additional Tx Channels */
|
||||
#define DMA_HW_FEAT_ENHDESSEL 0x01000000 /* Alternate Descriptor */
|
||||
/* Timestamping with Internal System Time */
|
||||
#define DMA_HW_FEAT_INTTSEN 0x02000000
|
||||
#define DMA_HW_FEAT_FLEXIPPSEN 0x04000000 /* Flexible PPS Output */
|
||||
#define DMA_HW_FEAT_SAVLANINS 0x08000000 /* Source Addr or VLAN */
|
||||
#define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY iface */
|
||||
#define DEFAULT_DMA_PBL 8
|
||||
|
||||
/* MSI defines */
|
||||
#define STMMAC_MSI_VEC_MAX 32
|
||||
|
||||
/* PCS status and mask defines */
|
||||
#define PCS_ANE_IRQ BIT(2) /* PCS Auto-Negotiation */
|
||||
#define PCS_LINK_IRQ BIT(1) /* PCS Link */
|
||||
#define PCS_RGSMIIIS_IRQ BIT(0) /* RGMII or SMII Interrupt */
|
||||
|
||||
/* Max/Min RI Watchdog Timer count value */
|
||||
#define MAX_DMA_RIWT 0xff
|
||||
#define MIN_DMA_RIWT 0x10
|
||||
#define DEF_DMA_RIWT 0xa0
|
||||
/* Tx coalesce parameters */
|
||||
#define STMMAC_COAL_TX_TIMER 5000
|
||||
#define STMMAC_MAX_COAL_TX_TICK 100000
|
||||
#define STMMAC_TX_MAX_FRAMES 256
|
||||
#define STMMAC_TX_FRAMES 25
|
||||
#define STMMAC_RX_FRAMES 0
|
||||
|
||||
/* Packets types */
|
||||
enum packets_types {
|
||||
PACKET_AVCPQ = 0x1, /* AV Untagged Control packets */
|
||||
PACKET_PTPQ = 0x2, /* PTP Packets */
|
||||
PACKET_DCBCPQ = 0x3, /* DCB Control Packets */
|
||||
PACKET_UPQ = 0x4, /* Untagged Packets */
|
||||
PACKET_MCBCQ = 0x5, /* Multicast & Broadcast Packets */
|
||||
};
|
||||
|
||||
/* Rx IPC status */
|
||||
enum rx_frame_status {
|
||||
good_frame = 0x0,
|
||||
discard_frame = 0x1,
|
||||
csum_none = 0x2,
|
||||
llc_snap = 0x4,
|
||||
dma_own = 0x8,
|
||||
rx_not_ls = 0x10,
|
||||
};
|
||||
|
||||
/* Tx status */
|
||||
enum tx_frame_status {
|
||||
tx_done = 0x0,
|
||||
tx_not_ls = 0x1,
|
||||
tx_err = 0x2,
|
||||
tx_dma_own = 0x4,
|
||||
tx_err_bump_tc = 0x8,
|
||||
};
|
||||
|
||||
enum dma_irq_status {
|
||||
tx_hard_error = 0x1,
|
||||
tx_hard_error_bump_tc = 0x2,
|
||||
handle_rx = 0x4,
|
||||
handle_tx = 0x8,
|
||||
};
|
||||
|
||||
enum dma_irq_dir {
|
||||
DMA_DIR_RX = 0x1,
|
||||
DMA_DIR_TX = 0x2,
|
||||
DMA_DIR_RXTX = 0x3,
|
||||
};
|
||||
|
||||
enum request_irq_err {
|
||||
REQ_IRQ_ERR_ALL,
|
||||
REQ_IRQ_ERR_TX,
|
||||
REQ_IRQ_ERR_RX,
|
||||
REQ_IRQ_ERR_SFTY,
|
||||
REQ_IRQ_ERR_SFTY_UE,
|
||||
REQ_IRQ_ERR_SFTY_CE,
|
||||
REQ_IRQ_ERR_LPI,
|
||||
REQ_IRQ_ERR_WOL,
|
||||
REQ_IRQ_ERR_MAC,
|
||||
REQ_IRQ_ERR_NO,
|
||||
};
|
||||
|
||||
/* EEE and LPI defines */
|
||||
#define CORE_IRQ_TX_PATH_IN_LPI_MODE (1 << 0)
|
||||
#define CORE_IRQ_TX_PATH_EXIT_LPI_MODE (1 << 1)
|
||||
#define CORE_IRQ_RX_PATH_IN_LPI_MODE (1 << 2)
|
||||
#define CORE_IRQ_RX_PATH_EXIT_LPI_MODE (1 << 3)
|
||||
|
||||
/* FPE defines */
|
||||
#define FPE_EVENT_UNKNOWN 0
|
||||
#define FPE_EVENT_TRSP BIT(0)
|
||||
#define FPE_EVENT_TVER BIT(1)
|
||||
#define FPE_EVENT_RRSP BIT(2)
|
||||
#define FPE_EVENT_RVER BIT(3)
|
||||
|
||||
#define CORE_IRQ_MTL_RX_OVERFLOW BIT(8)
|
||||
|
||||
/* Physical Coding Sublayer */
|
||||
struct rgmii_adv {
|
||||
unsigned int pause;
|
||||
unsigned int duplex;
|
||||
unsigned int lp_pause;
|
||||
unsigned int lp_duplex;
|
||||
};
|
||||
|
||||
#define STMMAC_PCS_PAUSE 1
|
||||
#define STMMAC_PCS_ASYM_PAUSE 2
|
||||
|
||||
/* DMA HW capabilities */
|
||||
struct dma_features {
|
||||
unsigned int mbps_10_100;
|
||||
unsigned int mbps_1000;
|
||||
unsigned int half_duplex;
|
||||
unsigned int hash_filter;
|
||||
unsigned int multi_addr;
|
||||
unsigned int pcs;
|
||||
unsigned int sma_mdio;
|
||||
unsigned int pmt_remote_wake_up;
|
||||
unsigned int pmt_magic_frame;
|
||||
unsigned int rmon;
|
||||
/* IEEE 1588-2002 */
|
||||
unsigned int time_stamp;
|
||||
/* IEEE 1588-2008 */
|
||||
unsigned int atime_stamp;
|
||||
/* 802.3az - Energy-Efficient Ethernet (EEE) */
|
||||
unsigned int eee;
|
||||
unsigned int av;
|
||||
unsigned int hash_tb_sz;
|
||||
unsigned int tsoen;
|
||||
/* TX and RX csum */
|
||||
unsigned int tx_coe;
|
||||
unsigned int rx_coe;
|
||||
unsigned int rx_coe_type1;
|
||||
unsigned int rx_coe_type2;
|
||||
unsigned int rxfifo_over_2048;
|
||||
/* TX and RX number of channels */
|
||||
unsigned int number_rx_channel;
|
||||
unsigned int number_tx_channel;
|
||||
/* TX and RX number of queues */
|
||||
unsigned int number_rx_queues;
|
||||
unsigned int number_tx_queues;
|
||||
/* PPS output */
|
||||
unsigned int pps_out_num;
|
||||
/* Number of Traffic Classes */
|
||||
unsigned int numtc;
|
||||
/* DCB Feature Enable */
|
||||
unsigned int dcben;
|
||||
/* IEEE 1588 High Word Register Enable */
|
||||
unsigned int advthword;
|
||||
/* PTP Offload Enable */
|
||||
unsigned int ptoen;
|
||||
/* One-Step Timestamping Enable */
|
||||
unsigned int osten;
|
||||
/* Priority-Based Flow Control Enable */
|
||||
unsigned int pfcen;
|
||||
/* Alternate (enhanced) DESC mode */
|
||||
unsigned int enh_desc;
|
||||
/* TX and RX FIFO sizes */
|
||||
unsigned int tx_fifo_size;
|
||||
unsigned int rx_fifo_size;
|
||||
/* Automotive Safety Package */
|
||||
unsigned int asp;
|
||||
/* RX Parser */
|
||||
unsigned int frpsel;
|
||||
unsigned int frpbs;
|
||||
unsigned int frpes;
|
||||
unsigned int addr64;
|
||||
unsigned int host_dma_width;
|
||||
unsigned int rssen;
|
||||
unsigned int vlhash;
|
||||
unsigned int sphen;
|
||||
unsigned int vlins;
|
||||
unsigned int dvlan;
|
||||
unsigned int l3l4fnum;
|
||||
unsigned int arpoffsel;
|
||||
/* One Step for PTP over UDP/IP Feature Enable */
|
||||
unsigned int pou_ost_en;
|
||||
/* Tx Timestamp FIFO Depth */
|
||||
unsigned int ttsfd;
|
||||
/* Queue/Channel-Based VLAN tag insertion on Tx */
|
||||
unsigned int cbtisel;
|
||||
/* Supported Parallel Instruction Processor Engines */
|
||||
unsigned int frppipe_num;
|
||||
/* Number of Extended VLAN Tag Filters */
|
||||
unsigned int nrvf_num;
|
||||
/* TSN Features */
|
||||
unsigned int estwid;
|
||||
unsigned int estdep;
|
||||
unsigned int estsel;
|
||||
unsigned int fpesel;
|
||||
unsigned int tbssel;
|
||||
/* Number of DMA channels enabled for TBS */
|
||||
unsigned int tbs_ch_num;
|
||||
/* Per-Stream Filtering Enable */
|
||||
unsigned int sgfsel;
|
||||
/* Numbers of Auxiliary Snapshot Inputs */
|
||||
unsigned int aux_snapshot_n;
|
||||
/* Timestamp System Time Source */
|
||||
unsigned int tssrc;
|
||||
/* Enhanced DMA Enable */
|
||||
unsigned int edma;
|
||||
/* Different Descriptor Cache Enable */
|
||||
unsigned int ediffc;
|
||||
/* VxLAN/NVGRE Enable */
|
||||
unsigned int vxn;
|
||||
/* Debug Memory Interface Enable */
|
||||
unsigned int dbgmem;
|
||||
/* Number of Policing Counters */
|
||||
unsigned int pcsel;
|
||||
};
|
||||
|
||||
/* RX Buffer size must be multiple of 4/8/16 bytes */
|
||||
#define BUF_SIZE_16KiB 16368
|
||||
#define BUF_SIZE_8KiB 8188
|
||||
#define BUF_SIZE_4KiB 4096
|
||||
#define BUF_SIZE_2KiB 2048
|
||||
|
||||
/* Power Down and WOL */
|
||||
#define PMT_NOT_SUPPORTED 0
|
||||
#define PMT_SUPPORTED 1
|
||||
|
||||
/* Common MAC defines */
|
||||
#define MAC_CTRL_REG 0x00000000 /* MAC Control */
|
||||
#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */
|
||||
#define MAC_ENABLE_RX 0x00000004 /* Receiver Enable */
|
||||
|
||||
/* Default LPI timers */
|
||||
#define STMMAC_DEFAULT_LIT_LS 0x3E8
|
||||
#define STMMAC_DEFAULT_TWT_LS 0x1E
|
||||
#define STMMAC_ET_MAX 0xFFFFF
|
||||
|
||||
#define STMMAC_CHAIN_MODE 0x1
|
||||
#define STMMAC_RING_MODE 0x2
|
||||
|
||||
#define JUMBO_LEN 9000
|
||||
|
||||
/* Receive Side Scaling */
|
||||
#define STMMAC_RSS_HASH_KEY_SIZE 40
|
||||
#define STMMAC_RSS_MAX_TABLE_SIZE 256
|
||||
|
||||
/* VLAN */
|
||||
#define STMMAC_VLAN_NONE 0x0
|
||||
#define STMMAC_VLAN_REMOVE 0x1
|
||||
#define STMMAC_VLAN_INSERT 0x2
|
||||
#define STMMAC_VLAN_REPLACE 0x3
|
||||
|
||||
extern const struct stmmac_desc_ops enh_desc_ops;
|
||||
extern const struct stmmac_desc_ops ndesc_ops;
|
||||
|
||||
struct mac_device_info;
|
||||
|
||||
extern const struct stmmac_hwtimestamp stmmac_ptp;
|
||||
extern const struct stmmac_mode_ops dwmac4_ring_mode_ops;
|
||||
|
||||
struct mac_link {
|
||||
u32 caps;
|
||||
u32 speed_mask;
|
||||
u32 speed10;
|
||||
u32 speed100;
|
||||
u32 speed1000;
|
||||
u32 speed2500;
|
||||
u32 duplex;
|
||||
struct {
|
||||
u32 speed2500;
|
||||
u32 speed5000;
|
||||
u32 speed10000;
|
||||
} xgmii;
|
||||
struct {
|
||||
u32 speed25000;
|
||||
u32 speed40000;
|
||||
u32 speed50000;
|
||||
u32 speed100000;
|
||||
} xlgmii;
|
||||
};
|
||||
|
||||
struct mii_regs {
|
||||
unsigned int addr; /* MII Address */
|
||||
unsigned int data; /* MII Data */
|
||||
unsigned int addr_shift; /* MII address shift */
|
||||
unsigned int reg_shift; /* MII reg shift */
|
||||
unsigned int addr_mask; /* MII address mask */
|
||||
unsigned int reg_mask; /* MII reg mask */
|
||||
unsigned int clk_csr_shift;
|
||||
unsigned int clk_csr_mask;
|
||||
};
|
||||
|
||||
struct mac_device_info {
|
||||
const struct stmmac_ops *mac;
|
||||
const struct stmmac_desc_ops *desc;
|
||||
const struct stmmac_dma_ops *dma;
|
||||
const struct stmmac_mode_ops *mode;
|
||||
const struct stmmac_hwtimestamp *ptp;
|
||||
const struct stmmac_tc_ops *tc;
|
||||
const struct stmmac_mmc_ops *mmc;
|
||||
const struct stmmac_est_ops *est;
|
||||
struct dw_xpcs *xpcs;
|
||||
struct phylink_pcs *phylink_pcs;
|
||||
struct mii_regs mii; /* MII register Addresses */
|
||||
struct mac_link link;
|
||||
void __iomem *pcsr; /* vpointer to device CSRs */
|
||||
unsigned int multicast_filter_bins;
|
||||
unsigned int unicast_filter_entries;
|
||||
unsigned int mcast_bits_log2;
|
||||
unsigned int rx_csum;
|
||||
unsigned int pcs;
|
||||
unsigned int pmt;
|
||||
unsigned int ps;
|
||||
unsigned int xlgmac;
|
||||
unsigned int num_vlan;
|
||||
u32 vlan_filter[32];
|
||||
bool vlan_fail_q_en;
|
||||
u8 vlan_fail_q;
|
||||
bool hw_vlan_en;
|
||||
};
|
||||
|
||||
struct stmmac_rx_routing {
|
||||
u32 reg_mask;
|
||||
u32 reg_shift;
|
||||
};
|
||||
|
||||
int dwmac100_setup(struct stmmac_priv *priv);
|
||||
int dwmac1000_setup(struct stmmac_priv *priv);
|
||||
int dwmac4_setup(struct stmmac_priv *priv);
|
||||
int dwxgmac2_setup(struct stmmac_priv *priv);
|
||||
int dwxlgmac2_setup(struct stmmac_priv *priv);
|
||||
|
||||
void stmmac_set_mac_addr(void __iomem *ioaddr, const u8 addr[6],
|
||||
unsigned int high, unsigned int low);
|
||||
void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int high, unsigned int low);
|
||||
void stmmac_set_mac(void __iomem *ioaddr, bool enable);
|
||||
|
||||
void stmmac_dwmac4_set_mac_addr(void __iomem *ioaddr, const u8 addr[6],
|
||||
unsigned int high, unsigned int low);
|
||||
void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int high, unsigned int low);
|
||||
void stmmac_dwmac4_set_mac(void __iomem *ioaddr, bool enable);
|
||||
|
||||
void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
|
||||
|
||||
extern const struct stmmac_mode_ops ring_mode_ops;
|
||||
extern const struct stmmac_mode_ops chain_mode_ops;
|
||||
extern const struct stmmac_desc_ops dwmac4_desc_ops;
|
||||
|
||||
#endif /* __COMMON_H__ */
|
||||
|
|
@ -0,0 +1,644 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
STMMAC Common Header File
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __COMMON_H__
|
||||
#define __COMMON_H__
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/stmmac.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/pcs/pcs-xpcs.h>
|
||||
#include <linux/module.h>
|
||||
#if IS_ENABLED(CONFIG_VLAN_8021Q)
|
||||
#define STMMAC_VLAN_TAG_USED
|
||||
#include <linux/if_vlan.h>
|
||||
#endif
|
||||
|
||||
#include "descs.h"
|
||||
#include "hwif.h"
|
||||
#include "mmc.h"
|
||||
|
||||
/* Synopsys Core versions */
|
||||
#define DWMAC_CORE_3_40 0x34
|
||||
#define DWMAC_CORE_3_50 0x35
|
||||
#define DWMAC_CORE_3_70 0x37
|
||||
#define DWMAC_CORE_4_00 0x40
|
||||
#define DWMAC_CORE_4_10 0x41
|
||||
#define DWMAC_CORE_5_00 0x50
|
||||
#define DWMAC_CORE_5_10 0x51
|
||||
#define DWMAC_CORE_5_20 0x52
|
||||
#define DWXGMAC_CORE_2_10 0x21
|
||||
#define DWXGMAC_CORE_2_20 0x22
|
||||
#define DWXLGMAC_CORE_2_00 0x20
|
||||
|
||||
/* Device ID */
|
||||
#define DWXGMAC_ID 0x76
|
||||
#define DWXLGMAC_ID 0x27
|
||||
|
||||
#define STMMAC_CHAN0 0 /* Always supported and default for all chips */
|
||||
|
||||
/* TX and RX Descriptor Length, these need to be power of two.
|
||||
* TX descriptor length less than 64 may cause transmit queue timed out error.
|
||||
* RX descriptor length less than 64 may cause inconsistent Rx chain error.
|
||||
*/
|
||||
#define DMA_MIN_TX_SIZE 64
|
||||
#define DMA_MAX_TX_SIZE 1024
|
||||
#define DMA_DEFAULT_TX_SIZE 512
|
||||
#define DMA_MIN_RX_SIZE 64
|
||||
#define DMA_MAX_RX_SIZE 1024
|
||||
#define DMA_DEFAULT_RX_SIZE 512
|
||||
#define STMMAC_GET_ENTRY(x, size) ((x + 1) & (size - 1))
|
||||
|
||||
#undef FRAME_FILTER_DEBUG
|
||||
/* #define FRAME_FILTER_DEBUG */
|
||||
|
||||
struct stmmac_q_tx_stats {
|
||||
u64_stats_t tx_bytes;
|
||||
u64_stats_t tx_set_ic_bit;
|
||||
u64_stats_t tx_tso_frames;
|
||||
u64_stats_t tx_tso_nfrags;
|
||||
};
|
||||
|
||||
struct stmmac_napi_tx_stats {
|
||||
u64_stats_t tx_packets;
|
||||
u64_stats_t tx_pkt_n;
|
||||
u64_stats_t poll;
|
||||
u64_stats_t tx_clean;
|
||||
u64_stats_t tx_set_ic_bit;
|
||||
};
|
||||
|
||||
struct stmmac_txq_stats {
|
||||
/* Updates protected by tx queue lock. */
|
||||
struct u64_stats_sync q_syncp;
|
||||
struct stmmac_q_tx_stats q;
|
||||
|
||||
/* Updates protected by NAPI poll logic. */
|
||||
struct u64_stats_sync napi_syncp;
|
||||
struct stmmac_napi_tx_stats napi;
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
struct stmmac_napi_rx_stats {
|
||||
u64_stats_t rx_bytes;
|
||||
u64_stats_t rx_packets;
|
||||
u64_stats_t rx_pkt_n;
|
||||
u64_stats_t poll;
|
||||
};
|
||||
|
||||
struct stmmac_rxq_stats {
|
||||
/* Updates protected by NAPI poll logic. */
|
||||
struct u64_stats_sync napi_syncp;
|
||||
struct stmmac_napi_rx_stats napi;
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
/* Updates on each CPU protected by not allowing nested irqs. */
|
||||
struct stmmac_pcpu_stats {
|
||||
struct u64_stats_sync syncp;
|
||||
u64_stats_t rx_normal_irq_n[MTL_MAX_TX_QUEUES];
|
||||
u64_stats_t tx_normal_irq_n[MTL_MAX_RX_QUEUES];
|
||||
};
|
||||
|
||||
/* Extra statistic and debug information exposed by ethtool */
|
||||
struct stmmac_extra_stats {
|
||||
/* Transmit errors */
|
||||
unsigned long tx_underflow ____cacheline_aligned;
|
||||
unsigned long tx_carrier;
|
||||
unsigned long tx_losscarrier;
|
||||
unsigned long vlan_tag;
|
||||
unsigned long tx_deferred;
|
||||
unsigned long tx_vlan;
|
||||
unsigned long tx_jabber;
|
||||
unsigned long tx_frame_flushed;
|
||||
unsigned long tx_payload_error;
|
||||
unsigned long tx_ip_header_error;
|
||||
unsigned long tx_collision;
|
||||
/* Receive errors */
|
||||
unsigned long rx_desc;
|
||||
unsigned long sa_filter_fail;
|
||||
unsigned long overflow_error;
|
||||
unsigned long ipc_csum_error;
|
||||
unsigned long rx_collision;
|
||||
unsigned long rx_crc_errors;
|
||||
unsigned long dribbling_bit;
|
||||
unsigned long rx_length;
|
||||
unsigned long rx_mii;
|
||||
unsigned long rx_multicast;
|
||||
unsigned long rx_gmac_overflow;
|
||||
unsigned long rx_watchdog;
|
||||
unsigned long da_rx_filter_fail;
|
||||
unsigned long sa_rx_filter_fail;
|
||||
unsigned long rx_missed_cntr;
|
||||
unsigned long rx_overflow_cntr;
|
||||
unsigned long rx_vlan;
|
||||
unsigned long rx_split_hdr_pkt_n;
|
||||
/* Tx/Rx IRQ error info */
|
||||
unsigned long tx_undeflow_irq;
|
||||
unsigned long tx_process_stopped_irq;
|
||||
unsigned long tx_jabber_irq;
|
||||
unsigned long rx_overflow_irq;
|
||||
unsigned long rx_buf_unav_irq;
|
||||
unsigned long rx_process_stopped_irq;
|
||||
unsigned long rx_watchdog_irq;
|
||||
unsigned long tx_early_irq;
|
||||
unsigned long fatal_bus_error_irq;
|
||||
/* Tx/Rx IRQ Events */
|
||||
unsigned long rx_early_irq;
|
||||
unsigned long threshold;
|
||||
unsigned long irq_receive_pmt_irq_n;
|
||||
/* MMC info */
|
||||
unsigned long mmc_tx_irq_n;
|
||||
unsigned long mmc_rx_irq_n;
|
||||
unsigned long mmc_rx_csum_offload_irq_n;
|
||||
/* EEE */
|
||||
unsigned long irq_tx_path_in_lpi_mode_n;
|
||||
unsigned long irq_tx_path_exit_lpi_mode_n;
|
||||
unsigned long irq_rx_path_in_lpi_mode_n;
|
||||
unsigned long irq_rx_path_exit_lpi_mode_n;
|
||||
unsigned long phy_eee_wakeup_error_n;
|
||||
/* Extended RDES status */
|
||||
unsigned long ip_hdr_err;
|
||||
unsigned long ip_payload_err;
|
||||
unsigned long ip_csum_bypassed;
|
||||
unsigned long ipv4_pkt_rcvd;
|
||||
unsigned long ipv6_pkt_rcvd;
|
||||
unsigned long no_ptp_rx_msg_type_ext;
|
||||
unsigned long ptp_rx_msg_type_sync;
|
||||
unsigned long ptp_rx_msg_type_follow_up;
|
||||
unsigned long ptp_rx_msg_type_delay_req;
|
||||
unsigned long ptp_rx_msg_type_delay_resp;
|
||||
unsigned long ptp_rx_msg_type_pdelay_req;
|
||||
unsigned long ptp_rx_msg_type_pdelay_resp;
|
||||
unsigned long ptp_rx_msg_type_pdelay_follow_up;
|
||||
unsigned long ptp_rx_msg_type_announce;
|
||||
unsigned long ptp_rx_msg_type_management;
|
||||
unsigned long ptp_rx_msg_pkt_reserved_type;
|
||||
unsigned long ptp_frame_type;
|
||||
unsigned long ptp_ver;
|
||||
unsigned long timestamp_dropped;
|
||||
unsigned long av_pkt_rcvd;
|
||||
unsigned long av_tagged_pkt_rcvd;
|
||||
unsigned long vlan_tag_priority_val;
|
||||
unsigned long l3_filter_match;
|
||||
unsigned long l4_filter_match;
|
||||
unsigned long l3_l4_filter_no_match;
|
||||
/* PCS */
|
||||
unsigned long irq_pcs_ane_n;
|
||||
unsigned long irq_pcs_link_n;
|
||||
unsigned long irq_rgmii_n;
|
||||
unsigned long pcs_link;
|
||||
unsigned long pcs_duplex;
|
||||
unsigned long pcs_speed;
|
||||
/* debug register */
|
||||
unsigned long mtl_tx_status_fifo_full;
|
||||
unsigned long mtl_tx_fifo_not_empty;
|
||||
unsigned long mmtl_fifo_ctrl;
|
||||
unsigned long mtl_tx_fifo_read_ctrl_write;
|
||||
unsigned long mtl_tx_fifo_read_ctrl_wait;
|
||||
unsigned long mtl_tx_fifo_read_ctrl_read;
|
||||
unsigned long mtl_tx_fifo_read_ctrl_idle;
|
||||
unsigned long mac_tx_in_pause;
|
||||
unsigned long mac_tx_frame_ctrl_xfer;
|
||||
unsigned long mac_tx_frame_ctrl_idle;
|
||||
unsigned long mac_tx_frame_ctrl_wait;
|
||||
unsigned long mac_tx_frame_ctrl_pause;
|
||||
unsigned long mac_gmii_tx_proto_engine;
|
||||
unsigned long mtl_rx_fifo_fill_level_full;
|
||||
unsigned long mtl_rx_fifo_fill_above_thresh;
|
||||
unsigned long mtl_rx_fifo_fill_below_thresh;
|
||||
unsigned long mtl_rx_fifo_fill_level_empty;
|
||||
unsigned long mtl_rx_fifo_read_ctrl_flush;
|
||||
unsigned long mtl_rx_fifo_read_ctrl_read_data;
|
||||
unsigned long mtl_rx_fifo_read_ctrl_status;
|
||||
unsigned long mtl_rx_fifo_read_ctrl_idle;
|
||||
unsigned long mtl_rx_fifo_ctrl_active;
|
||||
unsigned long mac_rx_frame_ctrl_fifo;
|
||||
unsigned long mac_gmii_rx_proto_engine;
|
||||
/* EST */
|
||||
unsigned long mtl_est_cgce;
|
||||
unsigned long mtl_est_hlbs;
|
||||
unsigned long mtl_est_hlbf;
|
||||
unsigned long mtl_est_btre;
|
||||
unsigned long mtl_est_btrlm;
|
||||
unsigned long max_sdu_txq_drop[MTL_MAX_TX_QUEUES];
|
||||
unsigned long mtl_est_txq_hlbf[MTL_MAX_TX_QUEUES];
|
||||
/* per queue statistics */
|
||||
struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES];
|
||||
struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES];
|
||||
struct stmmac_pcpu_stats __percpu *pcpu_stats;
|
||||
unsigned long rx_dropped;
|
||||
unsigned long rx_errors;
|
||||
unsigned long tx_dropped;
|
||||
unsigned long tx_errors;
|
||||
};
|
||||
|
||||
/* Safety Feature statistics exposed by ethtool */
|
||||
struct stmmac_safety_stats {
|
||||
unsigned long mac_errors[32];
|
||||
unsigned long mtl_errors[32];
|
||||
unsigned long dma_errors[32];
|
||||
unsigned long dma_dpp_errors[32];
|
||||
};
|
||||
|
||||
/* Number of fields in Safety Stats */
|
||||
#define STMMAC_SAFETY_FEAT_SIZE \
|
||||
(sizeof(struct stmmac_safety_stats) / sizeof(unsigned long))
|
||||
|
||||
/* CSR Frequency Access Defines*/
|
||||
#define CSR_F_35M 35000000
|
||||
#define CSR_F_60M 60000000
|
||||
#define CSR_F_100M 100000000
|
||||
#define CSR_F_150M 150000000
|
||||
#define CSR_F_250M 250000000
|
||||
#define CSR_F_300M 300000000
|
||||
|
||||
#define MAC_CSR_H_FRQ_MASK 0x20
|
||||
|
||||
#define HASH_TABLE_SIZE 64
|
||||
#define PAUSE_TIME 0xffff
|
||||
|
||||
/* Flow Control defines */
|
||||
#define FLOW_OFF 0
|
||||
#define FLOW_RX 1
|
||||
#define FLOW_TX 2
|
||||
#define FLOW_AUTO (FLOW_TX | FLOW_RX)
|
||||
|
||||
/* PCS defines */
|
||||
#define STMMAC_PCS_RGMII (1 << 0)
|
||||
#define STMMAC_PCS_SGMII (1 << 1)
|
||||
|
||||
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
|
||||
|
||||
/* DMA HW feature register fields */
|
||||
#define DMA_HW_FEAT_MIISEL 0x00000001 /* 10/100 Mbps Support */
|
||||
#define DMA_HW_FEAT_GMIISEL 0x00000002 /* 1000 Mbps Support */
|
||||
#define DMA_HW_FEAT_HDSEL 0x00000004 /* Half-Duplex Support */
|
||||
#define DMA_HW_FEAT_EXTHASHEN 0x00000008 /* Expanded DA Hash Filter */
|
||||
#define DMA_HW_FEAT_HASHSEL 0x00000010 /* HASH Filter */
|
||||
#define DMA_HW_FEAT_ADDMAC 0x00000020 /* Multiple MAC Addr Reg */
|
||||
#define DMA_HW_FEAT_PCSSEL 0x00000040 /* PCS registers */
|
||||
#define DMA_HW_FEAT_L3L4FLTREN 0x00000080 /* Layer 3 & Layer 4 Feature */
|
||||
#define DMA_HW_FEAT_SMASEL 0x00000100 /* SMA(MDIO) Interface */
|
||||
#define DMA_HW_FEAT_RWKSEL 0x00000200 /* PMT Remote Wakeup */
|
||||
#define DMA_HW_FEAT_MGKSEL 0x00000400 /* PMT Magic Packet */
|
||||
#define DMA_HW_FEAT_MMCSEL 0x00000800 /* RMON Module */
|
||||
#define DMA_HW_FEAT_TSVER1SEL 0x00001000 /* Only IEEE 1588-2002 */
|
||||
#define DMA_HW_FEAT_TSVER2SEL 0x00002000 /* IEEE 1588-2008 PTPv2 */
|
||||
#define DMA_HW_FEAT_EEESEL 0x00004000 /* Energy Efficient Ethernet */
|
||||
#define DMA_HW_FEAT_AVSEL 0x00008000 /* AV Feature */
|
||||
#define DMA_HW_FEAT_TXCOESEL 0x00010000 /* Checksum Offload in Tx */
|
||||
#define DMA_HW_FEAT_RXTYP1COE 0x00020000 /* IP COE (Type 1) in Rx */
|
||||
#define DMA_HW_FEAT_RXTYP2COE 0x00040000 /* IP COE (Type 2) in Rx */
|
||||
#define DMA_HW_FEAT_RXFIFOSIZE 0x00080000 /* Rx FIFO > 2048 Bytes */
|
||||
#define DMA_HW_FEAT_RXCHCNT 0x00300000 /* No. additional Rx Channels */
|
||||
#define DMA_HW_FEAT_TXCHCNT 0x00c00000 /* No. additional Tx Channels */
|
||||
#define DMA_HW_FEAT_ENHDESSEL 0x01000000 /* Alternate Descriptor */
|
||||
/* Timestamping with Internal System Time */
|
||||
#define DMA_HW_FEAT_INTTSEN 0x02000000
|
||||
#define DMA_HW_FEAT_FLEXIPPSEN 0x04000000 /* Flexible PPS Output */
|
||||
#define DMA_HW_FEAT_SAVLANINS 0x08000000 /* Source Addr or VLAN */
|
||||
#define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY iface */
|
||||
#define DEFAULT_DMA_PBL 8
|
||||
|
||||
/* MSI defines */
|
||||
#define STMMAC_MSI_VEC_MAX 32
|
||||
|
||||
/* PCS status and mask defines */
|
||||
#define PCS_ANE_IRQ BIT(2) /* PCS Auto-Negotiation */
|
||||
#define PCS_LINK_IRQ BIT(1) /* PCS Link */
|
||||
#define PCS_RGSMIIIS_IRQ BIT(0) /* RGMII or SMII Interrupt */
|
||||
|
||||
/* Max/Min RI Watchdog Timer count value */
|
||||
#define MAX_DMA_RIWT 0xff
|
||||
#define MIN_DMA_RIWT 0x10
|
||||
#define DEF_DMA_RIWT 0xa0
|
||||
/* Tx coalesce parameters */
|
||||
#define STMMAC_COAL_TX_TIMER 5000
|
||||
#define STMMAC_MAX_COAL_TX_TICK 100000
|
||||
#define STMMAC_TX_MAX_FRAMES 256
|
||||
#define STMMAC_TX_FRAMES 25
|
||||
#define STMMAC_RX_FRAMES 0
|
||||
|
||||
/* Packets types */
|
||||
enum packets_types {
|
||||
PACKET_AVCPQ = 0x1, /* AV Untagged Control packets */
|
||||
PACKET_PTPQ = 0x2, /* PTP Packets */
|
||||
PACKET_DCBCPQ = 0x3, /* DCB Control Packets */
|
||||
PACKET_UPQ = 0x4, /* Untagged Packets */
|
||||
PACKET_MCBCQ = 0x5, /* Multicast & Broadcast Packets */
|
||||
};
|
||||
|
||||
/* Rx IPC status */
|
||||
enum rx_frame_status {
|
||||
good_frame = 0x0,
|
||||
discard_frame = 0x1,
|
||||
csum_none = 0x2,
|
||||
llc_snap = 0x4,
|
||||
dma_own = 0x8,
|
||||
rx_not_ls = 0x10,
|
||||
};
|
||||
|
||||
/* Tx status */
|
||||
enum tx_frame_status {
|
||||
tx_done = 0x0,
|
||||
tx_not_ls = 0x1,
|
||||
tx_err = 0x2,
|
||||
tx_dma_own = 0x4,
|
||||
tx_err_bump_tc = 0x8,
|
||||
};
|
||||
|
||||
enum dma_irq_status {
|
||||
tx_hard_error = 0x1,
|
||||
tx_hard_error_bump_tc = 0x2,
|
||||
handle_rx = 0x4,
|
||||
handle_tx = 0x8,
|
||||
};
|
||||
|
||||
enum dma_irq_dir {
|
||||
DMA_DIR_RX = 0x1,
|
||||
DMA_DIR_TX = 0x2,
|
||||
DMA_DIR_RXTX = 0x3,
|
||||
};
|
||||
|
||||
enum request_irq_err {
|
||||
REQ_IRQ_ERR_ALL,
|
||||
REQ_IRQ_ERR_TX,
|
||||
REQ_IRQ_ERR_RX,
|
||||
REQ_IRQ_ERR_SFTY,
|
||||
REQ_IRQ_ERR_SFTY_UE,
|
||||
REQ_IRQ_ERR_SFTY_CE,
|
||||
REQ_IRQ_ERR_LPI,
|
||||
REQ_IRQ_ERR_WOL,
|
||||
REQ_IRQ_ERR_MAC,
|
||||
REQ_IRQ_ERR_NO,
|
||||
};
|
||||
|
||||
/* EEE and LPI defines */
|
||||
#define CORE_IRQ_TX_PATH_IN_LPI_MODE (1 << 0)
|
||||
#define CORE_IRQ_TX_PATH_EXIT_LPI_MODE (1 << 1)
|
||||
#define CORE_IRQ_RX_PATH_IN_LPI_MODE (1 << 2)
|
||||
#define CORE_IRQ_RX_PATH_EXIT_LPI_MODE (1 << 3)
|
||||
|
||||
/* FPE defines */
|
||||
#define FPE_EVENT_UNKNOWN 0
|
||||
#define FPE_EVENT_TRSP BIT(0)
|
||||
#define FPE_EVENT_TVER BIT(1)
|
||||
#define FPE_EVENT_RRSP BIT(2)
|
||||
#define FPE_EVENT_RVER BIT(3)
|
||||
|
||||
#define CORE_IRQ_MTL_RX_OVERFLOW BIT(8)
|
||||
|
||||
/* Physical Coding Sublayer */
|
||||
struct rgmii_adv {
|
||||
unsigned int pause;
|
||||
unsigned int duplex;
|
||||
unsigned int lp_pause;
|
||||
unsigned int lp_duplex;
|
||||
};
|
||||
|
||||
#define STMMAC_PCS_PAUSE 1
|
||||
#define STMMAC_PCS_ASYM_PAUSE 2
|
||||
|
||||
/* DMA HW capabilities */
|
||||
struct dma_features {
|
||||
unsigned int mbps_10_100;
|
||||
unsigned int mbps_1000;
|
||||
unsigned int half_duplex;
|
||||
unsigned int hash_filter;
|
||||
unsigned int multi_addr;
|
||||
unsigned int pcs;
|
||||
unsigned int sma_mdio;
|
||||
unsigned int pmt_remote_wake_up;
|
||||
unsigned int pmt_magic_frame;
|
||||
unsigned int rmon;
|
||||
/* IEEE 1588-2002 */
|
||||
unsigned int time_stamp;
|
||||
/* IEEE 1588-2008 */
|
||||
unsigned int atime_stamp;
|
||||
/* 802.3az - Energy-Efficient Ethernet (EEE) */
|
||||
unsigned int eee;
|
||||
unsigned int av;
|
||||
unsigned int hash_tb_sz;
|
||||
unsigned int tsoen;
|
||||
/* TX and RX csum */
|
||||
unsigned int tx_coe;
|
||||
unsigned int rx_coe;
|
||||
unsigned int rx_coe_type1;
|
||||
unsigned int rx_coe_type2;
|
||||
unsigned int rxfifo_over_2048;
|
||||
/* TX and RX number of channels */
|
||||
unsigned int number_rx_channel;
|
||||
unsigned int number_tx_channel;
|
||||
/* TX and RX number of queues */
|
||||
unsigned int number_rx_queues;
|
||||
unsigned int number_tx_queues;
|
||||
/* PPS output */
|
||||
unsigned int pps_out_num;
|
||||
/* Number of Traffic Classes */
|
||||
unsigned int numtc;
|
||||
/* DCB Feature Enable */
|
||||
unsigned int dcben;
|
||||
/* IEEE 1588 High Word Register Enable */
|
||||
unsigned int advthword;
|
||||
/* PTP Offload Enable */
|
||||
unsigned int ptoen;
|
||||
/* One-Step Timestamping Enable */
|
||||
unsigned int osten;
|
||||
/* Priority-Based Flow Control Enable */
|
||||
unsigned int pfcen;
|
||||
/* Alternate (enhanced) DESC mode */
|
||||
unsigned int enh_desc;
|
||||
/* TX and RX FIFO sizes */
|
||||
unsigned int tx_fifo_size;
|
||||
unsigned int rx_fifo_size;
|
||||
/* Automotive Safety Package */
|
||||
unsigned int asp;
|
||||
/* RX Parser */
|
||||
unsigned int frpsel;
|
||||
unsigned int frpbs;
|
||||
unsigned int frpes;
|
||||
unsigned int addr64;
|
||||
unsigned int host_dma_width;
|
||||
unsigned int rssen;
|
||||
unsigned int vlhash;
|
||||
unsigned int sphen;
|
||||
unsigned int vlins;
|
||||
unsigned int dvlan;
|
||||
unsigned int l3l4fnum;
|
||||
unsigned int arpoffsel;
|
||||
/* One Step for PTP over UDP/IP Feature Enable */
|
||||
unsigned int pou_ost_en;
|
||||
/* Tx Timestamp FIFO Depth */
|
||||
unsigned int ttsfd;
|
||||
/* Queue/Channel-Based VLAN tag insertion on Tx */
|
||||
unsigned int cbtisel;
|
||||
/* Supported Parallel Instruction Processor Engines */
|
||||
unsigned int frppipe_num;
|
||||
/* Number of Extended VLAN Tag Filters */
|
||||
unsigned int nrvf_num;
|
||||
/* TSN Features */
|
||||
unsigned int estwid;
|
||||
unsigned int estdep;
|
||||
unsigned int estsel;
|
||||
unsigned int fpesel;
|
||||
unsigned int tbssel;
|
||||
/* Number of DMA channels enabled for TBS */
|
||||
unsigned int tbs_ch_num;
|
||||
/* Per-Stream Filtering Enable */
|
||||
unsigned int sgfsel;
|
||||
/* Numbers of Auxiliary Snapshot Inputs */
|
||||
unsigned int aux_snapshot_n;
|
||||
/* Timestamp System Time Source */
|
||||
unsigned int tssrc;
|
||||
/* Enhanced DMA Enable */
|
||||
unsigned int edma;
|
||||
/* Different Descriptor Cache Enable */
|
||||
unsigned int ediffc;
|
||||
/* VxLAN/NVGRE Enable */
|
||||
unsigned int vxn;
|
||||
/* Debug Memory Interface Enable */
|
||||
unsigned int dbgmem;
|
||||
/* Number of Policing Counters */
|
||||
unsigned int pcsel;
|
||||
};
|
||||
|
||||
/* RX Buffer size must be multiple of 4/8/16 bytes */
|
||||
#define BUF_SIZE_16KiB 16368
|
||||
#define BUF_SIZE_8KiB 8188
|
||||
#define BUF_SIZE_4KiB 4096
|
||||
#define BUF_SIZE_2KiB 2048
|
||||
|
||||
/* Power Down and WOL */
|
||||
#define PMT_NOT_SUPPORTED 0
|
||||
#define PMT_SUPPORTED 1
|
||||
|
||||
/* Common MAC defines */
|
||||
#define MAC_CTRL_REG 0x00000000 /* MAC Control */
|
||||
#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */
|
||||
#define MAC_ENABLE_RX 0x00000004 /* Receiver Enable */
|
||||
|
||||
/* Default LPI timers */
|
||||
#define STMMAC_DEFAULT_LIT_LS 0x3E8
|
||||
#define STMMAC_DEFAULT_TWT_LS 0x1E
|
||||
#define STMMAC_ET_MAX 0xFFFFF
|
||||
|
||||
#define STMMAC_CHAIN_MODE 0x1
|
||||
#define STMMAC_RING_MODE 0x2
|
||||
|
||||
#define JUMBO_LEN 9000
|
||||
|
||||
/* Receive Side Scaling */
|
||||
#define STMMAC_RSS_HASH_KEY_SIZE 40
|
||||
#define STMMAC_RSS_MAX_TABLE_SIZE 256
|
||||
|
||||
/* VLAN */
|
||||
#define STMMAC_VLAN_NONE 0x0
|
||||
#define STMMAC_VLAN_REMOVE 0x1
|
||||
#define STMMAC_VLAN_INSERT 0x2
|
||||
#define STMMAC_VLAN_REPLACE 0x3
|
||||
|
||||
extern const struct stmmac_desc_ops enh_desc_ops;
|
||||
extern const struct stmmac_desc_ops ndesc_ops;
|
||||
|
||||
struct mac_device_info;
|
||||
|
||||
extern const struct stmmac_hwtimestamp stmmac_ptp;
|
||||
extern const struct stmmac_mode_ops dwmac4_ring_mode_ops;
|
||||
|
||||
struct mac_link {
|
||||
u32 caps;
|
||||
u32 speed_mask;
|
||||
u32 speed10;
|
||||
u32 speed100;
|
||||
u32 speed1000;
|
||||
u32 speed2500;
|
||||
u32 duplex;
|
||||
struct {
|
||||
u32 speed2500;
|
||||
u32 speed5000;
|
||||
u32 speed10000;
|
||||
} xgmii;
|
||||
struct {
|
||||
u32 speed25000;
|
||||
u32 speed40000;
|
||||
u32 speed50000;
|
||||
u32 speed100000;
|
||||
} xlgmii;
|
||||
};
|
||||
|
||||
struct mii_regs {
|
||||
unsigned int addr; /* MII Address */
|
||||
unsigned int data; /* MII Data */
|
||||
unsigned int addr_shift; /* MII address shift */
|
||||
unsigned int reg_shift; /* MII reg shift */
|
||||
unsigned int addr_mask; /* MII address mask */
|
||||
unsigned int reg_mask; /* MII reg mask */
|
||||
unsigned int clk_csr_shift;
|
||||
unsigned int clk_csr_mask;
|
||||
};
|
||||
|
||||
struct mac_device_info {
|
||||
const struct stmmac_ops *mac;
|
||||
const struct stmmac_desc_ops *desc;
|
||||
const struct stmmac_dma_ops *dma;
|
||||
const struct stmmac_mode_ops *mode;
|
||||
const struct stmmac_hwtimestamp *ptp;
|
||||
const struct stmmac_tc_ops *tc;
|
||||
const struct stmmac_mmc_ops *mmc;
|
||||
const struct stmmac_est_ops *est;
|
||||
struct dw_xpcs *xpcs;
|
||||
struct phylink_pcs *phylink_pcs;
|
||||
struct mii_regs mii; /* MII register Addresses */
|
||||
struct mac_link link;
|
||||
void __iomem *pcsr; /* vpointer to device CSRs */
|
||||
unsigned int multicast_filter_bins;
|
||||
unsigned int unicast_filter_entries;
|
||||
unsigned int mcast_bits_log2;
|
||||
unsigned int rx_csum;
|
||||
unsigned int pcs;
|
||||
unsigned int pmt;
|
||||
unsigned int ps;
|
||||
unsigned int xlgmac;
|
||||
unsigned int num_vlan;
|
||||
u32 vlan_filter[32];
|
||||
bool vlan_fail_q_en;
|
||||
u8 vlan_fail_q;
|
||||
bool hw_vlan_en;
|
||||
};
|
||||
|
||||
struct stmmac_rx_routing {
|
||||
u32 reg_mask;
|
||||
u32 reg_shift;
|
||||
};
|
||||
|
||||
int dwmac100_setup(struct stmmac_priv *priv);
|
||||
int dwmac1000_setup(struct stmmac_priv *priv);
|
||||
int dwmac4_setup(struct stmmac_priv *priv);
|
||||
int dwxgmac2_setup(struct stmmac_priv *priv);
|
||||
int dwxlgmac2_setup(struct stmmac_priv *priv);
|
||||
|
||||
void stmmac_set_mac_addr(void __iomem *ioaddr, const u8 addr[6],
|
||||
unsigned int high, unsigned int low);
|
||||
void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int high, unsigned int low);
|
||||
void stmmac_set_mac(void __iomem *ioaddr, bool enable);
|
||||
|
||||
void stmmac_dwmac4_set_mac_addr(void __iomem *ioaddr, const u8 addr[6],
|
||||
unsigned int high, unsigned int low);
|
||||
void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int high, unsigned int low);
|
||||
void stmmac_dwmac4_set_mac(void __iomem *ioaddr, bool enable);
|
||||
|
||||
void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
|
||||
|
||||
extern const struct stmmac_mode_ops ring_mode_ops;
|
||||
extern const struct stmmac_mode_ops chain_mode_ops;
|
||||
extern const struct stmmac_desc_ops dwmac4_desc_ops;
|
||||
|
||||
#endif /* __COMMON_H__ */
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
Header File to describe the DMA descriptors and related definitions.
|
||||
This is for DWMAC100 and 1000 cores.
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DESCS_H__
|
||||
#define __DESCS_H__
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/* Normal receive descriptor defines */
|
||||
|
||||
/* RDES0 */
|
||||
#define RDES0_PAYLOAD_CSUM_ERR BIT(0)
|
||||
#define RDES0_CRC_ERROR BIT(1)
|
||||
#define RDES0_DRIBBLING BIT(2)
|
||||
#define RDES0_MII_ERROR BIT(3)
|
||||
#define RDES0_RECEIVE_WATCHDOG BIT(4)
|
||||
#define RDES0_FRAME_TYPE BIT(5)
|
||||
#define RDES0_COLLISION BIT(6)
|
||||
#define RDES0_IPC_CSUM_ERROR BIT(7)
|
||||
#define RDES0_LAST_DESCRIPTOR BIT(8)
|
||||
#define RDES0_FIRST_DESCRIPTOR BIT(9)
|
||||
#define RDES0_VLAN_TAG BIT(10)
|
||||
#define RDES0_OVERFLOW_ERROR BIT(11)
|
||||
#define RDES0_LENGTH_ERROR BIT(12)
|
||||
#define RDES0_SA_FILTER_FAIL BIT(13)
|
||||
#define RDES0_DESCRIPTOR_ERROR BIT(14)
|
||||
#define RDES0_ERROR_SUMMARY BIT(15)
|
||||
#define RDES0_FRAME_LEN_MASK GENMASK(29, 16)
|
||||
#define RDES0_FRAME_LEN_SHIFT 16
|
||||
#define RDES0_DA_FILTER_FAIL BIT(30)
|
||||
#define RDES0_OWN BIT(31)
|
||||
/* RDES1 */
|
||||
#define RDES1_BUFFER1_SIZE_MASK GENMASK(10, 0)
|
||||
#define RDES1_BUFFER2_SIZE_MASK GENMASK(21, 11)
|
||||
#define RDES1_BUFFER2_SIZE_SHIFT 11
|
||||
#define RDES1_SECOND_ADDRESS_CHAINED BIT(24)
|
||||
#define RDES1_END_RING BIT(25)
|
||||
#define RDES1_DISABLE_IC BIT(31)
|
||||
|
||||
/* Enhanced receive descriptor defines */
|
||||
|
||||
/* RDES0 (similar to normal RDES) */
|
||||
#define ERDES0_RX_MAC_ADDR BIT(0)
|
||||
|
||||
/* RDES1: completely differ from normal desc definitions */
|
||||
#define ERDES1_BUFFER1_SIZE_MASK GENMASK(12, 0)
|
||||
#define ERDES1_SECOND_ADDRESS_CHAINED BIT(14)
|
||||
#define ERDES1_END_RING BIT(15)
|
||||
#define ERDES1_BUFFER2_SIZE_MASK GENMASK(28, 16)
|
||||
#define ERDES1_BUFFER2_SIZE_SHIFT 16
|
||||
#define ERDES1_DISABLE_IC BIT(31)
|
||||
|
||||
/* Normal transmit descriptor defines */
|
||||
/* TDES0 */
|
||||
#define TDES0_DEFERRED BIT(0)
|
||||
#define TDES0_UNDERFLOW_ERROR BIT(1)
|
||||
#define TDES0_EXCESSIVE_DEFERRAL BIT(2)
|
||||
#define TDES0_COLLISION_COUNT_MASK GENMASK(6, 3)
|
||||
#define TDES0_VLAN_FRAME BIT(7)
|
||||
#define TDES0_EXCESSIVE_COLLISIONS BIT(8)
|
||||
#define TDES0_LATE_COLLISION BIT(9)
|
||||
#define TDES0_NO_CARRIER BIT(10)
|
||||
#define TDES0_LOSS_CARRIER BIT(11)
|
||||
#define TDES0_PAYLOAD_ERROR BIT(12)
|
||||
#define TDES0_FRAME_FLUSHED BIT(13)
|
||||
#define TDES0_JABBER_TIMEOUT BIT(14)
|
||||
#define TDES0_ERROR_SUMMARY BIT(15)
|
||||
#define TDES0_IP_HEADER_ERROR BIT(16)
|
||||
#define TDES0_TIME_STAMP_STATUS BIT(17)
|
||||
#define TDES0_OWN ((u32)BIT(31)) /* silence sparse */
|
||||
/* TDES1 */
|
||||
#define TDES1_BUFFER1_SIZE_MASK GENMASK(10, 0)
|
||||
#define TDES1_BUFFER2_SIZE_MASK GENMASK(21, 11)
|
||||
#define TDES1_BUFFER2_SIZE_SHIFT 11
|
||||
#define TDES1_TIME_STAMP_ENABLE BIT(22)
|
||||
#define TDES1_DISABLE_PADDING BIT(23)
|
||||
#define TDES1_SECOND_ADDRESS_CHAINED BIT(24)
|
||||
#define TDES1_END_RING BIT(25)
|
||||
#define TDES1_CRC_DISABLE BIT(26)
|
||||
#define TDES1_CHECKSUM_INSERTION_MASK GENMASK(28, 27)
|
||||
#define TDES1_CHECKSUM_INSERTION_SHIFT 27
|
||||
#define TDES1_FIRST_SEGMENT BIT(29)
|
||||
#define TDES1_LAST_SEGMENT BIT(30)
|
||||
#define TDES1_INTERRUPT BIT(31)
|
||||
|
||||
/* Enhanced transmit descriptor defines */
|
||||
/* TDES0 */
|
||||
#define ETDES0_DEFERRED BIT(0)
|
||||
#define ETDES0_UNDERFLOW_ERROR BIT(1)
|
||||
#define ETDES0_EXCESSIVE_DEFERRAL BIT(2)
|
||||
#define ETDES0_COLLISION_COUNT_MASK GENMASK(6, 3)
|
||||
#define ETDES0_VLAN_FRAME BIT(7)
|
||||
#define ETDES0_EXCESSIVE_COLLISIONS BIT(8)
|
||||
#define ETDES0_LATE_COLLISION BIT(9)
|
||||
#define ETDES0_NO_CARRIER BIT(10)
|
||||
#define ETDES0_LOSS_CARRIER BIT(11)
|
||||
#define ETDES0_PAYLOAD_ERROR BIT(12)
|
||||
#define ETDES0_FRAME_FLUSHED BIT(13)
|
||||
#define ETDES0_JABBER_TIMEOUT BIT(14)
|
||||
#define ETDES0_ERROR_SUMMARY BIT(15)
|
||||
#define ETDES0_IP_HEADER_ERROR BIT(16)
|
||||
#define ETDES0_TIME_STAMP_STATUS BIT(17)
|
||||
#define ETDES0_SECOND_ADDRESS_CHAINED BIT(20)
|
||||
#define ETDES0_END_RING BIT(21)
|
||||
#define ETDES0_CHECKSUM_INSERTION_MASK GENMASK(23, 22)
|
||||
#define ETDES0_CHECKSUM_INSERTION_SHIFT 22
|
||||
#define ETDES0_TIME_STAMP_ENABLE BIT(25)
|
||||
#define ETDES0_DISABLE_PADDING BIT(26)
|
||||
#define ETDES0_CRC_DISABLE BIT(27)
|
||||
#define ETDES0_FIRST_SEGMENT BIT(28)
|
||||
#define ETDES0_LAST_SEGMENT BIT(29)
|
||||
#define ETDES0_INTERRUPT BIT(30)
|
||||
#define ETDES0_OWN ((u32)BIT(31)) /* silence sparse */
|
||||
/* TDES1 */
|
||||
#define ETDES1_BUFFER1_SIZE_MASK GENMASK(12, 0)
|
||||
#define ETDES1_BUFFER2_SIZE_MASK GENMASK(28, 16)
|
||||
#define ETDES1_BUFFER2_SIZE_SHIFT 16
|
||||
|
||||
/* Extended Receive descriptor definitions */
|
||||
#define ERDES4_IP_PAYLOAD_TYPE_MASK GENMASK(6, 2)
|
||||
#define ERDES4_IP_HDR_ERR BIT(3)
|
||||
#define ERDES4_IP_PAYLOAD_ERR BIT(4)
|
||||
#define ERDES4_IP_CSUM_BYPASSED BIT(5)
|
||||
#define ERDES4_IPV4_PKT_RCVD BIT(6)
|
||||
#define ERDES4_IPV6_PKT_RCVD BIT(7)
|
||||
#define ERDES4_MSG_TYPE_MASK GENMASK(11, 8)
|
||||
#define ERDES4_PTP_FRAME_TYPE BIT(12)
|
||||
#define ERDES4_PTP_VER BIT(13)
|
||||
#define ERDES4_TIMESTAMP_DROPPED BIT(14)
|
||||
#define ERDES4_AV_PKT_RCVD BIT(16)
|
||||
#define ERDES4_AV_TAGGED_PKT_RCVD BIT(17)
|
||||
#define ERDES4_VLAN_TAG_PRI_VAL_MASK GENMASK(20, 18)
|
||||
#define ERDES4_L3_FILTER_MATCH BIT(24)
|
||||
#define ERDES4_L4_FILTER_MATCH BIT(25)
|
||||
#define ERDES4_L3_L4_FILT_NO_MATCH_MASK GENMASK(27, 26)
|
||||
|
||||
/* Extended RDES4 message type definitions */
|
||||
#define RDES_EXT_NO_PTP 0x0
|
||||
#define RDES_EXT_SYNC 0x1
|
||||
#define RDES_EXT_FOLLOW_UP 0x2
|
||||
#define RDES_EXT_DELAY_REQ 0x3
|
||||
#define RDES_EXT_DELAY_RESP 0x4
|
||||
#define RDES_EXT_PDELAY_REQ 0x5
|
||||
#define RDES_EXT_PDELAY_RESP 0x6
|
||||
#define RDES_EXT_PDELAY_FOLLOW_UP 0x7
|
||||
#define RDES_PTP_ANNOUNCE 0x8
|
||||
#define RDES_PTP_MANAGEMENT 0x9
|
||||
#define RDES_PTP_SIGNALING 0xa
|
||||
#define RDES_PTP_PKT_RESERVED_TYPE 0xf
|
||||
|
||||
/* Basic descriptor structure for normal and alternate descriptors */
|
||||
struct dma_desc {
|
||||
__le32 des0;
|
||||
__le32 des1;
|
||||
__le32 des2;
|
||||
__le32 des3;
|
||||
};
|
||||
|
||||
/* Extended descriptor structure (e.g. >= databook 3.50a) */
|
||||
struct dma_extended_desc {
|
||||
struct dma_desc basic; /* Basic descriptors */
|
||||
__le32 des4; /* Extended Status */
|
||||
__le32 des5; /* Reserved */
|
||||
__le32 des6; /* Tx/Rx Timestamp Low */
|
||||
__le32 des7; /* Tx/Rx Timestamp High */
|
||||
};
|
||||
|
||||
/* Enhanced descriptor for TBS */
|
||||
struct dma_edesc {
|
||||
__le32 des4;
|
||||
__le32 des5;
|
||||
__le32 des6;
|
||||
__le32 des7;
|
||||
struct dma_desc basic;
|
||||
};
|
||||
|
||||
/* Transmit checksum insertion control */
|
||||
#define TX_CIC_FULL 3 /* Include IP header and pseudoheader */
|
||||
|
||||
#endif /* __DESCS_H__ */
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
Header File to describe the DMA descriptors and related definitions.
|
||||
This is for DWMAC100 and 1000 cores.
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DESCS_H__
|
||||
#define __DESCS_H__
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/* Normal receive descriptor defines */
|
||||
|
||||
/* RDES0 */
|
||||
#define RDES0_PAYLOAD_CSUM_ERR BIT(0)
|
||||
#define RDES0_CRC_ERROR BIT(1)
|
||||
#define RDES0_DRIBBLING BIT(2)
|
||||
#define RDES0_MII_ERROR BIT(3)
|
||||
#define RDES0_RECEIVE_WATCHDOG BIT(4)
|
||||
#define RDES0_FRAME_TYPE BIT(5)
|
||||
#define RDES0_COLLISION BIT(6)
|
||||
#define RDES0_IPC_CSUM_ERROR BIT(7)
|
||||
#define RDES0_LAST_DESCRIPTOR BIT(8)
|
||||
#define RDES0_FIRST_DESCRIPTOR BIT(9)
|
||||
#define RDES0_VLAN_TAG BIT(10)
|
||||
#define RDES0_OVERFLOW_ERROR BIT(11)
|
||||
#define RDES0_LENGTH_ERROR BIT(12)
|
||||
#define RDES0_SA_FILTER_FAIL BIT(13)
|
||||
#define RDES0_DESCRIPTOR_ERROR BIT(14)
|
||||
#define RDES0_ERROR_SUMMARY BIT(15)
|
||||
#define RDES0_FRAME_LEN_MASK GENMASK(29, 16)
|
||||
#define RDES0_FRAME_LEN_SHIFT 16
|
||||
#define RDES0_DA_FILTER_FAIL BIT(30)
|
||||
#define RDES0_OWN BIT(31)
|
||||
/* RDES1 */
|
||||
#define RDES1_BUFFER1_SIZE_MASK GENMASK(10, 0)
|
||||
#define RDES1_BUFFER2_SIZE_MASK GENMASK(21, 11)
|
||||
#define RDES1_BUFFER2_SIZE_SHIFT 11
|
||||
#define RDES1_SECOND_ADDRESS_CHAINED BIT(24)
|
||||
#define RDES1_END_RING BIT(25)
|
||||
#define RDES1_DISABLE_IC BIT(31)
|
||||
|
||||
/* Enhanced receive descriptor defines */
|
||||
|
||||
/* RDES0 (similar to normal RDES) */
|
||||
#define ERDES0_RX_MAC_ADDR BIT(0)
|
||||
|
||||
/* RDES1: completely differ from normal desc definitions */
|
||||
#define ERDES1_BUFFER1_SIZE_MASK GENMASK(12, 0)
|
||||
#define ERDES1_SECOND_ADDRESS_CHAINED BIT(14)
|
||||
#define ERDES1_END_RING BIT(15)
|
||||
#define ERDES1_BUFFER2_SIZE_MASK GENMASK(28, 16)
|
||||
#define ERDES1_BUFFER2_SIZE_SHIFT 16
|
||||
#define ERDES1_DISABLE_IC BIT(31)
|
||||
|
||||
/* Normal transmit descriptor defines */
|
||||
/* TDES0 */
|
||||
#define TDES0_DEFERRED BIT(0)
|
||||
#define TDES0_UNDERFLOW_ERROR BIT(1)
|
||||
#define TDES0_EXCESSIVE_DEFERRAL BIT(2)
|
||||
#define TDES0_COLLISION_COUNT_MASK GENMASK(6, 3)
|
||||
#define TDES0_VLAN_FRAME BIT(7)
|
||||
#define TDES0_EXCESSIVE_COLLISIONS BIT(8)
|
||||
#define TDES0_LATE_COLLISION BIT(9)
|
||||
#define TDES0_NO_CARRIER BIT(10)
|
||||
#define TDES0_LOSS_CARRIER BIT(11)
|
||||
#define TDES0_PAYLOAD_ERROR BIT(12)
|
||||
#define TDES0_FRAME_FLUSHED BIT(13)
|
||||
#define TDES0_JABBER_TIMEOUT BIT(14)
|
||||
#define TDES0_ERROR_SUMMARY BIT(15)
|
||||
#define TDES0_IP_HEADER_ERROR BIT(16)
|
||||
#define TDES0_TIME_STAMP_STATUS BIT(17)
|
||||
#define TDES0_OWN ((u32)BIT(31)) /* silence sparse */
|
||||
/* TDES1 */
|
||||
#define TDES1_BUFFER1_SIZE_MASK GENMASK(10, 0)
|
||||
#define TDES1_BUFFER2_SIZE_MASK GENMASK(21, 11)
|
||||
#define TDES1_BUFFER2_SIZE_SHIFT 11
|
||||
#define TDES1_TIME_STAMP_ENABLE BIT(22)
|
||||
#define TDES1_DISABLE_PADDING BIT(23)
|
||||
#define TDES1_SECOND_ADDRESS_CHAINED BIT(24)
|
||||
#define TDES1_END_RING BIT(25)
|
||||
#define TDES1_CRC_DISABLE BIT(26)
|
||||
#define TDES1_CHECKSUM_INSERTION_MASK GENMASK(28, 27)
|
||||
#define TDES1_CHECKSUM_INSERTION_SHIFT 27
|
||||
#define TDES1_FIRST_SEGMENT BIT(29)
|
||||
#define TDES1_LAST_SEGMENT BIT(30)
|
||||
#define TDES1_INTERRUPT BIT(31)
|
||||
|
||||
/* Enhanced transmit descriptor defines */
|
||||
/* TDES0 */
|
||||
#define ETDES0_DEFERRED BIT(0)
|
||||
#define ETDES0_UNDERFLOW_ERROR BIT(1)
|
||||
#define ETDES0_EXCESSIVE_DEFERRAL BIT(2)
|
||||
#define ETDES0_COLLISION_COUNT_MASK GENMASK(6, 3)
|
||||
#define ETDES0_VLAN_FRAME BIT(7)
|
||||
#define ETDES0_EXCESSIVE_COLLISIONS BIT(8)
|
||||
#define ETDES0_LATE_COLLISION BIT(9)
|
||||
#define ETDES0_NO_CARRIER BIT(10)
|
||||
#define ETDES0_LOSS_CARRIER BIT(11)
|
||||
#define ETDES0_PAYLOAD_ERROR BIT(12)
|
||||
#define ETDES0_FRAME_FLUSHED BIT(13)
|
||||
#define ETDES0_JABBER_TIMEOUT BIT(14)
|
||||
#define ETDES0_ERROR_SUMMARY BIT(15)
|
||||
#define ETDES0_IP_HEADER_ERROR BIT(16)
|
||||
#define ETDES0_TIME_STAMP_STATUS BIT(17)
|
||||
#define ETDES0_SECOND_ADDRESS_CHAINED BIT(20)
|
||||
#define ETDES0_END_RING BIT(21)
|
||||
#define ETDES0_CHECKSUM_INSERTION_MASK GENMASK(23, 22)
|
||||
#define ETDES0_CHECKSUM_INSERTION_SHIFT 22
|
||||
#define ETDES0_TIME_STAMP_ENABLE BIT(25)
|
||||
#define ETDES0_DISABLE_PADDING BIT(26)
|
||||
#define ETDES0_CRC_DISABLE BIT(27)
|
||||
#define ETDES0_FIRST_SEGMENT BIT(28)
|
||||
#define ETDES0_LAST_SEGMENT BIT(29)
|
||||
#define ETDES0_INTERRUPT BIT(30)
|
||||
#define ETDES0_OWN ((u32)BIT(31)) /* silence sparse */
|
||||
/* TDES1 */
|
||||
#define ETDES1_BUFFER1_SIZE_MASK GENMASK(12, 0)
|
||||
#define ETDES1_BUFFER2_SIZE_MASK GENMASK(28, 16)
|
||||
#define ETDES1_BUFFER2_SIZE_SHIFT 16
|
||||
|
||||
/* Extended Receive descriptor definitions */
|
||||
#define ERDES4_IP_PAYLOAD_TYPE_MASK GENMASK(6, 2)
|
||||
#define ERDES4_IP_HDR_ERR BIT(3)
|
||||
#define ERDES4_IP_PAYLOAD_ERR BIT(4)
|
||||
#define ERDES4_IP_CSUM_BYPASSED BIT(5)
|
||||
#define ERDES4_IPV4_PKT_RCVD BIT(6)
|
||||
#define ERDES4_IPV6_PKT_RCVD BIT(7)
|
||||
#define ERDES4_MSG_TYPE_MASK GENMASK(11, 8)
|
||||
#define ERDES4_PTP_FRAME_TYPE BIT(12)
|
||||
#define ERDES4_PTP_VER BIT(13)
|
||||
#define ERDES4_TIMESTAMP_DROPPED BIT(14)
|
||||
#define ERDES4_AV_PKT_RCVD BIT(16)
|
||||
#define ERDES4_AV_TAGGED_PKT_RCVD BIT(17)
|
||||
#define ERDES4_VLAN_TAG_PRI_VAL_MASK GENMASK(20, 18)
|
||||
#define ERDES4_L3_FILTER_MATCH BIT(24)
|
||||
#define ERDES4_L4_FILTER_MATCH BIT(25)
|
||||
#define ERDES4_L3_L4_FILT_NO_MATCH_MASK GENMASK(27, 26)
|
||||
|
||||
/* Extended RDES4 message type definitions */
|
||||
#define RDES_EXT_NO_PTP 0x0
|
||||
#define RDES_EXT_SYNC 0x1
|
||||
#define RDES_EXT_FOLLOW_UP 0x2
|
||||
#define RDES_EXT_DELAY_REQ 0x3
|
||||
#define RDES_EXT_DELAY_RESP 0x4
|
||||
#define RDES_EXT_PDELAY_REQ 0x5
|
||||
#define RDES_EXT_PDELAY_RESP 0x6
|
||||
#define RDES_EXT_PDELAY_FOLLOW_UP 0x7
|
||||
#define RDES_PTP_ANNOUNCE 0x8
|
||||
#define RDES_PTP_MANAGEMENT 0x9
|
||||
#define RDES_PTP_SIGNALING 0xa
|
||||
#define RDES_PTP_PKT_RESERVED_TYPE 0xf
|
||||
|
||||
/* Basic descriptor structure for normal and alternate descriptors */
|
||||
struct dma_desc {
|
||||
__le32 des0;
|
||||
__le32 des1;
|
||||
__le32 des2;
|
||||
__le32 des3;
|
||||
};
|
||||
|
||||
/* Extended descriptor structure (e.g. >= databook 3.50a) */
|
||||
struct dma_extended_desc {
|
||||
struct dma_desc basic; /* Basic descriptors */
|
||||
__le32 des4; /* Extended Status */
|
||||
__le32 des5; /* Reserved */
|
||||
__le32 des6; /* Tx/Rx Timestamp Low */
|
||||
__le32 des7; /* Tx/Rx Timestamp High */
|
||||
};
|
||||
|
||||
/* Enhanced descriptor for TBS */
|
||||
struct dma_edesc {
|
||||
__le32 des4;
|
||||
__le32 des5;
|
||||
__le32 des6;
|
||||
__le32 des7;
|
||||
struct dma_desc basic;
|
||||
};
|
||||
|
||||
/* Transmit checksum insertion control */
|
||||
#define TX_CIC_FULL 3 /* Include IP header and pseudoheader */
|
||||
|
||||
#endif /* __DESCS_H__ */
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
Header File to describe Normal/enhanced descriptor functions used for RING
|
||||
and CHAINED modes.
|
||||
|
||||
Copyright(C) 2011 STMicroelectronics Ltd
|
||||
|
||||
It defines all the functions used to handle the normal/enhanced
|
||||
descriptors in case of the DMA is configured to work in chained or
|
||||
in ring mode.
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DESC_COM_H__
|
||||
#define __DESC_COM_H__
|
||||
|
||||
/* Specific functions used for Ring mode */
|
||||
|
||||
/* Enhanced descriptors */
|
||||
static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end,
|
||||
int bfsize)
|
||||
{
|
||||
if (bfsize == BUF_SIZE_16KiB)
|
||||
p->des1 |= cpu_to_le32((BUF_SIZE_8KiB
|
||||
<< ERDES1_BUFFER2_SIZE_SHIFT)
|
||||
& ERDES1_BUFFER2_SIZE_MASK);
|
||||
|
||||
if (end)
|
||||
p->des1 |= cpu_to_le32(ERDES1_END_RING);
|
||||
}
|
||||
|
||||
static inline void enh_desc_end_tx_desc_on_ring(struct dma_desc *p, int end)
|
||||
{
|
||||
if (end)
|
||||
p->des0 |= cpu_to_le32(ETDES0_END_RING);
|
||||
else
|
||||
p->des0 &= cpu_to_le32(~ETDES0_END_RING);
|
||||
}
|
||||
|
||||
static inline void enh_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
|
||||
{
|
||||
if (unlikely(len > BUF_SIZE_4KiB)) {
|
||||
p->des1 |= cpu_to_le32((((len - BUF_SIZE_4KiB)
|
||||
<< ETDES1_BUFFER2_SIZE_SHIFT)
|
||||
& ETDES1_BUFFER2_SIZE_MASK) | (BUF_SIZE_4KiB
|
||||
& ETDES1_BUFFER1_SIZE_MASK));
|
||||
} else
|
||||
p->des1 |= cpu_to_le32((len & ETDES1_BUFFER1_SIZE_MASK));
|
||||
}
|
||||
|
||||
/* Normal descriptors */
|
||||
static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end, int bfsize)
|
||||
{
|
||||
if (bfsize >= BUF_SIZE_2KiB) {
|
||||
int bfsize2;
|
||||
|
||||
bfsize2 = min(bfsize - BUF_SIZE_2KiB + 1, BUF_SIZE_2KiB - 1);
|
||||
p->des1 |= cpu_to_le32((bfsize2 << RDES1_BUFFER2_SIZE_SHIFT)
|
||||
& RDES1_BUFFER2_SIZE_MASK);
|
||||
}
|
||||
|
||||
if (end)
|
||||
p->des1 |= cpu_to_le32(RDES1_END_RING);
|
||||
}
|
||||
|
||||
static inline void ndesc_end_tx_desc_on_ring(struct dma_desc *p, int end)
|
||||
{
|
||||
if (end)
|
||||
p->des1 |= cpu_to_le32(TDES1_END_RING);
|
||||
else
|
||||
p->des1 &= cpu_to_le32(~TDES1_END_RING);
|
||||
}
|
||||
|
||||
static inline void norm_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
|
||||
{
|
||||
if (unlikely(len > BUF_SIZE_2KiB)) {
|
||||
unsigned int buffer1 = (BUF_SIZE_2KiB - 1)
|
||||
& TDES1_BUFFER1_SIZE_MASK;
|
||||
p->des1 |= cpu_to_le32((((len - buffer1)
|
||||
<< TDES1_BUFFER2_SIZE_SHIFT)
|
||||
& TDES1_BUFFER2_SIZE_MASK) | buffer1);
|
||||
} else
|
||||
p->des1 |= cpu_to_le32((len & TDES1_BUFFER1_SIZE_MASK));
|
||||
}
|
||||
|
||||
/* Specific functions used for Chain mode */
|
||||
|
||||
/* Enhanced descriptors */
|
||||
static inline void ehn_desc_rx_set_on_chain(struct dma_desc *p)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(ERDES1_SECOND_ADDRESS_CHAINED);
|
||||
}
|
||||
|
||||
static inline void enh_desc_end_tx_desc_on_chain(struct dma_desc *p)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(ETDES0_SECOND_ADDRESS_CHAINED);
|
||||
}
|
||||
|
||||
static inline void enh_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(len & ETDES1_BUFFER1_SIZE_MASK);
|
||||
}
|
||||
|
||||
/* Normal descriptors */
|
||||
static inline void ndesc_rx_set_on_chain(struct dma_desc *p, int end)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(RDES1_SECOND_ADDRESS_CHAINED);
|
||||
}
|
||||
|
||||
static inline void ndesc_tx_set_on_chain(struct dma_desc *p)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(TDES1_SECOND_ADDRESS_CHAINED);
|
||||
}
|
||||
|
||||
static inline void norm_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(len & TDES1_BUFFER1_SIZE_MASK);
|
||||
}
|
||||
#endif /* __DESC_COM_H__ */
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
Header File to describe Normal/enhanced descriptor functions used for RING
|
||||
and CHAINED modes.
|
||||
|
||||
Copyright(C) 2011 STMicroelectronics Ltd
|
||||
|
||||
It defines all the functions used to handle the normal/enhanced
|
||||
descriptors in case of the DMA is configured to work in chained or
|
||||
in ring mode.
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DESC_COM_H__
|
||||
#define __DESC_COM_H__
|
||||
|
||||
/* Specific functions used for Ring mode */
|
||||
|
||||
/* Enhanced descriptors */
|
||||
static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end,
|
||||
int bfsize)
|
||||
{
|
||||
if (bfsize == BUF_SIZE_16KiB)
|
||||
p->des1 |= cpu_to_le32((BUF_SIZE_8KiB
|
||||
<< ERDES1_BUFFER2_SIZE_SHIFT)
|
||||
& ERDES1_BUFFER2_SIZE_MASK);
|
||||
|
||||
if (end)
|
||||
p->des1 |= cpu_to_le32(ERDES1_END_RING);
|
||||
}
|
||||
|
||||
static inline void enh_desc_end_tx_desc_on_ring(struct dma_desc *p, int end)
|
||||
{
|
||||
if (end)
|
||||
p->des0 |= cpu_to_le32(ETDES0_END_RING);
|
||||
else
|
||||
p->des0 &= cpu_to_le32(~ETDES0_END_RING);
|
||||
}
|
||||
|
||||
static inline void enh_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
|
||||
{
|
||||
if (unlikely(len > BUF_SIZE_4KiB)) {
|
||||
p->des1 |= cpu_to_le32((((len - BUF_SIZE_4KiB)
|
||||
<< ETDES1_BUFFER2_SIZE_SHIFT)
|
||||
& ETDES1_BUFFER2_SIZE_MASK) | (BUF_SIZE_4KiB
|
||||
& ETDES1_BUFFER1_SIZE_MASK));
|
||||
} else
|
||||
p->des1 |= cpu_to_le32((len & ETDES1_BUFFER1_SIZE_MASK));
|
||||
}
|
||||
|
||||
/* Normal descriptors */
|
||||
static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end, int bfsize)
|
||||
{
|
||||
if (bfsize >= BUF_SIZE_2KiB) {
|
||||
int bfsize2;
|
||||
|
||||
bfsize2 = min(bfsize - BUF_SIZE_2KiB + 1, BUF_SIZE_2KiB - 1);
|
||||
p->des1 |= cpu_to_le32((bfsize2 << RDES1_BUFFER2_SIZE_SHIFT)
|
||||
& RDES1_BUFFER2_SIZE_MASK);
|
||||
}
|
||||
|
||||
if (end)
|
||||
p->des1 |= cpu_to_le32(RDES1_END_RING);
|
||||
}
|
||||
|
||||
static inline void ndesc_end_tx_desc_on_ring(struct dma_desc *p, int end)
|
||||
{
|
||||
if (end)
|
||||
p->des1 |= cpu_to_le32(TDES1_END_RING);
|
||||
else
|
||||
p->des1 &= cpu_to_le32(~TDES1_END_RING);
|
||||
}
|
||||
|
||||
static inline void norm_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
|
||||
{
|
||||
if (unlikely(len > BUF_SIZE_2KiB)) {
|
||||
unsigned int buffer1 = (BUF_SIZE_2KiB - 1)
|
||||
& TDES1_BUFFER1_SIZE_MASK;
|
||||
p->des1 |= cpu_to_le32((((len - buffer1)
|
||||
<< TDES1_BUFFER2_SIZE_SHIFT)
|
||||
& TDES1_BUFFER2_SIZE_MASK) | buffer1);
|
||||
} else
|
||||
p->des1 |= cpu_to_le32((len & TDES1_BUFFER1_SIZE_MASK));
|
||||
}
|
||||
|
||||
/* Specific functions used for Chain mode */
|
||||
|
||||
/* Enhanced descriptors */
|
||||
static inline void ehn_desc_rx_set_on_chain(struct dma_desc *p)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(ERDES1_SECOND_ADDRESS_CHAINED);
|
||||
}
|
||||
|
||||
static inline void enh_desc_end_tx_desc_on_chain(struct dma_desc *p)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(ETDES0_SECOND_ADDRESS_CHAINED);
|
||||
}
|
||||
|
||||
static inline void enh_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(len & ETDES1_BUFFER1_SIZE_MASK);
|
||||
}
|
||||
|
||||
/* Normal descriptors */
|
||||
static inline void ndesc_rx_set_on_chain(struct dma_desc *p, int end)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(RDES1_SECOND_ADDRESS_CHAINED);
|
||||
}
|
||||
|
||||
static inline void ndesc_tx_set_on_chain(struct dma_desc *p)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(TDES1_SECOND_ADDRESS_CHAINED);
|
||||
}
|
||||
|
||||
static inline void norm_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(len & TDES1_BUFFER1_SIZE_MASK);
|
||||
}
|
||||
#endif /* __DESC_COM_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,53 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020, Intel Corporation
|
||||
* DWMAC Intel header file
|
||||
*/
|
||||
|
||||
#ifndef __DWMAC_INTEL_H__
|
||||
#define __DWMAC_INTEL_H__
|
||||
|
||||
#define POLL_DELAY_US 8
|
||||
|
||||
/* SERDES Register */
|
||||
#define SERDES_GCR 0x0 /* Global Conguration */
|
||||
#define SERDES_GSR0 0x5 /* Global Status Reg0 */
|
||||
#define SERDES_GCR0 0xb /* Global Configuration Reg0 */
|
||||
|
||||
/* SERDES defines */
|
||||
#define SERDES_PLL_CLK BIT(0) /* PLL clk valid signal */
|
||||
#define SERDES_PHY_RX_CLK BIT(1) /* PSE SGMII PHY rx clk */
|
||||
#define SERDES_RST BIT(2) /* Serdes Reset */
|
||||
#define SERDES_PWR_ST_MASK GENMASK(6, 4) /* Serdes Power state*/
|
||||
#define SERDES_RATE_MASK GENMASK(9, 8)
|
||||
#define SERDES_PCLK_MASK GENMASK(14, 12) /* PCLK rate to PHY */
|
||||
#define SERDES_LINK_MODE_MASK GENMASK(2, 1)
|
||||
#define SERDES_LINK_MODE_SHIFT 1
|
||||
#define SERDES_PWR_ST_SHIFT 4
|
||||
#define SERDES_PWR_ST_P0 0x0
|
||||
#define SERDES_PWR_ST_P3 0x3
|
||||
#define SERDES_LINK_MODE_2G5 0x3
|
||||
#define SERSED_LINK_MODE_1G 0x2
|
||||
#define SERDES_PCLK_37p5MHZ 0x0
|
||||
#define SERDES_PCLK_70MHZ 0x1
|
||||
#define SERDES_RATE_PCIE_GEN1 0x0
|
||||
#define SERDES_RATE_PCIE_GEN2 0x1
|
||||
#define SERDES_RATE_PCIE_SHIFT 8
|
||||
#define SERDES_PCLK_SHIFT 12
|
||||
|
||||
#define INTEL_MGBE_ADHOC_ADDR 0x15
|
||||
#define INTEL_MGBE_XPCS_ADDR 0x16
|
||||
|
||||
/* Cross-timestamping defines */
|
||||
#define ART_CPUID_LEAF 0x15
|
||||
#define EHL_PSE_ART_MHZ 19200000
|
||||
|
||||
/* Selection for PTP Clock Freq belongs to PSE & PCH GbE */
|
||||
#define PSE_PTP_CLK_FREQ_MASK (GMAC_GPO0 | GMAC_GPO3)
|
||||
#define PSE_PTP_CLK_FREQ_19_2MHZ (GMAC_GPO0)
|
||||
#define PSE_PTP_CLK_FREQ_200MHZ (GMAC_GPO0 | GMAC_GPO3)
|
||||
#define PSE_PTP_CLK_FREQ_256MHZ (0)
|
||||
#define PCH_PTP_CLK_FREQ_MASK (GMAC_GPO0)
|
||||
#define PCH_PTP_CLK_FREQ_19_2MHZ (GMAC_GPO0)
|
||||
#define PCH_PTP_CLK_FREQ_200MHZ (0)
|
||||
|
||||
#endif /* __DWMAC_INTEL_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,53 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020, Intel Corporation
|
||||
* DWMAC Intel header file
|
||||
*/
|
||||
|
||||
#ifndef __DWMAC_INTEL_H__
|
||||
#define __DWMAC_INTEL_H__
|
||||
|
||||
#define POLL_DELAY_US 8
|
||||
|
||||
/* SERDES Register */
|
||||
#define SERDES_GCR 0x0 /* Global Conguration */
|
||||
#define SERDES_GSR0 0x5 /* Global Status Reg0 */
|
||||
#define SERDES_GCR0 0xb /* Global Configuration Reg0 */
|
||||
|
||||
/* SERDES defines */
|
||||
#define SERDES_PLL_CLK BIT(0) /* PLL clk valid signal */
|
||||
#define SERDES_PHY_RX_CLK BIT(1) /* PSE SGMII PHY rx clk */
|
||||
#define SERDES_RST BIT(2) /* Serdes Reset */
|
||||
#define SERDES_PWR_ST_MASK GENMASK(6, 4) /* Serdes Power state*/
|
||||
#define SERDES_RATE_MASK GENMASK(9, 8)
|
||||
#define SERDES_PCLK_MASK GENMASK(14, 12) /* PCLK rate to PHY */
|
||||
#define SERDES_LINK_MODE_MASK GENMASK(2, 1)
|
||||
#define SERDES_LINK_MODE_SHIFT 1
|
||||
#define SERDES_PWR_ST_SHIFT 4
|
||||
#define SERDES_PWR_ST_P0 0x0
|
||||
#define SERDES_PWR_ST_P3 0x3
|
||||
#define SERDES_LINK_MODE_2G5 0x3
|
||||
#define SERSED_LINK_MODE_1G 0x2
|
||||
#define SERDES_PCLK_37p5MHZ 0x0
|
||||
#define SERDES_PCLK_70MHZ 0x1
|
||||
#define SERDES_RATE_PCIE_GEN1 0x0
|
||||
#define SERDES_RATE_PCIE_GEN2 0x1
|
||||
#define SERDES_RATE_PCIE_SHIFT 8
|
||||
#define SERDES_PCLK_SHIFT 12
|
||||
|
||||
#define INTEL_MGBE_ADHOC_ADDR 0x15
|
||||
#define INTEL_MGBE_XPCS_ADDR 0x16
|
||||
|
||||
/* Cross-timestamping defines */
|
||||
#define ART_CPUID_LEAF 0x15
|
||||
#define EHL_PSE_ART_MHZ 19200000
|
||||
|
||||
/* Selection for PTP Clock Freq belongs to PSE & PCH GbE */
|
||||
#define PSE_PTP_CLK_FREQ_MASK (GMAC_GPO0 | GMAC_GPO3)
|
||||
#define PSE_PTP_CLK_FREQ_19_2MHZ (GMAC_GPO0)
|
||||
#define PSE_PTP_CLK_FREQ_200MHZ (GMAC_GPO0 | GMAC_GPO3)
|
||||
#define PSE_PTP_CLK_FREQ_256MHZ (0)
|
||||
#define PCH_PTP_CLK_FREQ_MASK (GMAC_GPO0)
|
||||
#define PCH_PTP_CLK_FREQ_19_2MHZ (GMAC_GPO0)
|
||||
#define PCH_PTP_CLK_FREQ_200MHZ (0)
|
||||
|
||||
#endif /* __DWMAC_INTEL_H__ */
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
MAC 10/100 Header File
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DWMAC100_H__
|
||||
#define __DWMAC100_H__
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include "common-6.12-ethercat.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* MAC BLOCK defines
|
||||
*---------------------------------------------------------------------------*/
|
||||
/* MAC CSR offset */
|
||||
#define MAC_CONTROL 0x00000000 /* MAC Control */
|
||||
#define MAC_ADDR_HIGH 0x00000004 /* MAC Address High */
|
||||
#define MAC_ADDR_LOW 0x00000008 /* MAC Address Low */
|
||||
#define MAC_HASH_HIGH 0x0000000c /* Multicast Hash Table High */
|
||||
#define MAC_HASH_LOW 0x00000010 /* Multicast Hash Table Low */
|
||||
#define MAC_MII_ADDR 0x00000014 /* MII Address */
|
||||
#define MAC_MII_DATA 0x00000018 /* MII Data */
|
||||
#define MAC_FLOW_CTRL 0x0000001c /* Flow Control */
|
||||
#define MAC_VLAN1 0x00000020 /* VLAN1 Tag */
|
||||
#define MAC_VLAN2 0x00000024 /* VLAN2 Tag */
|
||||
|
||||
/* MAC CTRL defines */
|
||||
#define MAC_CONTROL_RA 0x80000000 /* Receive All Mode */
|
||||
#define MAC_CONTROL_BLE 0x40000000 /* Endian Mode */
|
||||
#define MAC_CONTROL_HBD 0x10000000 /* Heartbeat Disable */
|
||||
#define MAC_CONTROL_PS 0x08000000 /* Port Select */
|
||||
#define MAC_CONTROL_DRO 0x00800000 /* Disable Receive Own */
|
||||
#define MAC_CONTROL_EXT_LOOPBACK 0x00400000 /* Reserved (ext loopback?) */
|
||||
#define MAC_CONTROL_OM 0x00200000 /* Loopback Operating Mode */
|
||||
#define MAC_CONTROL_F 0x00100000 /* Full Duplex Mode */
|
||||
#define MAC_CONTROL_PM 0x00080000 /* Pass All Multicast */
|
||||
#define MAC_CONTROL_PR 0x00040000 /* Promiscuous Mode */
|
||||
#define MAC_CONTROL_IF 0x00020000 /* Inverse Filtering */
|
||||
#define MAC_CONTROL_PB 0x00010000 /* Pass Bad Frames */
|
||||
#define MAC_CONTROL_HO 0x00008000 /* Hash Only Filtering Mode */
|
||||
#define MAC_CONTROL_HP 0x00002000 /* Hash/Perfect Filtering Mode */
|
||||
#define MAC_CONTROL_LCC 0x00001000 /* Late Collision Control */
|
||||
#define MAC_CONTROL_DBF 0x00000800 /* Disable Broadcast Frames */
|
||||
#define MAC_CONTROL_DRTY 0x00000400 /* Disable Retry */
|
||||
#define MAC_CONTROL_ASTP 0x00000100 /* Automatic Pad Stripping */
|
||||
#define MAC_CONTROL_BOLMT_10 0x00000000 /* Back Off Limit 10 */
|
||||
#define MAC_CONTROL_BOLMT_8 0x00000040 /* Back Off Limit 8 */
|
||||
#define MAC_CONTROL_BOLMT_4 0x00000080 /* Back Off Limit 4 */
|
||||
#define MAC_CONTROL_BOLMT_1 0x000000c0 /* Back Off Limit 1 */
|
||||
#define MAC_CONTROL_DC 0x00000020 /* Deferral Check */
|
||||
#define MAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
|
||||
#define MAC_CONTROL_RE 0x00000004 /* Receiver Enable */
|
||||
|
||||
#define MAC_CORE_INIT (MAC_CONTROL_HBD)
|
||||
|
||||
/* MAC FLOW CTRL defines */
|
||||
#define MAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */
|
||||
#define MAC_FLOW_CTRL_PT_SHIFT 16
|
||||
#define MAC_FLOW_CTRL_PASS 0x00000004 /* Pass Control Frames */
|
||||
#define MAC_FLOW_CTRL_ENABLE 0x00000002 /* Flow Control Enable */
|
||||
#define MAC_FLOW_CTRL_PAUSE 0x00000001 /* Flow Control Busy ... */
|
||||
|
||||
/* MII ADDR defines */
|
||||
#define MAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
|
||||
#define MAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* DMA BLOCK defines
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
/* DMA Bus Mode register defines */
|
||||
#define DMA_BUS_MODE_DBO 0x00100000 /* Descriptor Byte Ordering */
|
||||
#define DMA_BUS_MODE_BLE 0x00000080 /* Big Endian/Little Endian */
|
||||
#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_PBL_SHIFT 8
|
||||
#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
|
||||
#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
|
||||
#define DMA_BUS_MODE_BAR_BUS 0x00000002 /* Bar-Bus Arbitration */
|
||||
#define DMA_BUS_MODE_DEFAULT 0x00000000
|
||||
|
||||
/* DMA Control register defines */
|
||||
#define DMA_CONTROL_SF 0x00200000 /* Store And Forward */
|
||||
|
||||
/* Transmit Threshold Control */
|
||||
enum ttc_control {
|
||||
DMA_CONTROL_TTC_DEFAULT = 0x00000000, /* Threshold is 32 DWORDS */
|
||||
DMA_CONTROL_TTC_64 = 0x00004000, /* Threshold is 64 DWORDS */
|
||||
DMA_CONTROL_TTC_128 = 0x00008000, /* Threshold is 128 DWORDS */
|
||||
DMA_CONTROL_TTC_256 = 0x0000c000, /* Threshold is 256 DWORDS */
|
||||
DMA_CONTROL_TTC_18 = 0x00400000, /* Threshold is 18 DWORDS */
|
||||
DMA_CONTROL_TTC_24 = 0x00404000, /* Threshold is 24 DWORDS */
|
||||
DMA_CONTROL_TTC_32 = 0x00408000, /* Threshold is 32 DWORDS */
|
||||
DMA_CONTROL_TTC_40 = 0x0040c000, /* Threshold is 40 DWORDS */
|
||||
DMA_CONTROL_SE = 0x00000008, /* Stop On Empty */
|
||||
DMA_CONTROL_OSF = 0x00000004, /* Operate On 2nd Frame */
|
||||
};
|
||||
|
||||
/* STMAC110 DMA Missed Frame Counter register defines */
|
||||
#define DMA_MISSED_FRAME_OVE 0x10000000 /* FIFO Overflow Overflow */
|
||||
#define DMA_MISSED_FRAME_OVE_CNTR 0x0ffe0000 /* Overflow Frame Counter */
|
||||
#define DMA_MISSED_FRAME_OVE_M 0x00010000 /* Missed Frame Overflow */
|
||||
#define DMA_MISSED_FRAME_M_CNTR 0x0000ffff /* Missed Frame Couinter */
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac100_dma_ops;
|
||||
|
||||
#endif /* __DWMAC100_H__ */
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
MAC 10/100 Header File
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DWMAC100_H__
|
||||
#define __DWMAC100_H__
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include "common.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* MAC BLOCK defines
|
||||
*---------------------------------------------------------------------------*/
|
||||
/* MAC CSR offset */
|
||||
#define MAC_CONTROL 0x00000000 /* MAC Control */
|
||||
#define MAC_ADDR_HIGH 0x00000004 /* MAC Address High */
|
||||
#define MAC_ADDR_LOW 0x00000008 /* MAC Address Low */
|
||||
#define MAC_HASH_HIGH 0x0000000c /* Multicast Hash Table High */
|
||||
#define MAC_HASH_LOW 0x00000010 /* Multicast Hash Table Low */
|
||||
#define MAC_MII_ADDR 0x00000014 /* MII Address */
|
||||
#define MAC_MII_DATA 0x00000018 /* MII Data */
|
||||
#define MAC_FLOW_CTRL 0x0000001c /* Flow Control */
|
||||
#define MAC_VLAN1 0x00000020 /* VLAN1 Tag */
|
||||
#define MAC_VLAN2 0x00000024 /* VLAN2 Tag */
|
||||
|
||||
/* MAC CTRL defines */
|
||||
#define MAC_CONTROL_RA 0x80000000 /* Receive All Mode */
|
||||
#define MAC_CONTROL_BLE 0x40000000 /* Endian Mode */
|
||||
#define MAC_CONTROL_HBD 0x10000000 /* Heartbeat Disable */
|
||||
#define MAC_CONTROL_PS 0x08000000 /* Port Select */
|
||||
#define MAC_CONTROL_DRO 0x00800000 /* Disable Receive Own */
|
||||
#define MAC_CONTROL_EXT_LOOPBACK 0x00400000 /* Reserved (ext loopback?) */
|
||||
#define MAC_CONTROL_OM 0x00200000 /* Loopback Operating Mode */
|
||||
#define MAC_CONTROL_F 0x00100000 /* Full Duplex Mode */
|
||||
#define MAC_CONTROL_PM 0x00080000 /* Pass All Multicast */
|
||||
#define MAC_CONTROL_PR 0x00040000 /* Promiscuous Mode */
|
||||
#define MAC_CONTROL_IF 0x00020000 /* Inverse Filtering */
|
||||
#define MAC_CONTROL_PB 0x00010000 /* Pass Bad Frames */
|
||||
#define MAC_CONTROL_HO 0x00008000 /* Hash Only Filtering Mode */
|
||||
#define MAC_CONTROL_HP 0x00002000 /* Hash/Perfect Filtering Mode */
|
||||
#define MAC_CONTROL_LCC 0x00001000 /* Late Collision Control */
|
||||
#define MAC_CONTROL_DBF 0x00000800 /* Disable Broadcast Frames */
|
||||
#define MAC_CONTROL_DRTY 0x00000400 /* Disable Retry */
|
||||
#define MAC_CONTROL_ASTP 0x00000100 /* Automatic Pad Stripping */
|
||||
#define MAC_CONTROL_BOLMT_10 0x00000000 /* Back Off Limit 10 */
|
||||
#define MAC_CONTROL_BOLMT_8 0x00000040 /* Back Off Limit 8 */
|
||||
#define MAC_CONTROL_BOLMT_4 0x00000080 /* Back Off Limit 4 */
|
||||
#define MAC_CONTROL_BOLMT_1 0x000000c0 /* Back Off Limit 1 */
|
||||
#define MAC_CONTROL_DC 0x00000020 /* Deferral Check */
|
||||
#define MAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
|
||||
#define MAC_CONTROL_RE 0x00000004 /* Receiver Enable */
|
||||
|
||||
#define MAC_CORE_INIT (MAC_CONTROL_HBD)
|
||||
|
||||
/* MAC FLOW CTRL defines */
|
||||
#define MAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */
|
||||
#define MAC_FLOW_CTRL_PT_SHIFT 16
|
||||
#define MAC_FLOW_CTRL_PASS 0x00000004 /* Pass Control Frames */
|
||||
#define MAC_FLOW_CTRL_ENABLE 0x00000002 /* Flow Control Enable */
|
||||
#define MAC_FLOW_CTRL_PAUSE 0x00000001 /* Flow Control Busy ... */
|
||||
|
||||
/* MII ADDR defines */
|
||||
#define MAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
|
||||
#define MAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* DMA BLOCK defines
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
/* DMA Bus Mode register defines */
|
||||
#define DMA_BUS_MODE_DBO 0x00100000 /* Descriptor Byte Ordering */
|
||||
#define DMA_BUS_MODE_BLE 0x00000080 /* Big Endian/Little Endian */
|
||||
#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_PBL_SHIFT 8
|
||||
#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
|
||||
#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
|
||||
#define DMA_BUS_MODE_BAR_BUS 0x00000002 /* Bar-Bus Arbitration */
|
||||
#define DMA_BUS_MODE_DEFAULT 0x00000000
|
||||
|
||||
/* DMA Control register defines */
|
||||
#define DMA_CONTROL_SF 0x00200000 /* Store And Forward */
|
||||
|
||||
/* Transmit Threshold Control */
|
||||
enum ttc_control {
|
||||
DMA_CONTROL_TTC_DEFAULT = 0x00000000, /* Threshold is 32 DWORDS */
|
||||
DMA_CONTROL_TTC_64 = 0x00004000, /* Threshold is 64 DWORDS */
|
||||
DMA_CONTROL_TTC_128 = 0x00008000, /* Threshold is 128 DWORDS */
|
||||
DMA_CONTROL_TTC_256 = 0x0000c000, /* Threshold is 256 DWORDS */
|
||||
DMA_CONTROL_TTC_18 = 0x00400000, /* Threshold is 18 DWORDS */
|
||||
DMA_CONTROL_TTC_24 = 0x00404000, /* Threshold is 24 DWORDS */
|
||||
DMA_CONTROL_TTC_32 = 0x00408000, /* Threshold is 32 DWORDS */
|
||||
DMA_CONTROL_TTC_40 = 0x0040c000, /* Threshold is 40 DWORDS */
|
||||
DMA_CONTROL_SE = 0x00000008, /* Stop On Empty */
|
||||
DMA_CONTROL_OSF = 0x00000004, /* Operate On 2nd Frame */
|
||||
};
|
||||
|
||||
/* STMAC110 DMA Missed Frame Counter register defines */
|
||||
#define DMA_MISSED_FRAME_OVE 0x10000000 /* FIFO Overflow Overflow */
|
||||
#define DMA_MISSED_FRAME_OVE_CNTR 0x0ffe0000 /* Overflow Frame Counter */
|
||||
#define DMA_MISSED_FRAME_OVE_M 0x00010000 /* Missed Frame Overflow */
|
||||
#define DMA_MISSED_FRAME_M_CNTR 0x0000ffff /* Missed Frame Couinter */
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac100_dma_ops;
|
||||
|
||||
#endif /* __DWMAC100_H__ */
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
#ifndef __DWMAC1000_H__
|
||||
#define __DWMAC1000_H__
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include "common-6.12-ethercat.h"
|
||||
|
||||
#define GMAC_CONTROL 0x00000000 /* Configuration */
|
||||
#define GMAC_FRAME_FILTER 0x00000004 /* Frame Filter */
|
||||
#define GMAC_HASH_HIGH 0x00000008 /* Multicast Hash Table High */
|
||||
#define GMAC_HASH_LOW 0x0000000c /* Multicast Hash Table Low */
|
||||
#define GMAC_MII_ADDR 0x00000010 /* MII Address */
|
||||
#define GMAC_MII_DATA 0x00000014 /* MII Data */
|
||||
#define GMAC_FLOW_CTRL 0x00000018 /* Flow Control */
|
||||
#define GMAC_VLAN_TAG 0x0000001c /* VLAN Tag */
|
||||
#define GMAC_DEBUG 0x00000024 /* GMAC debug register */
|
||||
#define GMAC_WAKEUP_FILTER 0x00000028 /* Wake-up Frame Filter */
|
||||
|
||||
#define GMAC_INT_STATUS 0x00000038 /* interrupt status register */
|
||||
#define GMAC_INT_STATUS_PMT BIT(3)
|
||||
#define GMAC_INT_STATUS_MMCIS BIT(4)
|
||||
#define GMAC_INT_STATUS_MMCRIS BIT(5)
|
||||
#define GMAC_INT_STATUS_MMCTIS BIT(6)
|
||||
#define GMAC_INT_STATUS_MMCCSUM BIT(7)
|
||||
#define GMAC_INT_STATUS_TSTAMP BIT(9)
|
||||
#define GMAC_INT_STATUS_LPIIS BIT(10)
|
||||
|
||||
/* interrupt mask register */
|
||||
#define GMAC_INT_MASK 0x0000003c
|
||||
#define GMAC_INT_DISABLE_RGMII BIT(0)
|
||||
#define GMAC_INT_DISABLE_PCSLINK BIT(1)
|
||||
#define GMAC_INT_DISABLE_PCSAN BIT(2)
|
||||
#define GMAC_INT_DISABLE_PMT BIT(3)
|
||||
#define GMAC_INT_DISABLE_TIMESTAMP BIT(9)
|
||||
#define GMAC_INT_DISABLE_PCS (GMAC_INT_DISABLE_RGMII | \
|
||||
GMAC_INT_DISABLE_PCSLINK | \
|
||||
GMAC_INT_DISABLE_PCSAN)
|
||||
#define GMAC_INT_DEFAULT_MASK (GMAC_INT_DISABLE_TIMESTAMP | \
|
||||
GMAC_INT_DISABLE_PCS)
|
||||
|
||||
/* PMT Control and Status */
|
||||
#define GMAC_PMT 0x0000002c
|
||||
enum power_event {
|
||||
pointer_reset = 0x80000000,
|
||||
global_unicast = 0x00000200,
|
||||
wake_up_rx_frame = 0x00000040,
|
||||
magic_frame = 0x00000020,
|
||||
wake_up_frame_en = 0x00000004,
|
||||
magic_pkt_en = 0x00000002,
|
||||
power_down = 0x00000001,
|
||||
};
|
||||
|
||||
/* Energy Efficient Ethernet (EEE)
|
||||
*
|
||||
* LPI status, timer and control register offset
|
||||
*/
|
||||
#define LPI_CTRL_STATUS 0x0030
|
||||
#define LPI_TIMER_CTRL 0x0034
|
||||
|
||||
/* LPI control and status defines */
|
||||
#define LPI_CTRL_STATUS_LPITXA 0x00080000 /* Enable LPI TX Automate */
|
||||
#define LPI_CTRL_STATUS_PLSEN 0x00040000 /* Enable PHY Link Status */
|
||||
#define LPI_CTRL_STATUS_PLS 0x00020000 /* PHY Link Status */
|
||||
#define LPI_CTRL_STATUS_LPIEN 0x00010000 /* LPI Enable */
|
||||
#define LPI_CTRL_STATUS_RLPIST 0x00000200 /* Receive LPI state */
|
||||
#define LPI_CTRL_STATUS_TLPIST 0x00000100 /* Transmit LPI state */
|
||||
#define LPI_CTRL_STATUS_RLPIEX 0x00000008 /* Receive LPI Exit */
|
||||
#define LPI_CTRL_STATUS_RLPIEN 0x00000004 /* Receive LPI Entry */
|
||||
#define LPI_CTRL_STATUS_TLPIEX 0x00000002 /* Transmit LPI Exit */
|
||||
#define LPI_CTRL_STATUS_TLPIEN 0x00000001 /* Transmit LPI Entry */
|
||||
|
||||
/* GMAC HW ADDR regs */
|
||||
#define GMAC_ADDR_HIGH(reg) ((reg > 15) ? 0x00000800 + (reg - 16) * 8 : \
|
||||
0x00000040 + (reg * 8))
|
||||
#define GMAC_ADDR_LOW(reg) ((reg > 15) ? 0x00000804 + (reg - 16) * 8 : \
|
||||
0x00000044 + (reg * 8))
|
||||
#define GMAC_MAX_PERFECT_ADDRESSES 1
|
||||
|
||||
#define GMAC_PCS_BASE 0x000000c0 /* PCS register base */
|
||||
#define GMAC_RGSMIIIS 0x000000d8 /* RGMII/SMII status */
|
||||
|
||||
/* SGMII/RGMII status register */
|
||||
#define GMAC_RGSMIIIS_LNKMODE BIT(0)
|
||||
#define GMAC_RGSMIIIS_SPEED GENMASK(2, 1)
|
||||
#define GMAC_RGSMIIIS_SPEED_SHIFT 1
|
||||
#define GMAC_RGSMIIIS_LNKSTS BIT(3)
|
||||
#define GMAC_RGSMIIIS_JABTO BIT(4)
|
||||
#define GMAC_RGSMIIIS_FALSECARDET BIT(5)
|
||||
#define GMAC_RGSMIIIS_SMIDRXS BIT(16)
|
||||
/* LNKMOD */
|
||||
#define GMAC_RGSMIIIS_LNKMOD_MASK 0x1
|
||||
/* LNKSPEED */
|
||||
#define GMAC_RGSMIIIS_SPEED_125 0x2
|
||||
#define GMAC_RGSMIIIS_SPEED_25 0x1
|
||||
#define GMAC_RGSMIIIS_SPEED_2_5 0x0
|
||||
|
||||
/* GMAC Configuration defines */
|
||||
#define GMAC_CONTROL_2K 0x08000000 /* IEEE 802.3as 2K packets */
|
||||
#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */
|
||||
#define GMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on receive */
|
||||
#define GMAC_CONTROL_JD 0x00400000 /* Jabber disable */
|
||||
#define GMAC_CONTROL_BE 0x00200000 /* Frame Burst Enable */
|
||||
#define GMAC_CONTROL_JE 0x00100000 /* Jumbo frame */
|
||||
enum inter_frame_gap {
|
||||
GMAC_CONTROL_IFG_88 = 0x00040000,
|
||||
GMAC_CONTROL_IFG_80 = 0x00020000,
|
||||
GMAC_CONTROL_IFG_40 = 0x000e0000,
|
||||
};
|
||||
#define GMAC_CONTROL_DCRS 0x00010000 /* Disable carrier sense */
|
||||
#define GMAC_CONTROL_PS 0x00008000 /* Port Select 0:GMI 1:MII */
|
||||
#define GMAC_CONTROL_FES 0x00004000 /* Speed 0:10 1:100 */
|
||||
#define GMAC_CONTROL_DO 0x00002000 /* Disable Rx Own */
|
||||
#define GMAC_CONTROL_LM 0x00001000 /* Loop-back mode */
|
||||
#define GMAC_CONTROL_DM 0x00000800 /* Duplex Mode */
|
||||
#define GMAC_CONTROL_IPC 0x00000400 /* Checksum Offload */
|
||||
#define GMAC_CONTROL_DR 0x00000200 /* Disable Retry */
|
||||
#define GMAC_CONTROL_LUD 0x00000100 /* Link up/down */
|
||||
#define GMAC_CONTROL_ACS 0x00000080 /* Auto Pad/FCS Stripping */
|
||||
#define GMAC_CONTROL_DC 0x00000010 /* Deferral Check */
|
||||
#define GMAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
|
||||
#define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */
|
||||
|
||||
#define GMAC_CORE_INIT (GMAC_CONTROL_JD | GMAC_CONTROL_PS | \
|
||||
GMAC_CONTROL_BE | GMAC_CONTROL_DCRS)
|
||||
|
||||
/* GMAC Frame Filter defines */
|
||||
#define GMAC_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */
|
||||
#define GMAC_FRAME_FILTER_HUC 0x00000002 /* Hash Unicast */
|
||||
#define GMAC_FRAME_FILTER_HMC 0x00000004 /* Hash Multicast */
|
||||
#define GMAC_FRAME_FILTER_DAIF 0x00000008 /* DA Inverse Filtering */
|
||||
#define GMAC_FRAME_FILTER_PM 0x00000010 /* Pass all multicast */
|
||||
#define GMAC_FRAME_FILTER_DBF 0x00000020 /* Disable Broadcast frames */
|
||||
#define GMAC_FRAME_FILTER_PCF 0x00000080 /* Pass Control frames */
|
||||
#define GMAC_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */
|
||||
#define GMAC_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */
|
||||
#define GMAC_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */
|
||||
#define GMAC_FRAME_FILTER_RA 0x80000000 /* Receive all mode */
|
||||
/* GMII ADDR defines */
|
||||
#define GMAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
|
||||
#define GMAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */
|
||||
/* GMAC FLOW CTRL defines */
|
||||
#define GMAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */
|
||||
#define GMAC_FLOW_CTRL_PT_SHIFT 16
|
||||
#define GMAC_FLOW_CTRL_UP 0x00000008 /* Unicast pause frame enable */
|
||||
#define GMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */
|
||||
#define GMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */
|
||||
#define GMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */
|
||||
|
||||
/* DEBUG Register defines */
|
||||
/* MTL TxStatus FIFO */
|
||||
#define GMAC_DEBUG_TXSTSFSTS BIT(25) /* MTL TxStatus FIFO Full Status */
|
||||
#define GMAC_DEBUG_TXFSTS BIT(24) /* MTL Tx FIFO Not Empty Status */
|
||||
#define GMAC_DEBUG_TWCSTS BIT(22) /* MTL Tx FIFO Write Controller */
|
||||
/* MTL Tx FIFO Read Controller Status */
|
||||
#define GMAC_DEBUG_TRCSTS_MASK GENMASK(21, 20)
|
||||
#define GMAC_DEBUG_TRCSTS_SHIFT 20
|
||||
#define GMAC_DEBUG_TRCSTS_IDLE 0
|
||||
#define GMAC_DEBUG_TRCSTS_READ 1
|
||||
#define GMAC_DEBUG_TRCSTS_TXW 2
|
||||
#define GMAC_DEBUG_TRCSTS_WRITE 3
|
||||
#define GMAC_DEBUG_TXPAUSED BIT(19) /* MAC Transmitter in PAUSE */
|
||||
/* MAC Transmit Frame Controller Status */
|
||||
#define GMAC_DEBUG_TFCSTS_MASK GENMASK(18, 17)
|
||||
#define GMAC_DEBUG_TFCSTS_SHIFT 17
|
||||
#define GMAC_DEBUG_TFCSTS_IDLE 0
|
||||
#define GMAC_DEBUG_TFCSTS_WAIT 1
|
||||
#define GMAC_DEBUG_TFCSTS_GEN_PAUSE 2
|
||||
#define GMAC_DEBUG_TFCSTS_XFER 3
|
||||
/* MAC GMII or MII Transmit Protocol Engine Status */
|
||||
#define GMAC_DEBUG_TPESTS BIT(16)
|
||||
#define GMAC_DEBUG_RXFSTS_MASK GENMASK(9, 8) /* MTL Rx FIFO Fill-level */
|
||||
#define GMAC_DEBUG_RXFSTS_SHIFT 8
|
||||
#define GMAC_DEBUG_RXFSTS_EMPTY 0
|
||||
#define GMAC_DEBUG_RXFSTS_BT 1
|
||||
#define GMAC_DEBUG_RXFSTS_AT 2
|
||||
#define GMAC_DEBUG_RXFSTS_FULL 3
|
||||
#define GMAC_DEBUG_RRCSTS_MASK GENMASK(6, 5) /* MTL Rx FIFO Read Controller */
|
||||
#define GMAC_DEBUG_RRCSTS_SHIFT 5
|
||||
#define GMAC_DEBUG_RRCSTS_IDLE 0
|
||||
#define GMAC_DEBUG_RRCSTS_RDATA 1
|
||||
#define GMAC_DEBUG_RRCSTS_RSTAT 2
|
||||
#define GMAC_DEBUG_RRCSTS_FLUSH 3
|
||||
#define GMAC_DEBUG_RWCSTS BIT(4) /* MTL Rx FIFO Write Controller Active */
|
||||
/* MAC Receive Frame Controller FIFO Status */
|
||||
#define GMAC_DEBUG_RFCFCSTS_MASK GENMASK(2, 1)
|
||||
#define GMAC_DEBUG_RFCFCSTS_SHIFT 1
|
||||
/* MAC GMII or MII Receive Protocol Engine Status */
|
||||
#define GMAC_DEBUG_RPESTS BIT(0)
|
||||
|
||||
/*--- DMA BLOCK defines ---*/
|
||||
/* DMA Bus Mode register defines */
|
||||
#define DMA_BUS_MODE_DA 0x00000002 /* Arbitration scheme */
|
||||
#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
|
||||
#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
|
||||
/* Programmable burst length (passed thorugh platform)*/
|
||||
#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_PBL_SHIFT 8
|
||||
#define DMA_BUS_MODE_ATDS 0x00000080 /* Alternate Descriptor Size */
|
||||
|
||||
enum rx_tx_priority_ratio {
|
||||
double_ratio = 0x00004000, /* 2:1 */
|
||||
triple_ratio = 0x00008000, /* 3:1 */
|
||||
quadruple_ratio = 0x0000c000, /* 4:1 */
|
||||
};
|
||||
|
||||
#define DMA_BUS_MODE_FB 0x00010000 /* Fixed burst */
|
||||
#define DMA_BUS_MODE_MB 0x04000000 /* Mixed burst */
|
||||
#define DMA_BUS_MODE_RPBL_MASK 0x007e0000 /* Rx-Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_RPBL_SHIFT 17
|
||||
#define DMA_BUS_MODE_USP 0x00800000
|
||||
#define DMA_BUS_MODE_MAXPBL 0x01000000
|
||||
#define DMA_BUS_MODE_AAL 0x02000000
|
||||
|
||||
/* DMA CRS Control and Status Register Mapping */
|
||||
#define DMA_HOST_TX_DESC 0x00001048 /* Current Host Tx descriptor */
|
||||
#define DMA_HOST_RX_DESC 0x0000104c /* Current Host Rx descriptor */
|
||||
/* DMA Bus Mode register defines */
|
||||
#define DMA_BUS_PR_RATIO_MASK 0x0000c000 /* Rx/Tx priority ratio */
|
||||
#define DMA_BUS_PR_RATIO_SHIFT 14
|
||||
#define DMA_BUS_FB 0x00010000 /* Fixed Burst */
|
||||
|
||||
/* DMA operation mode defines (start/stop tx/rx are placed in common header)*/
|
||||
/* Disable Drop TCP/IP csum error */
|
||||
#define DMA_CONTROL_DT 0x04000000
|
||||
#define DMA_CONTROL_RSF 0x02000000 /* Receive Store and Forward */
|
||||
#define DMA_CONTROL_DFF 0x01000000 /* Disaable flushing */
|
||||
/* Threshold for Activating the FC */
|
||||
enum rfa {
|
||||
act_full_minus_1 = 0x00800000,
|
||||
act_full_minus_2 = 0x00800200,
|
||||
act_full_minus_3 = 0x00800400,
|
||||
act_full_minus_4 = 0x00800600,
|
||||
};
|
||||
/* Threshold for Deactivating the FC */
|
||||
enum rfd {
|
||||
deac_full_minus_1 = 0x00400000,
|
||||
deac_full_minus_2 = 0x00400800,
|
||||
deac_full_minus_3 = 0x00401000,
|
||||
deac_full_minus_4 = 0x00401800,
|
||||
};
|
||||
#define DMA_CONTROL_TSF 0x00200000 /* Transmit Store and Forward */
|
||||
|
||||
enum ttc_control {
|
||||
DMA_CONTROL_TTC_64 = 0x00000000,
|
||||
DMA_CONTROL_TTC_128 = 0x00004000,
|
||||
DMA_CONTROL_TTC_192 = 0x00008000,
|
||||
DMA_CONTROL_TTC_256 = 0x0000c000,
|
||||
DMA_CONTROL_TTC_40 = 0x00010000,
|
||||
DMA_CONTROL_TTC_32 = 0x00014000,
|
||||
DMA_CONTROL_TTC_24 = 0x00018000,
|
||||
DMA_CONTROL_TTC_16 = 0x0001c000,
|
||||
};
|
||||
#define DMA_CONTROL_TC_TX_MASK 0xfffe3fff
|
||||
|
||||
#define DMA_CONTROL_EFC 0x00000100
|
||||
#define DMA_CONTROL_FEF 0x00000080
|
||||
#define DMA_CONTROL_FUF 0x00000040
|
||||
|
||||
/* Receive flow control activation field
|
||||
* RFA field in DMA control register, bits 23,10:9
|
||||
*/
|
||||
#define DMA_CONTROL_RFA_MASK 0x00800600
|
||||
|
||||
/* Receive flow control deactivation field
|
||||
* RFD field in DMA control register, bits 22,12:11
|
||||
*/
|
||||
#define DMA_CONTROL_RFD_MASK 0x00401800
|
||||
|
||||
/* RFD and RFA fields are encoded as follows
|
||||
*
|
||||
* Bit Field
|
||||
* 0,00 - Full minus 1KB (only valid when rxfifo >= 4KB and EFC enabled)
|
||||
* 0,01 - Full minus 2KB (only valid when rxfifo >= 4KB and EFC enabled)
|
||||
* 0,10 - Full minus 3KB (only valid when rxfifo >= 4KB and EFC enabled)
|
||||
* 0,11 - Full minus 4KB (only valid when rxfifo > 4KB and EFC enabled)
|
||||
* 1,00 - Full minus 5KB (only valid when rxfifo > 8KB and EFC enabled)
|
||||
* 1,01 - Full minus 6KB (only valid when rxfifo > 8KB and EFC enabled)
|
||||
* 1,10 - Full minus 7KB (only valid when rxfifo > 8KB and EFC enabled)
|
||||
* 1,11 - Reserved
|
||||
*
|
||||
* RFD should always be > RFA for a given FIFO size. RFD == RFA may work,
|
||||
* but packet throughput performance may not be as expected.
|
||||
*
|
||||
* Be sure that bit 3 in GMAC Register 6 is set for Unicast Pause frame
|
||||
* detection (IEEE Specification Requirement, Annex 31B, 31B.1, Pause
|
||||
* Description).
|
||||
*
|
||||
* Be sure that DZPA (bit 7 in Flow Control Register, GMAC Register 6),
|
||||
* is set to 0. This allows pause frames with a quanta of 0 to be sent
|
||||
* as an XOFF message to the link peer.
|
||||
*/
|
||||
|
||||
#define RFA_FULL_MINUS_1K 0x00000000
|
||||
#define RFA_FULL_MINUS_2K 0x00000200
|
||||
#define RFA_FULL_MINUS_3K 0x00000400
|
||||
#define RFA_FULL_MINUS_4K 0x00000600
|
||||
#define RFA_FULL_MINUS_5K 0x00800000
|
||||
#define RFA_FULL_MINUS_6K 0x00800200
|
||||
#define RFA_FULL_MINUS_7K 0x00800400
|
||||
|
||||
#define RFD_FULL_MINUS_1K 0x00000000
|
||||
#define RFD_FULL_MINUS_2K 0x00000800
|
||||
#define RFD_FULL_MINUS_3K 0x00001000
|
||||
#define RFD_FULL_MINUS_4K 0x00001800
|
||||
#define RFD_FULL_MINUS_5K 0x00400000
|
||||
#define RFD_FULL_MINUS_6K 0x00400800
|
||||
#define RFD_FULL_MINUS_7K 0x00401000
|
||||
|
||||
enum rtc_control {
|
||||
DMA_CONTROL_RTC_64 = 0x00000000,
|
||||
DMA_CONTROL_RTC_32 = 0x00000008,
|
||||
DMA_CONTROL_RTC_96 = 0x00000010,
|
||||
DMA_CONTROL_RTC_128 = 0x00000018,
|
||||
};
|
||||
#define DMA_CONTROL_TC_RX_MASK 0xffffffe7
|
||||
|
||||
#define DMA_CONTROL_OSF 0x00000004 /* Operate on second frame */
|
||||
|
||||
/* MMC registers offset */
|
||||
#define GMAC_MMC_CTRL 0x100
|
||||
#define GMAC_MMC_RX_INTR 0x104
|
||||
#define GMAC_MMC_TX_INTR 0x108
|
||||
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
|
||||
#define GMAC_EXTHASH_BASE 0x500
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
|
||||
#endif /* __DWMAC1000_H__ */
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
#ifndef __DWMAC1000_H__
|
||||
#define __DWMAC1000_H__
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include "common.h"
|
||||
|
||||
#define GMAC_CONTROL 0x00000000 /* Configuration */
|
||||
#define GMAC_FRAME_FILTER 0x00000004 /* Frame Filter */
|
||||
#define GMAC_HASH_HIGH 0x00000008 /* Multicast Hash Table High */
|
||||
#define GMAC_HASH_LOW 0x0000000c /* Multicast Hash Table Low */
|
||||
#define GMAC_MII_ADDR 0x00000010 /* MII Address */
|
||||
#define GMAC_MII_DATA 0x00000014 /* MII Data */
|
||||
#define GMAC_FLOW_CTRL 0x00000018 /* Flow Control */
|
||||
#define GMAC_VLAN_TAG 0x0000001c /* VLAN Tag */
|
||||
#define GMAC_DEBUG 0x00000024 /* GMAC debug register */
|
||||
#define GMAC_WAKEUP_FILTER 0x00000028 /* Wake-up Frame Filter */
|
||||
|
||||
#define GMAC_INT_STATUS 0x00000038 /* interrupt status register */
|
||||
#define GMAC_INT_STATUS_PMT BIT(3)
|
||||
#define GMAC_INT_STATUS_MMCIS BIT(4)
|
||||
#define GMAC_INT_STATUS_MMCRIS BIT(5)
|
||||
#define GMAC_INT_STATUS_MMCTIS BIT(6)
|
||||
#define GMAC_INT_STATUS_MMCCSUM BIT(7)
|
||||
#define GMAC_INT_STATUS_TSTAMP BIT(9)
|
||||
#define GMAC_INT_STATUS_LPIIS BIT(10)
|
||||
|
||||
/* interrupt mask register */
|
||||
#define GMAC_INT_MASK 0x0000003c
|
||||
#define GMAC_INT_DISABLE_RGMII BIT(0)
|
||||
#define GMAC_INT_DISABLE_PCSLINK BIT(1)
|
||||
#define GMAC_INT_DISABLE_PCSAN BIT(2)
|
||||
#define GMAC_INT_DISABLE_PMT BIT(3)
|
||||
#define GMAC_INT_DISABLE_TIMESTAMP BIT(9)
|
||||
#define GMAC_INT_DISABLE_PCS (GMAC_INT_DISABLE_RGMII | \
|
||||
GMAC_INT_DISABLE_PCSLINK | \
|
||||
GMAC_INT_DISABLE_PCSAN)
|
||||
#define GMAC_INT_DEFAULT_MASK (GMAC_INT_DISABLE_TIMESTAMP | \
|
||||
GMAC_INT_DISABLE_PCS)
|
||||
|
||||
/* PMT Control and Status */
|
||||
#define GMAC_PMT 0x0000002c
|
||||
enum power_event {
|
||||
pointer_reset = 0x80000000,
|
||||
global_unicast = 0x00000200,
|
||||
wake_up_rx_frame = 0x00000040,
|
||||
magic_frame = 0x00000020,
|
||||
wake_up_frame_en = 0x00000004,
|
||||
magic_pkt_en = 0x00000002,
|
||||
power_down = 0x00000001,
|
||||
};
|
||||
|
||||
/* Energy Efficient Ethernet (EEE)
|
||||
*
|
||||
* LPI status, timer and control register offset
|
||||
*/
|
||||
#define LPI_CTRL_STATUS 0x0030
|
||||
#define LPI_TIMER_CTRL 0x0034
|
||||
|
||||
/* LPI control and status defines */
|
||||
#define LPI_CTRL_STATUS_LPITXA 0x00080000 /* Enable LPI TX Automate */
|
||||
#define LPI_CTRL_STATUS_PLSEN 0x00040000 /* Enable PHY Link Status */
|
||||
#define LPI_CTRL_STATUS_PLS 0x00020000 /* PHY Link Status */
|
||||
#define LPI_CTRL_STATUS_LPIEN 0x00010000 /* LPI Enable */
|
||||
#define LPI_CTRL_STATUS_RLPIST 0x00000200 /* Receive LPI state */
|
||||
#define LPI_CTRL_STATUS_TLPIST 0x00000100 /* Transmit LPI state */
|
||||
#define LPI_CTRL_STATUS_RLPIEX 0x00000008 /* Receive LPI Exit */
|
||||
#define LPI_CTRL_STATUS_RLPIEN 0x00000004 /* Receive LPI Entry */
|
||||
#define LPI_CTRL_STATUS_TLPIEX 0x00000002 /* Transmit LPI Exit */
|
||||
#define LPI_CTRL_STATUS_TLPIEN 0x00000001 /* Transmit LPI Entry */
|
||||
|
||||
/* GMAC HW ADDR regs */
|
||||
#define GMAC_ADDR_HIGH(reg) ((reg > 15) ? 0x00000800 + (reg - 16) * 8 : \
|
||||
0x00000040 + (reg * 8))
|
||||
#define GMAC_ADDR_LOW(reg) ((reg > 15) ? 0x00000804 + (reg - 16) * 8 : \
|
||||
0x00000044 + (reg * 8))
|
||||
#define GMAC_MAX_PERFECT_ADDRESSES 1
|
||||
|
||||
#define GMAC_PCS_BASE 0x000000c0 /* PCS register base */
|
||||
#define GMAC_RGSMIIIS 0x000000d8 /* RGMII/SMII status */
|
||||
|
||||
/* SGMII/RGMII status register */
|
||||
#define GMAC_RGSMIIIS_LNKMODE BIT(0)
|
||||
#define GMAC_RGSMIIIS_SPEED GENMASK(2, 1)
|
||||
#define GMAC_RGSMIIIS_SPEED_SHIFT 1
|
||||
#define GMAC_RGSMIIIS_LNKSTS BIT(3)
|
||||
#define GMAC_RGSMIIIS_JABTO BIT(4)
|
||||
#define GMAC_RGSMIIIS_FALSECARDET BIT(5)
|
||||
#define GMAC_RGSMIIIS_SMIDRXS BIT(16)
|
||||
/* LNKMOD */
|
||||
#define GMAC_RGSMIIIS_LNKMOD_MASK 0x1
|
||||
/* LNKSPEED */
|
||||
#define GMAC_RGSMIIIS_SPEED_125 0x2
|
||||
#define GMAC_RGSMIIIS_SPEED_25 0x1
|
||||
#define GMAC_RGSMIIIS_SPEED_2_5 0x0
|
||||
|
||||
/* GMAC Configuration defines */
|
||||
#define GMAC_CONTROL_2K 0x08000000 /* IEEE 802.3as 2K packets */
|
||||
#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */
|
||||
#define GMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on receive */
|
||||
#define GMAC_CONTROL_JD 0x00400000 /* Jabber disable */
|
||||
#define GMAC_CONTROL_BE 0x00200000 /* Frame Burst Enable */
|
||||
#define GMAC_CONTROL_JE 0x00100000 /* Jumbo frame */
|
||||
enum inter_frame_gap {
|
||||
GMAC_CONTROL_IFG_88 = 0x00040000,
|
||||
GMAC_CONTROL_IFG_80 = 0x00020000,
|
||||
GMAC_CONTROL_IFG_40 = 0x000e0000,
|
||||
};
|
||||
#define GMAC_CONTROL_DCRS 0x00010000 /* Disable carrier sense */
|
||||
#define GMAC_CONTROL_PS 0x00008000 /* Port Select 0:GMI 1:MII */
|
||||
#define GMAC_CONTROL_FES 0x00004000 /* Speed 0:10 1:100 */
|
||||
#define GMAC_CONTROL_DO 0x00002000 /* Disable Rx Own */
|
||||
#define GMAC_CONTROL_LM 0x00001000 /* Loop-back mode */
|
||||
#define GMAC_CONTROL_DM 0x00000800 /* Duplex Mode */
|
||||
#define GMAC_CONTROL_IPC 0x00000400 /* Checksum Offload */
|
||||
#define GMAC_CONTROL_DR 0x00000200 /* Disable Retry */
|
||||
#define GMAC_CONTROL_LUD 0x00000100 /* Link up/down */
|
||||
#define GMAC_CONTROL_ACS 0x00000080 /* Auto Pad/FCS Stripping */
|
||||
#define GMAC_CONTROL_DC 0x00000010 /* Deferral Check */
|
||||
#define GMAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
|
||||
#define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */
|
||||
|
||||
#define GMAC_CORE_INIT (GMAC_CONTROL_JD | GMAC_CONTROL_PS | \
|
||||
GMAC_CONTROL_BE | GMAC_CONTROL_DCRS)
|
||||
|
||||
/* GMAC Frame Filter defines */
|
||||
#define GMAC_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */
|
||||
#define GMAC_FRAME_FILTER_HUC 0x00000002 /* Hash Unicast */
|
||||
#define GMAC_FRAME_FILTER_HMC 0x00000004 /* Hash Multicast */
|
||||
#define GMAC_FRAME_FILTER_DAIF 0x00000008 /* DA Inverse Filtering */
|
||||
#define GMAC_FRAME_FILTER_PM 0x00000010 /* Pass all multicast */
|
||||
#define GMAC_FRAME_FILTER_DBF 0x00000020 /* Disable Broadcast frames */
|
||||
#define GMAC_FRAME_FILTER_PCF 0x00000080 /* Pass Control frames */
|
||||
#define GMAC_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */
|
||||
#define GMAC_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */
|
||||
#define GMAC_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */
|
||||
#define GMAC_FRAME_FILTER_RA 0x80000000 /* Receive all mode */
|
||||
/* GMII ADDR defines */
|
||||
#define GMAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
|
||||
#define GMAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */
|
||||
/* GMAC FLOW CTRL defines */
|
||||
#define GMAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */
|
||||
#define GMAC_FLOW_CTRL_PT_SHIFT 16
|
||||
#define GMAC_FLOW_CTRL_UP 0x00000008 /* Unicast pause frame enable */
|
||||
#define GMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */
|
||||
#define GMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */
|
||||
#define GMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */
|
||||
|
||||
/* DEBUG Register defines */
|
||||
/* MTL TxStatus FIFO */
|
||||
#define GMAC_DEBUG_TXSTSFSTS BIT(25) /* MTL TxStatus FIFO Full Status */
|
||||
#define GMAC_DEBUG_TXFSTS BIT(24) /* MTL Tx FIFO Not Empty Status */
|
||||
#define GMAC_DEBUG_TWCSTS BIT(22) /* MTL Tx FIFO Write Controller */
|
||||
/* MTL Tx FIFO Read Controller Status */
|
||||
#define GMAC_DEBUG_TRCSTS_MASK GENMASK(21, 20)
|
||||
#define GMAC_DEBUG_TRCSTS_SHIFT 20
|
||||
#define GMAC_DEBUG_TRCSTS_IDLE 0
|
||||
#define GMAC_DEBUG_TRCSTS_READ 1
|
||||
#define GMAC_DEBUG_TRCSTS_TXW 2
|
||||
#define GMAC_DEBUG_TRCSTS_WRITE 3
|
||||
#define GMAC_DEBUG_TXPAUSED BIT(19) /* MAC Transmitter in PAUSE */
|
||||
/* MAC Transmit Frame Controller Status */
|
||||
#define GMAC_DEBUG_TFCSTS_MASK GENMASK(18, 17)
|
||||
#define GMAC_DEBUG_TFCSTS_SHIFT 17
|
||||
#define GMAC_DEBUG_TFCSTS_IDLE 0
|
||||
#define GMAC_DEBUG_TFCSTS_WAIT 1
|
||||
#define GMAC_DEBUG_TFCSTS_GEN_PAUSE 2
|
||||
#define GMAC_DEBUG_TFCSTS_XFER 3
|
||||
/* MAC GMII or MII Transmit Protocol Engine Status */
|
||||
#define GMAC_DEBUG_TPESTS BIT(16)
|
||||
#define GMAC_DEBUG_RXFSTS_MASK GENMASK(9, 8) /* MTL Rx FIFO Fill-level */
|
||||
#define GMAC_DEBUG_RXFSTS_SHIFT 8
|
||||
#define GMAC_DEBUG_RXFSTS_EMPTY 0
|
||||
#define GMAC_DEBUG_RXFSTS_BT 1
|
||||
#define GMAC_DEBUG_RXFSTS_AT 2
|
||||
#define GMAC_DEBUG_RXFSTS_FULL 3
|
||||
#define GMAC_DEBUG_RRCSTS_MASK GENMASK(6, 5) /* MTL Rx FIFO Read Controller */
|
||||
#define GMAC_DEBUG_RRCSTS_SHIFT 5
|
||||
#define GMAC_DEBUG_RRCSTS_IDLE 0
|
||||
#define GMAC_DEBUG_RRCSTS_RDATA 1
|
||||
#define GMAC_DEBUG_RRCSTS_RSTAT 2
|
||||
#define GMAC_DEBUG_RRCSTS_FLUSH 3
|
||||
#define GMAC_DEBUG_RWCSTS BIT(4) /* MTL Rx FIFO Write Controller Active */
|
||||
/* MAC Receive Frame Controller FIFO Status */
|
||||
#define GMAC_DEBUG_RFCFCSTS_MASK GENMASK(2, 1)
|
||||
#define GMAC_DEBUG_RFCFCSTS_SHIFT 1
|
||||
/* MAC GMII or MII Receive Protocol Engine Status */
|
||||
#define GMAC_DEBUG_RPESTS BIT(0)
|
||||
|
||||
/*--- DMA BLOCK defines ---*/
|
||||
/* DMA Bus Mode register defines */
|
||||
#define DMA_BUS_MODE_DA 0x00000002 /* Arbitration scheme */
|
||||
#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
|
||||
#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
|
||||
/* Programmable burst length (passed thorugh platform)*/
|
||||
#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_PBL_SHIFT 8
|
||||
#define DMA_BUS_MODE_ATDS 0x00000080 /* Alternate Descriptor Size */
|
||||
|
||||
enum rx_tx_priority_ratio {
|
||||
double_ratio = 0x00004000, /* 2:1 */
|
||||
triple_ratio = 0x00008000, /* 3:1 */
|
||||
quadruple_ratio = 0x0000c000, /* 4:1 */
|
||||
};
|
||||
|
||||
#define DMA_BUS_MODE_FB 0x00010000 /* Fixed burst */
|
||||
#define DMA_BUS_MODE_MB 0x04000000 /* Mixed burst */
|
||||
#define DMA_BUS_MODE_RPBL_MASK 0x007e0000 /* Rx-Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_RPBL_SHIFT 17
|
||||
#define DMA_BUS_MODE_USP 0x00800000
|
||||
#define DMA_BUS_MODE_MAXPBL 0x01000000
|
||||
#define DMA_BUS_MODE_AAL 0x02000000
|
||||
|
||||
/* DMA CRS Control and Status Register Mapping */
|
||||
#define DMA_HOST_TX_DESC 0x00001048 /* Current Host Tx descriptor */
|
||||
#define DMA_HOST_RX_DESC 0x0000104c /* Current Host Rx descriptor */
|
||||
/* DMA Bus Mode register defines */
|
||||
#define DMA_BUS_PR_RATIO_MASK 0x0000c000 /* Rx/Tx priority ratio */
|
||||
#define DMA_BUS_PR_RATIO_SHIFT 14
|
||||
#define DMA_BUS_FB 0x00010000 /* Fixed Burst */
|
||||
|
||||
/* DMA operation mode defines (start/stop tx/rx are placed in common header)*/
|
||||
/* Disable Drop TCP/IP csum error */
|
||||
#define DMA_CONTROL_DT 0x04000000
|
||||
#define DMA_CONTROL_RSF 0x02000000 /* Receive Store and Forward */
|
||||
#define DMA_CONTROL_DFF 0x01000000 /* Disaable flushing */
|
||||
/* Threshold for Activating the FC */
|
||||
enum rfa {
|
||||
act_full_minus_1 = 0x00800000,
|
||||
act_full_minus_2 = 0x00800200,
|
||||
act_full_minus_3 = 0x00800400,
|
||||
act_full_minus_4 = 0x00800600,
|
||||
};
|
||||
/* Threshold for Deactivating the FC */
|
||||
enum rfd {
|
||||
deac_full_minus_1 = 0x00400000,
|
||||
deac_full_minus_2 = 0x00400800,
|
||||
deac_full_minus_3 = 0x00401000,
|
||||
deac_full_minus_4 = 0x00401800,
|
||||
};
|
||||
#define DMA_CONTROL_TSF 0x00200000 /* Transmit Store and Forward */
|
||||
|
||||
enum ttc_control {
|
||||
DMA_CONTROL_TTC_64 = 0x00000000,
|
||||
DMA_CONTROL_TTC_128 = 0x00004000,
|
||||
DMA_CONTROL_TTC_192 = 0x00008000,
|
||||
DMA_CONTROL_TTC_256 = 0x0000c000,
|
||||
DMA_CONTROL_TTC_40 = 0x00010000,
|
||||
DMA_CONTROL_TTC_32 = 0x00014000,
|
||||
DMA_CONTROL_TTC_24 = 0x00018000,
|
||||
DMA_CONTROL_TTC_16 = 0x0001c000,
|
||||
};
|
||||
#define DMA_CONTROL_TC_TX_MASK 0xfffe3fff
|
||||
|
||||
#define DMA_CONTROL_EFC 0x00000100
|
||||
#define DMA_CONTROL_FEF 0x00000080
|
||||
#define DMA_CONTROL_FUF 0x00000040
|
||||
|
||||
/* Receive flow control activation field
|
||||
* RFA field in DMA control register, bits 23,10:9
|
||||
*/
|
||||
#define DMA_CONTROL_RFA_MASK 0x00800600
|
||||
|
||||
/* Receive flow control deactivation field
|
||||
* RFD field in DMA control register, bits 22,12:11
|
||||
*/
|
||||
#define DMA_CONTROL_RFD_MASK 0x00401800
|
||||
|
||||
/* RFD and RFA fields are encoded as follows
|
||||
*
|
||||
* Bit Field
|
||||
* 0,00 - Full minus 1KB (only valid when rxfifo >= 4KB and EFC enabled)
|
||||
* 0,01 - Full minus 2KB (only valid when rxfifo >= 4KB and EFC enabled)
|
||||
* 0,10 - Full minus 3KB (only valid when rxfifo >= 4KB and EFC enabled)
|
||||
* 0,11 - Full minus 4KB (only valid when rxfifo > 4KB and EFC enabled)
|
||||
* 1,00 - Full minus 5KB (only valid when rxfifo > 8KB and EFC enabled)
|
||||
* 1,01 - Full minus 6KB (only valid when rxfifo > 8KB and EFC enabled)
|
||||
* 1,10 - Full minus 7KB (only valid when rxfifo > 8KB and EFC enabled)
|
||||
* 1,11 - Reserved
|
||||
*
|
||||
* RFD should always be > RFA for a given FIFO size. RFD == RFA may work,
|
||||
* but packet throughput performance may not be as expected.
|
||||
*
|
||||
* Be sure that bit 3 in GMAC Register 6 is set for Unicast Pause frame
|
||||
* detection (IEEE Specification Requirement, Annex 31B, 31B.1, Pause
|
||||
* Description).
|
||||
*
|
||||
* Be sure that DZPA (bit 7 in Flow Control Register, GMAC Register 6),
|
||||
* is set to 0. This allows pause frames with a quanta of 0 to be sent
|
||||
* as an XOFF message to the link peer.
|
||||
*/
|
||||
|
||||
#define RFA_FULL_MINUS_1K 0x00000000
|
||||
#define RFA_FULL_MINUS_2K 0x00000200
|
||||
#define RFA_FULL_MINUS_3K 0x00000400
|
||||
#define RFA_FULL_MINUS_4K 0x00000600
|
||||
#define RFA_FULL_MINUS_5K 0x00800000
|
||||
#define RFA_FULL_MINUS_6K 0x00800200
|
||||
#define RFA_FULL_MINUS_7K 0x00800400
|
||||
|
||||
#define RFD_FULL_MINUS_1K 0x00000000
|
||||
#define RFD_FULL_MINUS_2K 0x00000800
|
||||
#define RFD_FULL_MINUS_3K 0x00001000
|
||||
#define RFD_FULL_MINUS_4K 0x00001800
|
||||
#define RFD_FULL_MINUS_5K 0x00400000
|
||||
#define RFD_FULL_MINUS_6K 0x00400800
|
||||
#define RFD_FULL_MINUS_7K 0x00401000
|
||||
|
||||
enum rtc_control {
|
||||
DMA_CONTROL_RTC_64 = 0x00000000,
|
||||
DMA_CONTROL_RTC_32 = 0x00000008,
|
||||
DMA_CONTROL_RTC_96 = 0x00000010,
|
||||
DMA_CONTROL_RTC_128 = 0x00000018,
|
||||
};
|
||||
#define DMA_CONTROL_TC_RX_MASK 0xffffffe7
|
||||
|
||||
#define DMA_CONTROL_OSF 0x00000004 /* Operate on second frame */
|
||||
|
||||
/* MMC registers offset */
|
||||
#define GMAC_MMC_CTRL 0x100
|
||||
#define GMAC_MMC_RX_INTR 0x104
|
||||
#define GMAC_MMC_TX_INTR 0x108
|
||||
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
|
||||
#define GMAC_EXTHASH_BASE 0x500
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
|
||||
#endif /* __DWMAC1000_H__ */
|
||||
|
|
@ -0,0 +1,553 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
|
||||
DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
|
||||
developing this code.
|
||||
|
||||
This only implements the mac core functions for this chip.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/io.h>
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
#include "stmmac_pcs-6.12-ethercat.h"
|
||||
#include "dwmac1000-6.12-ethercat.h"
|
||||
|
||||
static void dwmac1000_core_init(struct mac_device_info *hw,
|
||||
struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + GMAC_CONTROL);
|
||||
int mtu = dev->mtu;
|
||||
|
||||
/* Configure GMAC core */
|
||||
value |= GMAC_CORE_INIT;
|
||||
|
||||
if (mtu > 1500)
|
||||
value |= GMAC_CONTROL_2K;
|
||||
if (mtu > 2000)
|
||||
value |= GMAC_CONTROL_JE;
|
||||
|
||||
if (hw->ps) {
|
||||
value |= GMAC_CONTROL_TE;
|
||||
|
||||
value &= ~hw->link.speed_mask;
|
||||
switch (hw->ps) {
|
||||
case SPEED_1000:
|
||||
value |= hw->link.speed1000;
|
||||
break;
|
||||
case SPEED_100:
|
||||
value |= hw->link.speed100;
|
||||
break;
|
||||
case SPEED_10:
|
||||
value |= hw->link.speed10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writel(value, ioaddr + GMAC_CONTROL);
|
||||
|
||||
/* Mask GMAC interrupts */
|
||||
value = GMAC_INT_DEFAULT_MASK;
|
||||
|
||||
if (hw->pcs)
|
||||
value &= ~GMAC_INT_DISABLE_PCS;
|
||||
|
||||
writel(value, ioaddr + GMAC_INT_MASK);
|
||||
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
/* Tag detection without filtering */
|
||||
writel(0x0, ioaddr + GMAC_VLAN_TAG);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int dwmac1000_rx_ipc_enable(struct mac_device_info *hw)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + GMAC_CONTROL);
|
||||
|
||||
if (hw->rx_csum)
|
||||
value |= GMAC_CONTROL_IPC;
|
||||
else
|
||||
value &= ~GMAC_CONTROL_IPC;
|
||||
|
||||
writel(value, ioaddr + GMAC_CONTROL);
|
||||
|
||||
value = readl(ioaddr + GMAC_CONTROL);
|
||||
|
||||
return !!(value & GMAC_CONTROL_IPC);
|
||||
}
|
||||
|
||||
static void dwmac1000_dump_regs(struct mac_device_info *hw, u32 *reg_space)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 55; i++)
|
||||
reg_space[i] = readl(ioaddr + i * 4);
|
||||
}
|
||||
|
||||
static void dwmac1000_set_umac_addr(struct mac_device_info *hw,
|
||||
const unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
|
||||
GMAC_ADDR_LOW(reg_n));
|
||||
}
|
||||
|
||||
static void dwmac1000_get_umac_addr(struct mac_device_info *hw,
|
||||
unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
|
||||
GMAC_ADDR_LOW(reg_n));
|
||||
}
|
||||
|
||||
static void dwmac1000_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits,
|
||||
int mcbitslog2)
|
||||
{
|
||||
int numhashregs, regs;
|
||||
|
||||
switch (mcbitslog2) {
|
||||
case 6:
|
||||
writel(mcfilterbits[0], ioaddr + GMAC_HASH_LOW);
|
||||
writel(mcfilterbits[1], ioaddr + GMAC_HASH_HIGH);
|
||||
return;
|
||||
case 7:
|
||||
numhashregs = 4;
|
||||
break;
|
||||
case 8:
|
||||
numhashregs = 8;
|
||||
break;
|
||||
default:
|
||||
pr_debug("STMMAC: err in setting multicast filter\n");
|
||||
return;
|
||||
}
|
||||
for (regs = 0; regs < numhashregs; regs++)
|
||||
writel(mcfilterbits[regs],
|
||||
ioaddr + GMAC_EXTHASH_BASE + regs * 4);
|
||||
}
|
||||
|
||||
static void dwmac1000_set_filter(struct mac_device_info *hw,
|
||||
struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = (void __iomem *)dev->base_addr;
|
||||
unsigned int value = 0;
|
||||
unsigned int perfect_addr_number = hw->unicast_filter_entries;
|
||||
u32 mc_filter[8];
|
||||
int mcbitslog2 = hw->mcast_bits_log2;
|
||||
|
||||
pr_debug("%s: # mcasts %d, # unicast %d\n", __func__,
|
||||
netdev_mc_count(dev), netdev_uc_count(dev));
|
||||
|
||||
memset(mc_filter, 0, sizeof(mc_filter));
|
||||
|
||||
if (dev->flags & IFF_PROMISC) {
|
||||
value = GMAC_FRAME_FILTER_PR | GMAC_FRAME_FILTER_PCF;
|
||||
} else if (dev->flags & IFF_ALLMULTI) {
|
||||
value = GMAC_FRAME_FILTER_PM; /* pass all multi */
|
||||
} else if (!netdev_mc_empty(dev) && (mcbitslog2 == 0)) {
|
||||
/* Fall back to all multicast if we've no filter */
|
||||
value = GMAC_FRAME_FILTER_PM;
|
||||
} else if (!netdev_mc_empty(dev)) {
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
/* Hash filter for multicast */
|
||||
value = GMAC_FRAME_FILTER_HMC;
|
||||
|
||||
netdev_for_each_mc_addr(ha, dev) {
|
||||
/* The upper n bits of the calculated CRC are used to
|
||||
* index the contents of the hash table. The number of
|
||||
* bits used depends on the hardware configuration
|
||||
* selected at core configuration time.
|
||||
*/
|
||||
int bit_nr = bitrev32(~crc32_le(~0, ha->addr,
|
||||
ETH_ALEN)) >>
|
||||
(32 - mcbitslog2);
|
||||
/* The most significant bit determines the register to
|
||||
* use (H/L) while the other 5 bits determine the bit
|
||||
* within the register.
|
||||
*/
|
||||
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
|
||||
}
|
||||
}
|
||||
|
||||
value |= GMAC_FRAME_FILTER_HPF;
|
||||
dwmac1000_set_mchash(ioaddr, mc_filter, mcbitslog2);
|
||||
|
||||
/* Handle multiple unicast addresses (perfect filtering) */
|
||||
if (netdev_uc_count(dev) > perfect_addr_number)
|
||||
/* Switch to promiscuous mode if more than unicast
|
||||
* addresses are requested than supported by hardware.
|
||||
*/
|
||||
value |= GMAC_FRAME_FILTER_PR;
|
||||
else {
|
||||
int reg = 1;
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
netdev_for_each_uc_addr(ha, dev) {
|
||||
stmmac_set_mac_addr(ioaddr, ha->addr,
|
||||
GMAC_ADDR_HIGH(reg),
|
||||
GMAC_ADDR_LOW(reg));
|
||||
reg++;
|
||||
}
|
||||
|
||||
while (reg < perfect_addr_number) {
|
||||
writel(0, ioaddr + GMAC_ADDR_HIGH(reg));
|
||||
writel(0, ioaddr + GMAC_ADDR_LOW(reg));
|
||||
reg++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FRAME_FILTER_DEBUG
|
||||
/* Enable Receive all mode (to debug filtering_fail errors) */
|
||||
value |= GMAC_FRAME_FILTER_RA;
|
||||
#endif
|
||||
writel(value, ioaddr + GMAC_FRAME_FILTER);
|
||||
}
|
||||
|
||||
|
||||
static void dwmac1000_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
|
||||
unsigned int fc, unsigned int pause_time,
|
||||
u32 tx_cnt)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
/* Set flow such that DZPQ in Mac Register 6 is 0,
|
||||
* and unicast pause detect is enabled.
|
||||
*/
|
||||
unsigned int flow = GMAC_FLOW_CTRL_UP;
|
||||
|
||||
pr_debug("GMAC Flow-Control:\n");
|
||||
if (fc & FLOW_RX) {
|
||||
pr_debug("\tReceive Flow-Control ON\n");
|
||||
flow |= GMAC_FLOW_CTRL_RFE;
|
||||
}
|
||||
if (fc & FLOW_TX) {
|
||||
pr_debug("\tTransmit Flow-Control ON\n");
|
||||
flow |= GMAC_FLOW_CTRL_TFE;
|
||||
}
|
||||
|
||||
if (duplex) {
|
||||
pr_debug("\tduplex mode: PAUSE %d\n", pause_time);
|
||||
flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
|
||||
}
|
||||
|
||||
writel(flow, ioaddr + GMAC_FLOW_CTRL);
|
||||
}
|
||||
|
||||
static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
unsigned int pmt = 0;
|
||||
|
||||
if (mode & WAKE_MAGIC) {
|
||||
pr_debug("GMAC: WOL Magic frame\n");
|
||||
pmt |= power_down | magic_pkt_en;
|
||||
}
|
||||
if (mode & WAKE_UCAST) {
|
||||
pr_debug("GMAC: WOL on global unicast\n");
|
||||
pmt |= power_down | global_unicast | wake_up_frame_en;
|
||||
}
|
||||
|
||||
writel(pmt, ioaddr + GMAC_PMT);
|
||||
}
|
||||
|
||||
/* RGMII or SMII interface */
|
||||
static void dwmac1000_rgsmii(void __iomem *ioaddr, struct stmmac_extra_stats *x)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
status = readl(ioaddr + GMAC_RGSMIIIS);
|
||||
x->irq_rgmii_n++;
|
||||
|
||||
/* Check the link status */
|
||||
if (status & GMAC_RGSMIIIS_LNKSTS) {
|
||||
int speed_value;
|
||||
|
||||
x->pcs_link = 1;
|
||||
|
||||
speed_value = ((status & GMAC_RGSMIIIS_SPEED) >>
|
||||
GMAC_RGSMIIIS_SPEED_SHIFT);
|
||||
if (speed_value == GMAC_RGSMIIIS_SPEED_125)
|
||||
x->pcs_speed = SPEED_1000;
|
||||
else if (speed_value == GMAC_RGSMIIIS_SPEED_25)
|
||||
x->pcs_speed = SPEED_100;
|
||||
else
|
||||
x->pcs_speed = SPEED_10;
|
||||
|
||||
x->pcs_duplex = (status & GMAC_RGSMIIIS_LNKMOD_MASK);
|
||||
|
||||
pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed,
|
||||
x->pcs_duplex ? "Full" : "Half");
|
||||
} else {
|
||||
x->pcs_link = 0;
|
||||
pr_info("Link is Down\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int dwmac1000_irq_status(struct mac_device_info *hw,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
|
||||
u32 intr_mask = readl(ioaddr + GMAC_INT_MASK);
|
||||
int ret = 0;
|
||||
|
||||
/* Discard masked bits */
|
||||
intr_status &= ~intr_mask;
|
||||
|
||||
/* Not used events (e.g. MMC interrupts) are not handled. */
|
||||
if ((intr_status & GMAC_INT_STATUS_MMCTIS))
|
||||
x->mmc_tx_irq_n++;
|
||||
if (unlikely(intr_status & GMAC_INT_STATUS_MMCRIS))
|
||||
x->mmc_rx_irq_n++;
|
||||
if (unlikely(intr_status & GMAC_INT_STATUS_MMCCSUM))
|
||||
x->mmc_rx_csum_offload_irq_n++;
|
||||
if (unlikely(intr_status & GMAC_INT_DISABLE_PMT)) {
|
||||
/* clear the PMT bits 5 and 6 by reading the PMT status reg */
|
||||
readl(ioaddr + GMAC_PMT);
|
||||
x->irq_receive_pmt_irq_n++;
|
||||
}
|
||||
|
||||
/* MAC tx/rx EEE LPI entry/exit interrupts */
|
||||
if (intr_status & GMAC_INT_STATUS_LPIIS) {
|
||||
/* Clean LPI interrupt by reading the Reg 12 */
|
||||
ret = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
|
||||
if (ret & LPI_CTRL_STATUS_TLPIEN)
|
||||
x->irq_tx_path_in_lpi_mode_n++;
|
||||
if (ret & LPI_CTRL_STATUS_TLPIEX)
|
||||
x->irq_tx_path_exit_lpi_mode_n++;
|
||||
if (ret & LPI_CTRL_STATUS_RLPIEN)
|
||||
x->irq_rx_path_in_lpi_mode_n++;
|
||||
if (ret & LPI_CTRL_STATUS_RLPIEX)
|
||||
x->irq_rx_path_exit_lpi_mode_n++;
|
||||
}
|
||||
|
||||
dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
|
||||
|
||||
if (intr_status & PCS_RGSMIIIS_IRQ)
|
||||
dwmac1000_rgsmii(ioaddr, x);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwmac1000_set_eee_mode(struct mac_device_info *hw,
|
||||
bool en_tx_lpi_clockgating)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value;
|
||||
|
||||
/*TODO - en_tx_lpi_clockgating treatment */
|
||||
|
||||
/* Enable the link status receive on RGMII, SGMII ore SMII
|
||||
* receive path and instruct the transmit to enter in LPI
|
||||
* state.
|
||||
*/
|
||||
value = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
|
||||
writel(value, ioaddr + LPI_CTRL_STATUS);
|
||||
}
|
||||
|
||||
static void dwmac1000_reset_eee_mode(struct mac_device_info *hw)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
value &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA);
|
||||
writel(value, ioaddr + LPI_CTRL_STATUS);
|
||||
}
|
||||
|
||||
static void dwmac1000_set_eee_pls(struct mac_device_info *hw, int link)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
|
||||
if (link)
|
||||
value |= LPI_CTRL_STATUS_PLS;
|
||||
else
|
||||
value &= ~LPI_CTRL_STATUS_PLS;
|
||||
|
||||
writel(value, ioaddr + LPI_CTRL_STATUS);
|
||||
}
|
||||
|
||||
static void dwmac1000_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
|
||||
|
||||
/* Program the timers in the LPI timer control register:
|
||||
* LS: minimum time (ms) for which the link
|
||||
* status from PHY should be ok before transmitting
|
||||
* the LPI pattern.
|
||||
* TW: minimum time (us) for which the core waits
|
||||
* after it has stopped transmitting the LPI pattern.
|
||||
*/
|
||||
writel(value, ioaddr + LPI_TIMER_CTRL);
|
||||
}
|
||||
|
||||
static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool ane, bool srgmi_ral,
|
||||
bool loopback)
|
||||
{
|
||||
dwmac_ctrl_ane(ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback);
|
||||
}
|
||||
|
||||
static void dwmac1000_get_adv_lp(void __iomem *ioaddr, struct rgmii_adv *adv)
|
||||
{
|
||||
dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv);
|
||||
}
|
||||
|
||||
static void dwmac1000_debug(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x,
|
||||
u32 rx_queues, u32 tx_queues)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_DEBUG);
|
||||
|
||||
if (value & GMAC_DEBUG_TXSTSFSTS)
|
||||
x->mtl_tx_status_fifo_full++;
|
||||
if (value & GMAC_DEBUG_TXFSTS)
|
||||
x->mtl_tx_fifo_not_empty++;
|
||||
if (value & GMAC_DEBUG_TWCSTS)
|
||||
x->mmtl_fifo_ctrl++;
|
||||
if (value & GMAC_DEBUG_TRCSTS_MASK) {
|
||||
u32 trcsts = (value & GMAC_DEBUG_TRCSTS_MASK)
|
||||
>> GMAC_DEBUG_TRCSTS_SHIFT;
|
||||
if (trcsts == GMAC_DEBUG_TRCSTS_WRITE)
|
||||
x->mtl_tx_fifo_read_ctrl_write++;
|
||||
else if (trcsts == GMAC_DEBUG_TRCSTS_TXW)
|
||||
x->mtl_tx_fifo_read_ctrl_wait++;
|
||||
else if (trcsts == GMAC_DEBUG_TRCSTS_READ)
|
||||
x->mtl_tx_fifo_read_ctrl_read++;
|
||||
else
|
||||
x->mtl_tx_fifo_read_ctrl_idle++;
|
||||
}
|
||||
if (value & GMAC_DEBUG_TXPAUSED)
|
||||
x->mac_tx_in_pause++;
|
||||
if (value & GMAC_DEBUG_TFCSTS_MASK) {
|
||||
u32 tfcsts = (value & GMAC_DEBUG_TFCSTS_MASK)
|
||||
>> GMAC_DEBUG_TFCSTS_SHIFT;
|
||||
|
||||
if (tfcsts == GMAC_DEBUG_TFCSTS_XFER)
|
||||
x->mac_tx_frame_ctrl_xfer++;
|
||||
else if (tfcsts == GMAC_DEBUG_TFCSTS_GEN_PAUSE)
|
||||
x->mac_tx_frame_ctrl_pause++;
|
||||
else if (tfcsts == GMAC_DEBUG_TFCSTS_WAIT)
|
||||
x->mac_tx_frame_ctrl_wait++;
|
||||
else
|
||||
x->mac_tx_frame_ctrl_idle++;
|
||||
}
|
||||
if (value & GMAC_DEBUG_TPESTS)
|
||||
x->mac_gmii_tx_proto_engine++;
|
||||
if (value & GMAC_DEBUG_RXFSTS_MASK) {
|
||||
u32 rxfsts = (value & GMAC_DEBUG_RXFSTS_MASK)
|
||||
>> GMAC_DEBUG_RRCSTS_SHIFT;
|
||||
|
||||
if (rxfsts == GMAC_DEBUG_RXFSTS_FULL)
|
||||
x->mtl_rx_fifo_fill_level_full++;
|
||||
else if (rxfsts == GMAC_DEBUG_RXFSTS_AT)
|
||||
x->mtl_rx_fifo_fill_above_thresh++;
|
||||
else if (rxfsts == GMAC_DEBUG_RXFSTS_BT)
|
||||
x->mtl_rx_fifo_fill_below_thresh++;
|
||||
else
|
||||
x->mtl_rx_fifo_fill_level_empty++;
|
||||
}
|
||||
if (value & GMAC_DEBUG_RRCSTS_MASK) {
|
||||
u32 rrcsts = (value & GMAC_DEBUG_RRCSTS_MASK) >>
|
||||
GMAC_DEBUG_RRCSTS_SHIFT;
|
||||
|
||||
if (rrcsts == GMAC_DEBUG_RRCSTS_FLUSH)
|
||||
x->mtl_rx_fifo_read_ctrl_flush++;
|
||||
else if (rrcsts == GMAC_DEBUG_RRCSTS_RSTAT)
|
||||
x->mtl_rx_fifo_read_ctrl_read_data++;
|
||||
else if (rrcsts == GMAC_DEBUG_RRCSTS_RDATA)
|
||||
x->mtl_rx_fifo_read_ctrl_status++;
|
||||
else
|
||||
x->mtl_rx_fifo_read_ctrl_idle++;
|
||||
}
|
||||
if (value & GMAC_DEBUG_RWCSTS)
|
||||
x->mtl_rx_fifo_ctrl_active++;
|
||||
if (value & GMAC_DEBUG_RFCFCSTS_MASK)
|
||||
x->mac_rx_frame_ctrl_fifo = (value & GMAC_DEBUG_RFCFCSTS_MASK)
|
||||
>> GMAC_DEBUG_RFCFCSTS_SHIFT;
|
||||
if (value & GMAC_DEBUG_RPESTS)
|
||||
x->mac_gmii_rx_proto_engine++;
|
||||
}
|
||||
|
||||
static void dwmac1000_set_mac_loopback(void __iomem *ioaddr, bool enable)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_CONTROL);
|
||||
|
||||
if (enable)
|
||||
value |= GMAC_CONTROL_LM;
|
||||
else
|
||||
value &= ~GMAC_CONTROL_LM;
|
||||
|
||||
writel(value, ioaddr + GMAC_CONTROL);
|
||||
}
|
||||
|
||||
const struct stmmac_ops dwmac1000_ops = {
|
||||
.core_init = dwmac1000_core_init,
|
||||
.set_mac = stmmac_set_mac,
|
||||
.rx_ipc = dwmac1000_rx_ipc_enable,
|
||||
.dump_regs = dwmac1000_dump_regs,
|
||||
.host_irq_status = dwmac1000_irq_status,
|
||||
.set_filter = dwmac1000_set_filter,
|
||||
.flow_ctrl = dwmac1000_flow_ctrl,
|
||||
.pmt = dwmac1000_pmt,
|
||||
.set_umac_addr = dwmac1000_set_umac_addr,
|
||||
.get_umac_addr = dwmac1000_get_umac_addr,
|
||||
.set_eee_mode = dwmac1000_set_eee_mode,
|
||||
.reset_eee_mode = dwmac1000_reset_eee_mode,
|
||||
.set_eee_timer = dwmac1000_set_eee_timer,
|
||||
.set_eee_pls = dwmac1000_set_eee_pls,
|
||||
.debug = dwmac1000_debug,
|
||||
.pcs_ctrl_ane = dwmac1000_ctrl_ane,
|
||||
.pcs_get_adv_lp = dwmac1000_get_adv_lp,
|
||||
.set_mac_loopback = dwmac1000_set_mac_loopback,
|
||||
};
|
||||
|
||||
int dwmac1000_setup(struct stmmac_priv *priv)
|
||||
{
|
||||
struct mac_device_info *mac = priv->hw;
|
||||
|
||||
dev_info(priv->device, "\tDWMAC1000\n");
|
||||
|
||||
priv->dev->priv_flags |= IFF_UNICAST_FLT;
|
||||
mac->pcsr = priv->ioaddr;
|
||||
mac->multicast_filter_bins = priv->plat->multicast_filter_bins;
|
||||
mac->unicast_filter_entries = priv->plat->unicast_filter_entries;
|
||||
mac->mcast_bits_log2 = 0;
|
||||
|
||||
if (mac->multicast_filter_bins)
|
||||
mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins);
|
||||
|
||||
mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
|
||||
MAC_10 | MAC_100 | MAC_1000;
|
||||
mac->link.duplex = GMAC_CONTROL_DM;
|
||||
mac->link.speed10 = GMAC_CONTROL_PS;
|
||||
mac->link.speed100 = GMAC_CONTROL_PS | GMAC_CONTROL_FES;
|
||||
mac->link.speed1000 = 0;
|
||||
mac->link.speed_mask = GMAC_CONTROL_PS | GMAC_CONTROL_FES;
|
||||
mac->mii.addr = GMAC_MII_ADDR;
|
||||
mac->mii.data = GMAC_MII_DATA;
|
||||
mac->mii.addr_shift = 11;
|
||||
mac->mii.addr_mask = 0x0000F800;
|
||||
mac->mii.reg_shift = 6;
|
||||
mac->mii.reg_mask = 0x000007C0;
|
||||
mac->mii.clk_csr_shift = 2;
|
||||
mac->mii.clk_csr_mask = GENMASK(5, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,553 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
|
||||
DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
|
||||
developing this code.
|
||||
|
||||
This only implements the mac core functions for this chip.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/io.h>
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_pcs.h"
|
||||
#include "dwmac1000.h"
|
||||
|
||||
static void dwmac1000_core_init(struct mac_device_info *hw,
|
||||
struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + GMAC_CONTROL);
|
||||
int mtu = dev->mtu;
|
||||
|
||||
/* Configure GMAC core */
|
||||
value |= GMAC_CORE_INIT;
|
||||
|
||||
if (mtu > 1500)
|
||||
value |= GMAC_CONTROL_2K;
|
||||
if (mtu > 2000)
|
||||
value |= GMAC_CONTROL_JE;
|
||||
|
||||
if (hw->ps) {
|
||||
value |= GMAC_CONTROL_TE;
|
||||
|
||||
value &= ~hw->link.speed_mask;
|
||||
switch (hw->ps) {
|
||||
case SPEED_1000:
|
||||
value |= hw->link.speed1000;
|
||||
break;
|
||||
case SPEED_100:
|
||||
value |= hw->link.speed100;
|
||||
break;
|
||||
case SPEED_10:
|
||||
value |= hw->link.speed10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writel(value, ioaddr + GMAC_CONTROL);
|
||||
|
||||
/* Mask GMAC interrupts */
|
||||
value = GMAC_INT_DEFAULT_MASK;
|
||||
|
||||
if (hw->pcs)
|
||||
value &= ~GMAC_INT_DISABLE_PCS;
|
||||
|
||||
writel(value, ioaddr + GMAC_INT_MASK);
|
||||
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
/* Tag detection without filtering */
|
||||
writel(0x0, ioaddr + GMAC_VLAN_TAG);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int dwmac1000_rx_ipc_enable(struct mac_device_info *hw)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + GMAC_CONTROL);
|
||||
|
||||
if (hw->rx_csum)
|
||||
value |= GMAC_CONTROL_IPC;
|
||||
else
|
||||
value &= ~GMAC_CONTROL_IPC;
|
||||
|
||||
writel(value, ioaddr + GMAC_CONTROL);
|
||||
|
||||
value = readl(ioaddr + GMAC_CONTROL);
|
||||
|
||||
return !!(value & GMAC_CONTROL_IPC);
|
||||
}
|
||||
|
||||
static void dwmac1000_dump_regs(struct mac_device_info *hw, u32 *reg_space)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 55; i++)
|
||||
reg_space[i] = readl(ioaddr + i * 4);
|
||||
}
|
||||
|
||||
static void dwmac1000_set_umac_addr(struct mac_device_info *hw,
|
||||
const unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
|
||||
GMAC_ADDR_LOW(reg_n));
|
||||
}
|
||||
|
||||
static void dwmac1000_get_umac_addr(struct mac_device_info *hw,
|
||||
unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
|
||||
GMAC_ADDR_LOW(reg_n));
|
||||
}
|
||||
|
||||
static void dwmac1000_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits,
|
||||
int mcbitslog2)
|
||||
{
|
||||
int numhashregs, regs;
|
||||
|
||||
switch (mcbitslog2) {
|
||||
case 6:
|
||||
writel(mcfilterbits[0], ioaddr + GMAC_HASH_LOW);
|
||||
writel(mcfilterbits[1], ioaddr + GMAC_HASH_HIGH);
|
||||
return;
|
||||
case 7:
|
||||
numhashregs = 4;
|
||||
break;
|
||||
case 8:
|
||||
numhashregs = 8;
|
||||
break;
|
||||
default:
|
||||
pr_debug("STMMAC: err in setting multicast filter\n");
|
||||
return;
|
||||
}
|
||||
for (regs = 0; regs < numhashregs; regs++)
|
||||
writel(mcfilterbits[regs],
|
||||
ioaddr + GMAC_EXTHASH_BASE + regs * 4);
|
||||
}
|
||||
|
||||
static void dwmac1000_set_filter(struct mac_device_info *hw,
|
||||
struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = (void __iomem *)dev->base_addr;
|
||||
unsigned int value = 0;
|
||||
unsigned int perfect_addr_number = hw->unicast_filter_entries;
|
||||
u32 mc_filter[8];
|
||||
int mcbitslog2 = hw->mcast_bits_log2;
|
||||
|
||||
pr_debug("%s: # mcasts %d, # unicast %d\n", __func__,
|
||||
netdev_mc_count(dev), netdev_uc_count(dev));
|
||||
|
||||
memset(mc_filter, 0, sizeof(mc_filter));
|
||||
|
||||
if (dev->flags & IFF_PROMISC) {
|
||||
value = GMAC_FRAME_FILTER_PR | GMAC_FRAME_FILTER_PCF;
|
||||
} else if (dev->flags & IFF_ALLMULTI) {
|
||||
value = GMAC_FRAME_FILTER_PM; /* pass all multi */
|
||||
} else if (!netdev_mc_empty(dev) && (mcbitslog2 == 0)) {
|
||||
/* Fall back to all multicast if we've no filter */
|
||||
value = GMAC_FRAME_FILTER_PM;
|
||||
} else if (!netdev_mc_empty(dev)) {
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
/* Hash filter for multicast */
|
||||
value = GMAC_FRAME_FILTER_HMC;
|
||||
|
||||
netdev_for_each_mc_addr(ha, dev) {
|
||||
/* The upper n bits of the calculated CRC are used to
|
||||
* index the contents of the hash table. The number of
|
||||
* bits used depends on the hardware configuration
|
||||
* selected at core configuration time.
|
||||
*/
|
||||
int bit_nr = bitrev32(~crc32_le(~0, ha->addr,
|
||||
ETH_ALEN)) >>
|
||||
(32 - mcbitslog2);
|
||||
/* The most significant bit determines the register to
|
||||
* use (H/L) while the other 5 bits determine the bit
|
||||
* within the register.
|
||||
*/
|
||||
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
|
||||
}
|
||||
}
|
||||
|
||||
value |= GMAC_FRAME_FILTER_HPF;
|
||||
dwmac1000_set_mchash(ioaddr, mc_filter, mcbitslog2);
|
||||
|
||||
/* Handle multiple unicast addresses (perfect filtering) */
|
||||
if (netdev_uc_count(dev) > perfect_addr_number)
|
||||
/* Switch to promiscuous mode if more than unicast
|
||||
* addresses are requested than supported by hardware.
|
||||
*/
|
||||
value |= GMAC_FRAME_FILTER_PR;
|
||||
else {
|
||||
int reg = 1;
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
netdev_for_each_uc_addr(ha, dev) {
|
||||
stmmac_set_mac_addr(ioaddr, ha->addr,
|
||||
GMAC_ADDR_HIGH(reg),
|
||||
GMAC_ADDR_LOW(reg));
|
||||
reg++;
|
||||
}
|
||||
|
||||
while (reg < perfect_addr_number) {
|
||||
writel(0, ioaddr + GMAC_ADDR_HIGH(reg));
|
||||
writel(0, ioaddr + GMAC_ADDR_LOW(reg));
|
||||
reg++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FRAME_FILTER_DEBUG
|
||||
/* Enable Receive all mode (to debug filtering_fail errors) */
|
||||
value |= GMAC_FRAME_FILTER_RA;
|
||||
#endif
|
||||
writel(value, ioaddr + GMAC_FRAME_FILTER);
|
||||
}
|
||||
|
||||
|
||||
static void dwmac1000_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
|
||||
unsigned int fc, unsigned int pause_time,
|
||||
u32 tx_cnt)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
/* Set flow such that DZPQ in Mac Register 6 is 0,
|
||||
* and unicast pause detect is enabled.
|
||||
*/
|
||||
unsigned int flow = GMAC_FLOW_CTRL_UP;
|
||||
|
||||
pr_debug("GMAC Flow-Control:\n");
|
||||
if (fc & FLOW_RX) {
|
||||
pr_debug("\tReceive Flow-Control ON\n");
|
||||
flow |= GMAC_FLOW_CTRL_RFE;
|
||||
}
|
||||
if (fc & FLOW_TX) {
|
||||
pr_debug("\tTransmit Flow-Control ON\n");
|
||||
flow |= GMAC_FLOW_CTRL_TFE;
|
||||
}
|
||||
|
||||
if (duplex) {
|
||||
pr_debug("\tduplex mode: PAUSE %d\n", pause_time);
|
||||
flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
|
||||
}
|
||||
|
||||
writel(flow, ioaddr + GMAC_FLOW_CTRL);
|
||||
}
|
||||
|
||||
static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
unsigned int pmt = 0;
|
||||
|
||||
if (mode & WAKE_MAGIC) {
|
||||
pr_debug("GMAC: WOL Magic frame\n");
|
||||
pmt |= power_down | magic_pkt_en;
|
||||
}
|
||||
if (mode & WAKE_UCAST) {
|
||||
pr_debug("GMAC: WOL on global unicast\n");
|
||||
pmt |= power_down | global_unicast | wake_up_frame_en;
|
||||
}
|
||||
|
||||
writel(pmt, ioaddr + GMAC_PMT);
|
||||
}
|
||||
|
||||
/* RGMII or SMII interface */
|
||||
static void dwmac1000_rgsmii(void __iomem *ioaddr, struct stmmac_extra_stats *x)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
status = readl(ioaddr + GMAC_RGSMIIIS);
|
||||
x->irq_rgmii_n++;
|
||||
|
||||
/* Check the link status */
|
||||
if (status & GMAC_RGSMIIIS_LNKSTS) {
|
||||
int speed_value;
|
||||
|
||||
x->pcs_link = 1;
|
||||
|
||||
speed_value = ((status & GMAC_RGSMIIIS_SPEED) >>
|
||||
GMAC_RGSMIIIS_SPEED_SHIFT);
|
||||
if (speed_value == GMAC_RGSMIIIS_SPEED_125)
|
||||
x->pcs_speed = SPEED_1000;
|
||||
else if (speed_value == GMAC_RGSMIIIS_SPEED_25)
|
||||
x->pcs_speed = SPEED_100;
|
||||
else
|
||||
x->pcs_speed = SPEED_10;
|
||||
|
||||
x->pcs_duplex = (status & GMAC_RGSMIIIS_LNKMOD_MASK);
|
||||
|
||||
pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed,
|
||||
x->pcs_duplex ? "Full" : "Half");
|
||||
} else {
|
||||
x->pcs_link = 0;
|
||||
pr_info("Link is Down\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int dwmac1000_irq_status(struct mac_device_info *hw,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
|
||||
u32 intr_mask = readl(ioaddr + GMAC_INT_MASK);
|
||||
int ret = 0;
|
||||
|
||||
/* Discard masked bits */
|
||||
intr_status &= ~intr_mask;
|
||||
|
||||
/* Not used events (e.g. MMC interrupts) are not handled. */
|
||||
if ((intr_status & GMAC_INT_STATUS_MMCTIS))
|
||||
x->mmc_tx_irq_n++;
|
||||
if (unlikely(intr_status & GMAC_INT_STATUS_MMCRIS))
|
||||
x->mmc_rx_irq_n++;
|
||||
if (unlikely(intr_status & GMAC_INT_STATUS_MMCCSUM))
|
||||
x->mmc_rx_csum_offload_irq_n++;
|
||||
if (unlikely(intr_status & GMAC_INT_DISABLE_PMT)) {
|
||||
/* clear the PMT bits 5 and 6 by reading the PMT status reg */
|
||||
readl(ioaddr + GMAC_PMT);
|
||||
x->irq_receive_pmt_irq_n++;
|
||||
}
|
||||
|
||||
/* MAC tx/rx EEE LPI entry/exit interrupts */
|
||||
if (intr_status & GMAC_INT_STATUS_LPIIS) {
|
||||
/* Clean LPI interrupt by reading the Reg 12 */
|
||||
ret = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
|
||||
if (ret & LPI_CTRL_STATUS_TLPIEN)
|
||||
x->irq_tx_path_in_lpi_mode_n++;
|
||||
if (ret & LPI_CTRL_STATUS_TLPIEX)
|
||||
x->irq_tx_path_exit_lpi_mode_n++;
|
||||
if (ret & LPI_CTRL_STATUS_RLPIEN)
|
||||
x->irq_rx_path_in_lpi_mode_n++;
|
||||
if (ret & LPI_CTRL_STATUS_RLPIEX)
|
||||
x->irq_rx_path_exit_lpi_mode_n++;
|
||||
}
|
||||
|
||||
dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
|
||||
|
||||
if (intr_status & PCS_RGSMIIIS_IRQ)
|
||||
dwmac1000_rgsmii(ioaddr, x);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwmac1000_set_eee_mode(struct mac_device_info *hw,
|
||||
bool en_tx_lpi_clockgating)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value;
|
||||
|
||||
/*TODO - en_tx_lpi_clockgating treatment */
|
||||
|
||||
/* Enable the link status receive on RGMII, SGMII ore SMII
|
||||
* receive path and instruct the transmit to enter in LPI
|
||||
* state.
|
||||
*/
|
||||
value = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
|
||||
writel(value, ioaddr + LPI_CTRL_STATUS);
|
||||
}
|
||||
|
||||
static void dwmac1000_reset_eee_mode(struct mac_device_info *hw)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
value &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA);
|
||||
writel(value, ioaddr + LPI_CTRL_STATUS);
|
||||
}
|
||||
|
||||
static void dwmac1000_set_eee_pls(struct mac_device_info *hw, int link)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
|
||||
if (link)
|
||||
value |= LPI_CTRL_STATUS_PLS;
|
||||
else
|
||||
value &= ~LPI_CTRL_STATUS_PLS;
|
||||
|
||||
writel(value, ioaddr + LPI_CTRL_STATUS);
|
||||
}
|
||||
|
||||
static void dwmac1000_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
|
||||
|
||||
/* Program the timers in the LPI timer control register:
|
||||
* LS: minimum time (ms) for which the link
|
||||
* status from PHY should be ok before transmitting
|
||||
* the LPI pattern.
|
||||
* TW: minimum time (us) for which the core waits
|
||||
* after it has stopped transmitting the LPI pattern.
|
||||
*/
|
||||
writel(value, ioaddr + LPI_TIMER_CTRL);
|
||||
}
|
||||
|
||||
static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool ane, bool srgmi_ral,
|
||||
bool loopback)
|
||||
{
|
||||
dwmac_ctrl_ane(ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback);
|
||||
}
|
||||
|
||||
static void dwmac1000_get_adv_lp(void __iomem *ioaddr, struct rgmii_adv *adv)
|
||||
{
|
||||
dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv);
|
||||
}
|
||||
|
||||
static void dwmac1000_debug(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x,
|
||||
u32 rx_queues, u32 tx_queues)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_DEBUG);
|
||||
|
||||
if (value & GMAC_DEBUG_TXSTSFSTS)
|
||||
x->mtl_tx_status_fifo_full++;
|
||||
if (value & GMAC_DEBUG_TXFSTS)
|
||||
x->mtl_tx_fifo_not_empty++;
|
||||
if (value & GMAC_DEBUG_TWCSTS)
|
||||
x->mmtl_fifo_ctrl++;
|
||||
if (value & GMAC_DEBUG_TRCSTS_MASK) {
|
||||
u32 trcsts = (value & GMAC_DEBUG_TRCSTS_MASK)
|
||||
>> GMAC_DEBUG_TRCSTS_SHIFT;
|
||||
if (trcsts == GMAC_DEBUG_TRCSTS_WRITE)
|
||||
x->mtl_tx_fifo_read_ctrl_write++;
|
||||
else if (trcsts == GMAC_DEBUG_TRCSTS_TXW)
|
||||
x->mtl_tx_fifo_read_ctrl_wait++;
|
||||
else if (trcsts == GMAC_DEBUG_TRCSTS_READ)
|
||||
x->mtl_tx_fifo_read_ctrl_read++;
|
||||
else
|
||||
x->mtl_tx_fifo_read_ctrl_idle++;
|
||||
}
|
||||
if (value & GMAC_DEBUG_TXPAUSED)
|
||||
x->mac_tx_in_pause++;
|
||||
if (value & GMAC_DEBUG_TFCSTS_MASK) {
|
||||
u32 tfcsts = (value & GMAC_DEBUG_TFCSTS_MASK)
|
||||
>> GMAC_DEBUG_TFCSTS_SHIFT;
|
||||
|
||||
if (tfcsts == GMAC_DEBUG_TFCSTS_XFER)
|
||||
x->mac_tx_frame_ctrl_xfer++;
|
||||
else if (tfcsts == GMAC_DEBUG_TFCSTS_GEN_PAUSE)
|
||||
x->mac_tx_frame_ctrl_pause++;
|
||||
else if (tfcsts == GMAC_DEBUG_TFCSTS_WAIT)
|
||||
x->mac_tx_frame_ctrl_wait++;
|
||||
else
|
||||
x->mac_tx_frame_ctrl_idle++;
|
||||
}
|
||||
if (value & GMAC_DEBUG_TPESTS)
|
||||
x->mac_gmii_tx_proto_engine++;
|
||||
if (value & GMAC_DEBUG_RXFSTS_MASK) {
|
||||
u32 rxfsts = (value & GMAC_DEBUG_RXFSTS_MASK)
|
||||
>> GMAC_DEBUG_RRCSTS_SHIFT;
|
||||
|
||||
if (rxfsts == GMAC_DEBUG_RXFSTS_FULL)
|
||||
x->mtl_rx_fifo_fill_level_full++;
|
||||
else if (rxfsts == GMAC_DEBUG_RXFSTS_AT)
|
||||
x->mtl_rx_fifo_fill_above_thresh++;
|
||||
else if (rxfsts == GMAC_DEBUG_RXFSTS_BT)
|
||||
x->mtl_rx_fifo_fill_below_thresh++;
|
||||
else
|
||||
x->mtl_rx_fifo_fill_level_empty++;
|
||||
}
|
||||
if (value & GMAC_DEBUG_RRCSTS_MASK) {
|
||||
u32 rrcsts = (value & GMAC_DEBUG_RRCSTS_MASK) >>
|
||||
GMAC_DEBUG_RRCSTS_SHIFT;
|
||||
|
||||
if (rrcsts == GMAC_DEBUG_RRCSTS_FLUSH)
|
||||
x->mtl_rx_fifo_read_ctrl_flush++;
|
||||
else if (rrcsts == GMAC_DEBUG_RRCSTS_RSTAT)
|
||||
x->mtl_rx_fifo_read_ctrl_read_data++;
|
||||
else if (rrcsts == GMAC_DEBUG_RRCSTS_RDATA)
|
||||
x->mtl_rx_fifo_read_ctrl_status++;
|
||||
else
|
||||
x->mtl_rx_fifo_read_ctrl_idle++;
|
||||
}
|
||||
if (value & GMAC_DEBUG_RWCSTS)
|
||||
x->mtl_rx_fifo_ctrl_active++;
|
||||
if (value & GMAC_DEBUG_RFCFCSTS_MASK)
|
||||
x->mac_rx_frame_ctrl_fifo = (value & GMAC_DEBUG_RFCFCSTS_MASK)
|
||||
>> GMAC_DEBUG_RFCFCSTS_SHIFT;
|
||||
if (value & GMAC_DEBUG_RPESTS)
|
||||
x->mac_gmii_rx_proto_engine++;
|
||||
}
|
||||
|
||||
static void dwmac1000_set_mac_loopback(void __iomem *ioaddr, bool enable)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_CONTROL);
|
||||
|
||||
if (enable)
|
||||
value |= GMAC_CONTROL_LM;
|
||||
else
|
||||
value &= ~GMAC_CONTROL_LM;
|
||||
|
||||
writel(value, ioaddr + GMAC_CONTROL);
|
||||
}
|
||||
|
||||
const struct stmmac_ops dwmac1000_ops = {
|
||||
.core_init = dwmac1000_core_init,
|
||||
.set_mac = stmmac_set_mac,
|
||||
.rx_ipc = dwmac1000_rx_ipc_enable,
|
||||
.dump_regs = dwmac1000_dump_regs,
|
||||
.host_irq_status = dwmac1000_irq_status,
|
||||
.set_filter = dwmac1000_set_filter,
|
||||
.flow_ctrl = dwmac1000_flow_ctrl,
|
||||
.pmt = dwmac1000_pmt,
|
||||
.set_umac_addr = dwmac1000_set_umac_addr,
|
||||
.get_umac_addr = dwmac1000_get_umac_addr,
|
||||
.set_eee_mode = dwmac1000_set_eee_mode,
|
||||
.reset_eee_mode = dwmac1000_reset_eee_mode,
|
||||
.set_eee_timer = dwmac1000_set_eee_timer,
|
||||
.set_eee_pls = dwmac1000_set_eee_pls,
|
||||
.debug = dwmac1000_debug,
|
||||
.pcs_ctrl_ane = dwmac1000_ctrl_ane,
|
||||
.pcs_get_adv_lp = dwmac1000_get_adv_lp,
|
||||
.set_mac_loopback = dwmac1000_set_mac_loopback,
|
||||
};
|
||||
|
||||
int dwmac1000_setup(struct stmmac_priv *priv)
|
||||
{
|
||||
struct mac_device_info *mac = priv->hw;
|
||||
|
||||
dev_info(priv->device, "\tDWMAC1000\n");
|
||||
|
||||
priv->dev->priv_flags |= IFF_UNICAST_FLT;
|
||||
mac->pcsr = priv->ioaddr;
|
||||
mac->multicast_filter_bins = priv->plat->multicast_filter_bins;
|
||||
mac->unicast_filter_entries = priv->plat->unicast_filter_entries;
|
||||
mac->mcast_bits_log2 = 0;
|
||||
|
||||
if (mac->multicast_filter_bins)
|
||||
mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins);
|
||||
|
||||
mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
|
||||
MAC_10 | MAC_100 | MAC_1000;
|
||||
mac->link.duplex = GMAC_CONTROL_DM;
|
||||
mac->link.speed10 = GMAC_CONTROL_PS;
|
||||
mac->link.speed100 = GMAC_CONTROL_PS | GMAC_CONTROL_FES;
|
||||
mac->link.speed1000 = 0;
|
||||
mac->link.speed_mask = GMAC_CONTROL_PS | GMAC_CONTROL_FES;
|
||||
mac->mii.addr = GMAC_MII_ADDR;
|
||||
mac->mii.data = GMAC_MII_DATA;
|
||||
mac->mii.addr_shift = 11;
|
||||
mac->mii.addr_mask = 0x0000F800;
|
||||
mac->mii.reg_shift = 6;
|
||||
mac->mii.reg_mask = 0x000007C0;
|
||||
mac->mii.clk_csr_shift = 2;
|
||||
mac->mii.clk_csr_mask = GENMASK(5, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
|
||||
DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
|
||||
developing this code.
|
||||
|
||||
This contains the functions to handle the dma.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include "dwmac1000-6.12-ethercat.h"
|
||||
#include "dwmac_dma-6.12-ethercat.h"
|
||||
|
||||
static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_AXI_BUS_MODE);
|
||||
int i;
|
||||
|
||||
pr_info("dwmac1000: Master AXI performs %s burst length\n",
|
||||
!(value & DMA_AXI_UNDEF) ? "fixed" : "any");
|
||||
|
||||
if (axi->axi_lpi_en)
|
||||
value |= DMA_AXI_EN_LPI;
|
||||
if (axi->axi_xit_frm)
|
||||
value |= DMA_AXI_LPI_XIT_FRM;
|
||||
|
||||
value &= ~DMA_AXI_WR_OSR_LMT;
|
||||
value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR_LMT_MASK) <<
|
||||
DMA_AXI_WR_OSR_LMT_SHIFT;
|
||||
|
||||
value &= ~DMA_AXI_RD_OSR_LMT;
|
||||
value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR_LMT_MASK) <<
|
||||
DMA_AXI_RD_OSR_LMT_SHIFT;
|
||||
|
||||
/* Depending on the UNDEF bit the Master AXI will perform any burst
|
||||
* length according to the BLEN programmed (by default all BLEN are
|
||||
* set).
|
||||
*/
|
||||
for (i = 0; i < AXI_BLEN; i++) {
|
||||
switch (axi->axi_blen[i]) {
|
||||
case 256:
|
||||
value |= DMA_AXI_BLEN256;
|
||||
break;
|
||||
case 128:
|
||||
value |= DMA_AXI_BLEN128;
|
||||
break;
|
||||
case 64:
|
||||
value |= DMA_AXI_BLEN64;
|
||||
break;
|
||||
case 32:
|
||||
value |= DMA_AXI_BLEN32;
|
||||
break;
|
||||
case 16:
|
||||
value |= DMA_AXI_BLEN16;
|
||||
break;
|
||||
case 8:
|
||||
value |= DMA_AXI_BLEN8;
|
||||
break;
|
||||
case 4:
|
||||
value |= DMA_AXI_BLEN4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writel(value, ioaddr + DMA_AXI_BUS_MODE);
|
||||
}
|
||||
|
||||
static void dwmac1000_dma_init_channel(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg, u32 chan)
|
||||
{
|
||||
int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
|
||||
int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + DMA_CHAN_BUS_MODE(chan));
|
||||
|
||||
/* Set the DMA PBL (Programmable Burst Length) mode.
|
||||
*
|
||||
* Note: before stmmac core 3.50 this mode bit was 4xPBL, and
|
||||
* post 3.5 mode bit acts as 8*PBL.
|
||||
*/
|
||||
if (dma_cfg->pblx8)
|
||||
value |= DMA_BUS_MODE_MAXPBL;
|
||||
value |= DMA_BUS_MODE_USP;
|
||||
value &= ~(DMA_BUS_MODE_PBL_MASK | DMA_BUS_MODE_RPBL_MASK);
|
||||
value |= (txpbl << DMA_BUS_MODE_PBL_SHIFT);
|
||||
value |= (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
|
||||
|
||||
/* Set the Fixed burst mode */
|
||||
if (dma_cfg->fixed_burst)
|
||||
value |= DMA_BUS_MODE_FB;
|
||||
|
||||
/* Mixed Burst has no effect when fb is set */
|
||||
if (dma_cfg->mixed_burst)
|
||||
value |= DMA_BUS_MODE_MB;
|
||||
|
||||
if (dma_cfg->atds)
|
||||
value |= DMA_BUS_MODE_ATDS;
|
||||
|
||||
if (dma_cfg->aal)
|
||||
value |= DMA_BUS_MODE_AAL;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_BUS_MODE(chan));
|
||||
|
||||
/* Mask interrupts by writing to CSR7 */
|
||||
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_CHAN_INTR_ENA(chan));
|
||||
}
|
||||
|
||||
static void dwmac1000_dma_init_rx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t dma_rx_phy, u32 chan)
|
||||
{
|
||||
/* RX descriptor base address list must be written into DMA CSR3 */
|
||||
writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_CHAN_RCV_BASE_ADDR(chan));
|
||||
}
|
||||
|
||||
static void dwmac1000_dma_init_tx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t dma_tx_phy, u32 chan)
|
||||
{
|
||||
/* TX descriptor base address list must be written into DMA CSR4 */
|
||||
writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_CHAN_TX_BASE_ADDR(chan));
|
||||
}
|
||||
|
||||
static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)
|
||||
{
|
||||
csr6 &= ~DMA_CONTROL_RFA_MASK;
|
||||
csr6 &= ~DMA_CONTROL_RFD_MASK;
|
||||
|
||||
/* Leave flow control disabled if receive fifo size is less than
|
||||
* 4K or 0. Otherwise, send XOFF when fifo is 1K less than full,
|
||||
* and send XON when 2K less than full.
|
||||
*/
|
||||
if (rxfifosz < 4096) {
|
||||
csr6 &= ~DMA_CONTROL_EFC;
|
||||
pr_debug("GMAC: disabling flow control, rxfifo too small(%d)\n",
|
||||
rxfifosz);
|
||||
} else {
|
||||
csr6 |= DMA_CONTROL_EFC;
|
||||
csr6 |= RFA_FULL_MINUS_1K;
|
||||
csr6 |= RFD_FULL_MINUS_2K;
|
||||
}
|
||||
return csr6;
|
||||
}
|
||||
|
||||
static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, int mode,
|
||||
u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
|
||||
|
||||
if (mode == SF_DMA_MODE) {
|
||||
pr_debug("GMAC: enable RX store and forward mode\n");
|
||||
csr6 |= DMA_CONTROL_RSF;
|
||||
} else {
|
||||
pr_debug("GMAC: disable RX SF mode (threshold %d)\n", mode);
|
||||
csr6 &= ~DMA_CONTROL_RSF;
|
||||
csr6 &= DMA_CONTROL_TC_RX_MASK;
|
||||
if (mode <= 32)
|
||||
csr6 |= DMA_CONTROL_RTC_32;
|
||||
else if (mode <= 64)
|
||||
csr6 |= DMA_CONTROL_RTC_64;
|
||||
else if (mode <= 96)
|
||||
csr6 |= DMA_CONTROL_RTC_96;
|
||||
else
|
||||
csr6 |= DMA_CONTROL_RTC_128;
|
||||
}
|
||||
|
||||
/* Configure flow control based on rx fifo size */
|
||||
csr6 = dwmac1000_configure_fc(csr6, fifosz);
|
||||
|
||||
writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
|
||||
}
|
||||
|
||||
static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, int mode,
|
||||
u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
|
||||
|
||||
if (mode == SF_DMA_MODE) {
|
||||
pr_debug("GMAC: enable TX store and forward mode\n");
|
||||
/* Transmit COE type 2 cannot be done in cut-through mode. */
|
||||
csr6 |= DMA_CONTROL_TSF;
|
||||
/* Operating on second frame increase the performance
|
||||
* especially when transmit store-and-forward is used.
|
||||
*/
|
||||
csr6 |= DMA_CONTROL_OSF;
|
||||
} else {
|
||||
pr_debug("GMAC: disabling TX SF (threshold %d)\n", mode);
|
||||
csr6 &= ~DMA_CONTROL_TSF;
|
||||
csr6 &= DMA_CONTROL_TC_TX_MASK;
|
||||
/* Set the transmit threshold */
|
||||
if (mode <= 32)
|
||||
csr6 |= DMA_CONTROL_TTC_32;
|
||||
else if (mode <= 64)
|
||||
csr6 |= DMA_CONTROL_TTC_64;
|
||||
else if (mode <= 128)
|
||||
csr6 |= DMA_CONTROL_TTC_128;
|
||||
else if (mode <= 192)
|
||||
csr6 |= DMA_CONTROL_TTC_192;
|
||||
else
|
||||
csr6 |= DMA_CONTROL_TTC_256;
|
||||
}
|
||||
|
||||
writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
|
||||
}
|
||||
|
||||
static void dwmac1000_dump_dma_regs(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 *reg_space)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_DWMAC1000_DMA_REGS; i++)
|
||||
if ((i < 12) || (i > 17))
|
||||
reg_space[DMA_BUS_MODE / 4 + i] =
|
||||
readl(ioaddr + DMA_BUS_MODE + i * 4);
|
||||
}
|
||||
|
||||
static int dwmac1000_get_hw_feature(void __iomem *ioaddr,
|
||||
struct dma_features *dma_cap)
|
||||
{
|
||||
u32 hw_cap = readl(ioaddr + DMA_HW_FEATURE);
|
||||
|
||||
if (!hw_cap) {
|
||||
/* 0x00000000 is the value read on old hardware that does not
|
||||
* implement this register
|
||||
*/
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
dma_cap->mbps_10_100 = (hw_cap & DMA_HW_FEAT_MIISEL);
|
||||
dma_cap->mbps_1000 = (hw_cap & DMA_HW_FEAT_GMIISEL) >> 1;
|
||||
dma_cap->half_duplex = (hw_cap & DMA_HW_FEAT_HDSEL) >> 2;
|
||||
dma_cap->hash_filter = (hw_cap & DMA_HW_FEAT_HASHSEL) >> 4;
|
||||
dma_cap->multi_addr = (hw_cap & DMA_HW_FEAT_ADDMAC) >> 5;
|
||||
dma_cap->pcs = (hw_cap & DMA_HW_FEAT_PCSSEL) >> 6;
|
||||
dma_cap->sma_mdio = (hw_cap & DMA_HW_FEAT_SMASEL) >> 8;
|
||||
dma_cap->pmt_remote_wake_up = (hw_cap & DMA_HW_FEAT_RWKSEL) >> 9;
|
||||
dma_cap->pmt_magic_frame = (hw_cap & DMA_HW_FEAT_MGKSEL) >> 10;
|
||||
/* MMC */
|
||||
dma_cap->rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11;
|
||||
/* IEEE 1588-2002 */
|
||||
dma_cap->time_stamp =
|
||||
(hw_cap & DMA_HW_FEAT_TSVER1SEL) >> 12;
|
||||
/* IEEE 1588-2008 */
|
||||
dma_cap->atime_stamp = (hw_cap & DMA_HW_FEAT_TSVER2SEL) >> 13;
|
||||
/* 802.3az - Energy-Efficient Ethernet (EEE) */
|
||||
dma_cap->eee = (hw_cap & DMA_HW_FEAT_EEESEL) >> 14;
|
||||
dma_cap->av = (hw_cap & DMA_HW_FEAT_AVSEL) >> 15;
|
||||
/* TX and RX csum */
|
||||
dma_cap->tx_coe = (hw_cap & DMA_HW_FEAT_TXCOESEL) >> 16;
|
||||
dma_cap->rx_coe_type1 = (hw_cap & DMA_HW_FEAT_RXTYP1COE) >> 17;
|
||||
dma_cap->rx_coe_type2 = (hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18;
|
||||
dma_cap->rxfifo_over_2048 = (hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19;
|
||||
/* TX and RX number of channels */
|
||||
dma_cap->number_rx_channel = (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
|
||||
dma_cap->number_tx_channel = (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
|
||||
/* Alternate (enhanced) DESC mode */
|
||||
dma_cap->enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwmac1000_rx_watchdog(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 riwt, u32 queue)
|
||||
{
|
||||
writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(queue));
|
||||
}
|
||||
|
||||
const struct stmmac_dma_ops dwmac1000_dma_ops = {
|
||||
.reset = dwmac_dma_reset,
|
||||
.init_chan = dwmac1000_dma_init_channel,
|
||||
.init_rx_chan = dwmac1000_dma_init_rx,
|
||||
.init_tx_chan = dwmac1000_dma_init_tx,
|
||||
.axi = dwmac1000_dma_axi,
|
||||
.dump_regs = dwmac1000_dump_dma_regs,
|
||||
.dma_rx_mode = dwmac1000_dma_operation_mode_rx,
|
||||
.dma_tx_mode = dwmac1000_dma_operation_mode_tx,
|
||||
.enable_dma_transmission = dwmac_enable_dma_transmission,
|
||||
.enable_dma_irq = dwmac_enable_dma_irq,
|
||||
.disable_dma_irq = dwmac_disable_dma_irq,
|
||||
.start_tx = dwmac_dma_start_tx,
|
||||
.stop_tx = dwmac_dma_stop_tx,
|
||||
.start_rx = dwmac_dma_start_rx,
|
||||
.stop_rx = dwmac_dma_stop_rx,
|
||||
.dma_interrupt = dwmac_dma_interrupt,
|
||||
.get_hw_feature = dwmac1000_get_hw_feature,
|
||||
.rx_watchdog = dwmac1000_rx_watchdog,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(dwmac1000_dma_ops);
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
|
||||
DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
|
||||
developing this code.
|
||||
|
||||
This contains the functions to handle the dma.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include "dwmac1000.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_AXI_BUS_MODE);
|
||||
int i;
|
||||
|
||||
pr_info("dwmac1000: Master AXI performs %s burst length\n",
|
||||
!(value & DMA_AXI_UNDEF) ? "fixed" : "any");
|
||||
|
||||
if (axi->axi_lpi_en)
|
||||
value |= DMA_AXI_EN_LPI;
|
||||
if (axi->axi_xit_frm)
|
||||
value |= DMA_AXI_LPI_XIT_FRM;
|
||||
|
||||
value &= ~DMA_AXI_WR_OSR_LMT;
|
||||
value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR_LMT_MASK) <<
|
||||
DMA_AXI_WR_OSR_LMT_SHIFT;
|
||||
|
||||
value &= ~DMA_AXI_RD_OSR_LMT;
|
||||
value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR_LMT_MASK) <<
|
||||
DMA_AXI_RD_OSR_LMT_SHIFT;
|
||||
|
||||
/* Depending on the UNDEF bit the Master AXI will perform any burst
|
||||
* length according to the BLEN programmed (by default all BLEN are
|
||||
* set).
|
||||
*/
|
||||
for (i = 0; i < AXI_BLEN; i++) {
|
||||
switch (axi->axi_blen[i]) {
|
||||
case 256:
|
||||
value |= DMA_AXI_BLEN256;
|
||||
break;
|
||||
case 128:
|
||||
value |= DMA_AXI_BLEN128;
|
||||
break;
|
||||
case 64:
|
||||
value |= DMA_AXI_BLEN64;
|
||||
break;
|
||||
case 32:
|
||||
value |= DMA_AXI_BLEN32;
|
||||
break;
|
||||
case 16:
|
||||
value |= DMA_AXI_BLEN16;
|
||||
break;
|
||||
case 8:
|
||||
value |= DMA_AXI_BLEN8;
|
||||
break;
|
||||
case 4:
|
||||
value |= DMA_AXI_BLEN4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writel(value, ioaddr + DMA_AXI_BUS_MODE);
|
||||
}
|
||||
|
||||
static void dwmac1000_dma_init_channel(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg, u32 chan)
|
||||
{
|
||||
int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
|
||||
int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + DMA_CHAN_BUS_MODE(chan));
|
||||
|
||||
/* Set the DMA PBL (Programmable Burst Length) mode.
|
||||
*
|
||||
* Note: before stmmac core 3.50 this mode bit was 4xPBL, and
|
||||
* post 3.5 mode bit acts as 8*PBL.
|
||||
*/
|
||||
if (dma_cfg->pblx8)
|
||||
value |= DMA_BUS_MODE_MAXPBL;
|
||||
value |= DMA_BUS_MODE_USP;
|
||||
value &= ~(DMA_BUS_MODE_PBL_MASK | DMA_BUS_MODE_RPBL_MASK);
|
||||
value |= (txpbl << DMA_BUS_MODE_PBL_SHIFT);
|
||||
value |= (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
|
||||
|
||||
/* Set the Fixed burst mode */
|
||||
if (dma_cfg->fixed_burst)
|
||||
value |= DMA_BUS_MODE_FB;
|
||||
|
||||
/* Mixed Burst has no effect when fb is set */
|
||||
if (dma_cfg->mixed_burst)
|
||||
value |= DMA_BUS_MODE_MB;
|
||||
|
||||
if (dma_cfg->atds)
|
||||
value |= DMA_BUS_MODE_ATDS;
|
||||
|
||||
if (dma_cfg->aal)
|
||||
value |= DMA_BUS_MODE_AAL;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_BUS_MODE(chan));
|
||||
|
||||
/* Mask interrupts by writing to CSR7 */
|
||||
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_CHAN_INTR_ENA(chan));
|
||||
}
|
||||
|
||||
static void dwmac1000_dma_init_rx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t dma_rx_phy, u32 chan)
|
||||
{
|
||||
/* RX descriptor base address list must be written into DMA CSR3 */
|
||||
writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_CHAN_RCV_BASE_ADDR(chan));
|
||||
}
|
||||
|
||||
static void dwmac1000_dma_init_tx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t dma_tx_phy, u32 chan)
|
||||
{
|
||||
/* TX descriptor base address list must be written into DMA CSR4 */
|
||||
writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_CHAN_TX_BASE_ADDR(chan));
|
||||
}
|
||||
|
||||
static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)
|
||||
{
|
||||
csr6 &= ~DMA_CONTROL_RFA_MASK;
|
||||
csr6 &= ~DMA_CONTROL_RFD_MASK;
|
||||
|
||||
/* Leave flow control disabled if receive fifo size is less than
|
||||
* 4K or 0. Otherwise, send XOFF when fifo is 1K less than full,
|
||||
* and send XON when 2K less than full.
|
||||
*/
|
||||
if (rxfifosz < 4096) {
|
||||
csr6 &= ~DMA_CONTROL_EFC;
|
||||
pr_debug("GMAC: disabling flow control, rxfifo too small(%d)\n",
|
||||
rxfifosz);
|
||||
} else {
|
||||
csr6 |= DMA_CONTROL_EFC;
|
||||
csr6 |= RFA_FULL_MINUS_1K;
|
||||
csr6 |= RFD_FULL_MINUS_2K;
|
||||
}
|
||||
return csr6;
|
||||
}
|
||||
|
||||
static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, int mode,
|
||||
u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
|
||||
|
||||
if (mode == SF_DMA_MODE) {
|
||||
pr_debug("GMAC: enable RX store and forward mode\n");
|
||||
csr6 |= DMA_CONTROL_RSF;
|
||||
} else {
|
||||
pr_debug("GMAC: disable RX SF mode (threshold %d)\n", mode);
|
||||
csr6 &= ~DMA_CONTROL_RSF;
|
||||
csr6 &= DMA_CONTROL_TC_RX_MASK;
|
||||
if (mode <= 32)
|
||||
csr6 |= DMA_CONTROL_RTC_32;
|
||||
else if (mode <= 64)
|
||||
csr6 |= DMA_CONTROL_RTC_64;
|
||||
else if (mode <= 96)
|
||||
csr6 |= DMA_CONTROL_RTC_96;
|
||||
else
|
||||
csr6 |= DMA_CONTROL_RTC_128;
|
||||
}
|
||||
|
||||
/* Configure flow control based on rx fifo size */
|
||||
csr6 = dwmac1000_configure_fc(csr6, fifosz);
|
||||
|
||||
writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
|
||||
}
|
||||
|
||||
static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, int mode,
|
||||
u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
|
||||
|
||||
if (mode == SF_DMA_MODE) {
|
||||
pr_debug("GMAC: enable TX store and forward mode\n");
|
||||
/* Transmit COE type 2 cannot be done in cut-through mode. */
|
||||
csr6 |= DMA_CONTROL_TSF;
|
||||
/* Operating on second frame increase the performance
|
||||
* especially when transmit store-and-forward is used.
|
||||
*/
|
||||
csr6 |= DMA_CONTROL_OSF;
|
||||
} else {
|
||||
pr_debug("GMAC: disabling TX SF (threshold %d)\n", mode);
|
||||
csr6 &= ~DMA_CONTROL_TSF;
|
||||
csr6 &= DMA_CONTROL_TC_TX_MASK;
|
||||
/* Set the transmit threshold */
|
||||
if (mode <= 32)
|
||||
csr6 |= DMA_CONTROL_TTC_32;
|
||||
else if (mode <= 64)
|
||||
csr6 |= DMA_CONTROL_TTC_64;
|
||||
else if (mode <= 128)
|
||||
csr6 |= DMA_CONTROL_TTC_128;
|
||||
else if (mode <= 192)
|
||||
csr6 |= DMA_CONTROL_TTC_192;
|
||||
else
|
||||
csr6 |= DMA_CONTROL_TTC_256;
|
||||
}
|
||||
|
||||
writel(csr6, ioaddr + DMA_CHAN_CONTROL(channel));
|
||||
}
|
||||
|
||||
static void dwmac1000_dump_dma_regs(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 *reg_space)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_DWMAC1000_DMA_REGS; i++)
|
||||
if ((i < 12) || (i > 17))
|
||||
reg_space[DMA_BUS_MODE / 4 + i] =
|
||||
readl(ioaddr + DMA_BUS_MODE + i * 4);
|
||||
}
|
||||
|
||||
static int dwmac1000_get_hw_feature(void __iomem *ioaddr,
|
||||
struct dma_features *dma_cap)
|
||||
{
|
||||
u32 hw_cap = readl(ioaddr + DMA_HW_FEATURE);
|
||||
|
||||
if (!hw_cap) {
|
||||
/* 0x00000000 is the value read on old hardware that does not
|
||||
* implement this register
|
||||
*/
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
dma_cap->mbps_10_100 = (hw_cap & DMA_HW_FEAT_MIISEL);
|
||||
dma_cap->mbps_1000 = (hw_cap & DMA_HW_FEAT_GMIISEL) >> 1;
|
||||
dma_cap->half_duplex = (hw_cap & DMA_HW_FEAT_HDSEL) >> 2;
|
||||
dma_cap->hash_filter = (hw_cap & DMA_HW_FEAT_HASHSEL) >> 4;
|
||||
dma_cap->multi_addr = (hw_cap & DMA_HW_FEAT_ADDMAC) >> 5;
|
||||
dma_cap->pcs = (hw_cap & DMA_HW_FEAT_PCSSEL) >> 6;
|
||||
dma_cap->sma_mdio = (hw_cap & DMA_HW_FEAT_SMASEL) >> 8;
|
||||
dma_cap->pmt_remote_wake_up = (hw_cap & DMA_HW_FEAT_RWKSEL) >> 9;
|
||||
dma_cap->pmt_magic_frame = (hw_cap & DMA_HW_FEAT_MGKSEL) >> 10;
|
||||
/* MMC */
|
||||
dma_cap->rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11;
|
||||
/* IEEE 1588-2002 */
|
||||
dma_cap->time_stamp =
|
||||
(hw_cap & DMA_HW_FEAT_TSVER1SEL) >> 12;
|
||||
/* IEEE 1588-2008 */
|
||||
dma_cap->atime_stamp = (hw_cap & DMA_HW_FEAT_TSVER2SEL) >> 13;
|
||||
/* 802.3az - Energy-Efficient Ethernet (EEE) */
|
||||
dma_cap->eee = (hw_cap & DMA_HW_FEAT_EEESEL) >> 14;
|
||||
dma_cap->av = (hw_cap & DMA_HW_FEAT_AVSEL) >> 15;
|
||||
/* TX and RX csum */
|
||||
dma_cap->tx_coe = (hw_cap & DMA_HW_FEAT_TXCOESEL) >> 16;
|
||||
dma_cap->rx_coe_type1 = (hw_cap & DMA_HW_FEAT_RXTYP1COE) >> 17;
|
||||
dma_cap->rx_coe_type2 = (hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18;
|
||||
dma_cap->rxfifo_over_2048 = (hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19;
|
||||
/* TX and RX number of channels */
|
||||
dma_cap->number_rx_channel = (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
|
||||
dma_cap->number_tx_channel = (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
|
||||
/* Alternate (enhanced) DESC mode */
|
||||
dma_cap->enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwmac1000_rx_watchdog(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 riwt, u32 queue)
|
||||
{
|
||||
writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(queue));
|
||||
}
|
||||
|
||||
const struct stmmac_dma_ops dwmac1000_dma_ops = {
|
||||
.reset = dwmac_dma_reset,
|
||||
.init_chan = dwmac1000_dma_init_channel,
|
||||
.init_rx_chan = dwmac1000_dma_init_rx,
|
||||
.init_tx_chan = dwmac1000_dma_init_tx,
|
||||
.axi = dwmac1000_dma_axi,
|
||||
.dump_regs = dwmac1000_dump_dma_regs,
|
||||
.dma_rx_mode = dwmac1000_dma_operation_mode_rx,
|
||||
.dma_tx_mode = dwmac1000_dma_operation_mode_tx,
|
||||
.enable_dma_transmission = dwmac_enable_dma_transmission,
|
||||
.enable_dma_irq = dwmac_enable_dma_irq,
|
||||
.disable_dma_irq = dwmac_disable_dma_irq,
|
||||
.start_tx = dwmac_dma_start_tx,
|
||||
.stop_tx = dwmac_dma_stop_tx,
|
||||
.start_rx = dwmac_dma_start_rx,
|
||||
.stop_rx = dwmac_dma_stop_rx,
|
||||
.dma_interrupt = dwmac_dma_interrupt,
|
||||
.get_hw_feature = dwmac1000_get_hw_feature,
|
||||
.rx_watchdog = dwmac1000_rx_watchdog,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(dwmac1000_dma_ops);
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This is the driver for the MAC 10/100 on-chip Ethernet controller
|
||||
currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
|
||||
|
||||
DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
|
||||
this code.
|
||||
|
||||
This only implements the mac core functions for this chip.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/io.h>
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
#include "dwmac100-6.12-ethercat.h"
|
||||
|
||||
static void dwmac100_core_init(struct mac_device_info *hw,
|
||||
struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + MAC_CONTROL);
|
||||
|
||||
value |= MAC_CORE_INIT;
|
||||
|
||||
writel(value, ioaddr + MAC_CONTROL);
|
||||
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
writel(ETH_P_8021Q, ioaddr + MAC_VLAN1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dwmac100_dump_mac_regs(struct mac_device_info *hw, u32 *reg_space)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
|
||||
reg_space[MAC_CONTROL / 4] = readl(ioaddr + MAC_CONTROL);
|
||||
reg_space[MAC_ADDR_HIGH / 4] = readl(ioaddr + MAC_ADDR_HIGH);
|
||||
reg_space[MAC_ADDR_LOW / 4] = readl(ioaddr + MAC_ADDR_LOW);
|
||||
reg_space[MAC_HASH_HIGH / 4] = readl(ioaddr + MAC_HASH_HIGH);
|
||||
reg_space[MAC_HASH_LOW / 4] = readl(ioaddr + MAC_HASH_LOW);
|
||||
reg_space[MAC_FLOW_CTRL / 4] = readl(ioaddr + MAC_FLOW_CTRL);
|
||||
reg_space[MAC_VLAN1 / 4] = readl(ioaddr + MAC_VLAN1);
|
||||
reg_space[MAC_VLAN2 / 4] = readl(ioaddr + MAC_VLAN2);
|
||||
}
|
||||
|
||||
static int dwmac100_rx_ipc_enable(struct mac_device_info *hw)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwmac100_irq_status(struct mac_device_info *hw,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwmac100_set_umac_addr(struct mac_device_info *hw,
|
||||
const unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
|
||||
}
|
||||
|
||||
static void dwmac100_get_umac_addr(struct mac_device_info *hw,
|
||||
unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
|
||||
}
|
||||
|
||||
static void dwmac100_set_filter(struct mac_device_info *hw,
|
||||
struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = (void __iomem *)dev->base_addr;
|
||||
u32 value = readl(ioaddr + MAC_CONTROL);
|
||||
|
||||
if (dev->flags & IFF_PROMISC) {
|
||||
value |= MAC_CONTROL_PR;
|
||||
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO |
|
||||
MAC_CONTROL_HP);
|
||||
} else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
|
||||
|| (dev->flags & IFF_ALLMULTI)) {
|
||||
value |= MAC_CONTROL_PM;
|
||||
value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO);
|
||||
writel(0xffffffff, ioaddr + MAC_HASH_HIGH);
|
||||
writel(0xffffffff, ioaddr + MAC_HASH_LOW);
|
||||
} else if (netdev_mc_empty(dev)) { /* no multicast */
|
||||
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF |
|
||||
MAC_CONTROL_HO | MAC_CONTROL_HP);
|
||||
} else {
|
||||
u32 mc_filter[2];
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
/* Perfect filter mode for physical address and Hash
|
||||
* filter for multicast
|
||||
*/
|
||||
value |= MAC_CONTROL_HP;
|
||||
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR |
|
||||
MAC_CONTROL_IF | MAC_CONTROL_HO);
|
||||
|
||||
memset(mc_filter, 0, sizeof(mc_filter));
|
||||
netdev_for_each_mc_addr(ha, dev) {
|
||||
/* The upper 6 bits of the calculated CRC are used to
|
||||
* index the contens of the hash table
|
||||
*/
|
||||
int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
|
||||
/* The most significant bit determines the register to
|
||||
* use (H/L) while the other 5 bits determine the bit
|
||||
* within the register.
|
||||
*/
|
||||
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
|
||||
}
|
||||
writel(mc_filter[0], ioaddr + MAC_HASH_LOW);
|
||||
writel(mc_filter[1], ioaddr + MAC_HASH_HIGH);
|
||||
}
|
||||
|
||||
writel(value, ioaddr + MAC_CONTROL);
|
||||
}
|
||||
|
||||
static void dwmac100_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
|
||||
unsigned int fc, unsigned int pause_time,
|
||||
u32 tx_cnt)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
unsigned int flow = MAC_FLOW_CTRL_ENABLE;
|
||||
|
||||
if (duplex)
|
||||
flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT);
|
||||
writel(flow, ioaddr + MAC_FLOW_CTRL);
|
||||
}
|
||||
|
||||
/* No PMT module supported on ST boards with this Eth chip. */
|
||||
static void dwmac100_pmt(struct mac_device_info *hw, unsigned long mode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void dwmac100_set_mac_loopback(void __iomem *ioaddr, bool enable)
|
||||
{
|
||||
u32 value = readl(ioaddr + MAC_CONTROL);
|
||||
|
||||
if (enable)
|
||||
value |= MAC_CONTROL_OM;
|
||||
else
|
||||
value &= ~MAC_CONTROL_OM;
|
||||
|
||||
writel(value, ioaddr + MAC_CONTROL);
|
||||
}
|
||||
|
||||
const struct stmmac_ops dwmac100_ops = {
|
||||
.core_init = dwmac100_core_init,
|
||||
.set_mac = stmmac_set_mac,
|
||||
.rx_ipc = dwmac100_rx_ipc_enable,
|
||||
.dump_regs = dwmac100_dump_mac_regs,
|
||||
.host_irq_status = dwmac100_irq_status,
|
||||
.set_filter = dwmac100_set_filter,
|
||||
.flow_ctrl = dwmac100_flow_ctrl,
|
||||
.pmt = dwmac100_pmt,
|
||||
.set_umac_addr = dwmac100_set_umac_addr,
|
||||
.get_umac_addr = dwmac100_get_umac_addr,
|
||||
.set_mac_loopback = dwmac100_set_mac_loopback,
|
||||
};
|
||||
|
||||
int dwmac100_setup(struct stmmac_priv *priv)
|
||||
{
|
||||
struct mac_device_info *mac = priv->hw;
|
||||
|
||||
dev_info(priv->device, "\tDWMAC100\n");
|
||||
|
||||
mac->pcsr = priv->ioaddr;
|
||||
mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
|
||||
MAC_10 | MAC_100;
|
||||
mac->link.duplex = MAC_CONTROL_F;
|
||||
mac->link.speed10 = 0;
|
||||
mac->link.speed100 = 0;
|
||||
mac->link.speed1000 = 0;
|
||||
mac->link.speed_mask = MAC_CONTROL_PS;
|
||||
mac->mii.addr = MAC_MII_ADDR;
|
||||
mac->mii.data = MAC_MII_DATA;
|
||||
mac->mii.addr_shift = 11;
|
||||
mac->mii.addr_mask = 0x0000F800;
|
||||
mac->mii.reg_shift = 6;
|
||||
mac->mii.reg_mask = 0x000007C0;
|
||||
mac->mii.clk_csr_shift = 2;
|
||||
mac->mii.clk_csr_mask = GENMASK(5, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This is the driver for the MAC 10/100 on-chip Ethernet controller
|
||||
currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
|
||||
|
||||
DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
|
||||
this code.
|
||||
|
||||
This only implements the mac core functions for this chip.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/io.h>
|
||||
#include "stmmac.h"
|
||||
#include "dwmac100.h"
|
||||
|
||||
static void dwmac100_core_init(struct mac_device_info *hw,
|
||||
struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + MAC_CONTROL);
|
||||
|
||||
value |= MAC_CORE_INIT;
|
||||
|
||||
writel(value, ioaddr + MAC_CONTROL);
|
||||
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
writel(ETH_P_8021Q, ioaddr + MAC_VLAN1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dwmac100_dump_mac_regs(struct mac_device_info *hw, u32 *reg_space)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
|
||||
reg_space[MAC_CONTROL / 4] = readl(ioaddr + MAC_CONTROL);
|
||||
reg_space[MAC_ADDR_HIGH / 4] = readl(ioaddr + MAC_ADDR_HIGH);
|
||||
reg_space[MAC_ADDR_LOW / 4] = readl(ioaddr + MAC_ADDR_LOW);
|
||||
reg_space[MAC_HASH_HIGH / 4] = readl(ioaddr + MAC_HASH_HIGH);
|
||||
reg_space[MAC_HASH_LOW / 4] = readl(ioaddr + MAC_HASH_LOW);
|
||||
reg_space[MAC_FLOW_CTRL / 4] = readl(ioaddr + MAC_FLOW_CTRL);
|
||||
reg_space[MAC_VLAN1 / 4] = readl(ioaddr + MAC_VLAN1);
|
||||
reg_space[MAC_VLAN2 / 4] = readl(ioaddr + MAC_VLAN2);
|
||||
}
|
||||
|
||||
static int dwmac100_rx_ipc_enable(struct mac_device_info *hw)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwmac100_irq_status(struct mac_device_info *hw,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwmac100_set_umac_addr(struct mac_device_info *hw,
|
||||
const unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
|
||||
}
|
||||
|
||||
static void dwmac100_get_umac_addr(struct mac_device_info *hw,
|
||||
unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
|
||||
}
|
||||
|
||||
static void dwmac100_set_filter(struct mac_device_info *hw,
|
||||
struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = (void __iomem *)dev->base_addr;
|
||||
u32 value = readl(ioaddr + MAC_CONTROL);
|
||||
|
||||
if (dev->flags & IFF_PROMISC) {
|
||||
value |= MAC_CONTROL_PR;
|
||||
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO |
|
||||
MAC_CONTROL_HP);
|
||||
} else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
|
||||
|| (dev->flags & IFF_ALLMULTI)) {
|
||||
value |= MAC_CONTROL_PM;
|
||||
value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO);
|
||||
writel(0xffffffff, ioaddr + MAC_HASH_HIGH);
|
||||
writel(0xffffffff, ioaddr + MAC_HASH_LOW);
|
||||
} else if (netdev_mc_empty(dev)) { /* no multicast */
|
||||
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF |
|
||||
MAC_CONTROL_HO | MAC_CONTROL_HP);
|
||||
} else {
|
||||
u32 mc_filter[2];
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
/* Perfect filter mode for physical address and Hash
|
||||
* filter for multicast
|
||||
*/
|
||||
value |= MAC_CONTROL_HP;
|
||||
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR |
|
||||
MAC_CONTROL_IF | MAC_CONTROL_HO);
|
||||
|
||||
memset(mc_filter, 0, sizeof(mc_filter));
|
||||
netdev_for_each_mc_addr(ha, dev) {
|
||||
/* The upper 6 bits of the calculated CRC are used to
|
||||
* index the contens of the hash table
|
||||
*/
|
||||
int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
|
||||
/* The most significant bit determines the register to
|
||||
* use (H/L) while the other 5 bits determine the bit
|
||||
* within the register.
|
||||
*/
|
||||
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
|
||||
}
|
||||
writel(mc_filter[0], ioaddr + MAC_HASH_LOW);
|
||||
writel(mc_filter[1], ioaddr + MAC_HASH_HIGH);
|
||||
}
|
||||
|
||||
writel(value, ioaddr + MAC_CONTROL);
|
||||
}
|
||||
|
||||
static void dwmac100_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
|
||||
unsigned int fc, unsigned int pause_time,
|
||||
u32 tx_cnt)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
unsigned int flow = MAC_FLOW_CTRL_ENABLE;
|
||||
|
||||
if (duplex)
|
||||
flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT);
|
||||
writel(flow, ioaddr + MAC_FLOW_CTRL);
|
||||
}
|
||||
|
||||
/* No PMT module supported on ST boards with this Eth chip. */
|
||||
static void dwmac100_pmt(struct mac_device_info *hw, unsigned long mode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void dwmac100_set_mac_loopback(void __iomem *ioaddr, bool enable)
|
||||
{
|
||||
u32 value = readl(ioaddr + MAC_CONTROL);
|
||||
|
||||
if (enable)
|
||||
value |= MAC_CONTROL_OM;
|
||||
else
|
||||
value &= ~MAC_CONTROL_OM;
|
||||
|
||||
writel(value, ioaddr + MAC_CONTROL);
|
||||
}
|
||||
|
||||
const struct stmmac_ops dwmac100_ops = {
|
||||
.core_init = dwmac100_core_init,
|
||||
.set_mac = stmmac_set_mac,
|
||||
.rx_ipc = dwmac100_rx_ipc_enable,
|
||||
.dump_regs = dwmac100_dump_mac_regs,
|
||||
.host_irq_status = dwmac100_irq_status,
|
||||
.set_filter = dwmac100_set_filter,
|
||||
.flow_ctrl = dwmac100_flow_ctrl,
|
||||
.pmt = dwmac100_pmt,
|
||||
.set_umac_addr = dwmac100_set_umac_addr,
|
||||
.get_umac_addr = dwmac100_get_umac_addr,
|
||||
.set_mac_loopback = dwmac100_set_mac_loopback,
|
||||
};
|
||||
|
||||
int dwmac100_setup(struct stmmac_priv *priv)
|
||||
{
|
||||
struct mac_device_info *mac = priv->hw;
|
||||
|
||||
dev_info(priv->device, "\tDWMAC100\n");
|
||||
|
||||
mac->pcsr = priv->ioaddr;
|
||||
mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
|
||||
MAC_10 | MAC_100;
|
||||
mac->link.duplex = MAC_CONTROL_F;
|
||||
mac->link.speed10 = 0;
|
||||
mac->link.speed100 = 0;
|
||||
mac->link.speed1000 = 0;
|
||||
mac->link.speed_mask = MAC_CONTROL_PS;
|
||||
mac->mii.addr = MAC_MII_ADDR;
|
||||
mac->mii.data = MAC_MII_DATA;
|
||||
mac->mii.addr_shift = 11;
|
||||
mac->mii.addr_mask = 0x0000F800;
|
||||
mac->mii.reg_shift = 6;
|
||||
mac->mii.reg_mask = 0x000007C0;
|
||||
mac->mii.clk_csr_shift = 2;
|
||||
mac->mii.clk_csr_mask = GENMASK(5, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This is the driver for the MAC 10/100 on-chip Ethernet controller
|
||||
currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
|
||||
|
||||
DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
|
||||
this code.
|
||||
|
||||
This contains the functions to handle the dma.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include "dwmac100-6.12-ethercat.h"
|
||||
#include "dwmac_dma-6.12-ethercat.h"
|
||||
|
||||
static void dwmac100_dma_init(void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg)
|
||||
{
|
||||
/* Enable Application Access by writing to DMA CSR0 */
|
||||
writel(DMA_BUS_MODE_DEFAULT | (dma_cfg->pbl << DMA_BUS_MODE_PBL_SHIFT),
|
||||
ioaddr + DMA_BUS_MODE);
|
||||
|
||||
/* Mask interrupts by writing to CSR7 */
|
||||
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
|
||||
}
|
||||
|
||||
static void dwmac100_dma_init_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t dma_rx_phy, u32 chan)
|
||||
{
|
||||
/* RX descriptor base addr lists must be written into DMA CSR3 */
|
||||
writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR);
|
||||
}
|
||||
|
||||
static void dwmac100_dma_init_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t dma_tx_phy, u32 chan)
|
||||
{
|
||||
/* TX descriptor base addr lists must be written into DMA CSR4 */
|
||||
writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_TX_BASE_ADDR);
|
||||
}
|
||||
|
||||
/* Store and Forward capability is not used at all.
|
||||
*
|
||||
* The transmit threshold can be programmed by setting the TTC bits in the DMA
|
||||
* control register.
|
||||
*/
|
||||
static void dwmac100_dma_operation_mode_tx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, int mode,
|
||||
u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CONTROL);
|
||||
|
||||
if (mode <= 32)
|
||||
csr6 |= DMA_CONTROL_TTC_32;
|
||||
else if (mode <= 64)
|
||||
csr6 |= DMA_CONTROL_TTC_64;
|
||||
else
|
||||
csr6 |= DMA_CONTROL_TTC_128;
|
||||
|
||||
writel(csr6, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
static void dwmac100_dump_dma_regs(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 *reg_space)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_DWMAC100_DMA_REGS; i++)
|
||||
reg_space[DMA_BUS_MODE / 4 + i] =
|
||||
readl(ioaddr + DMA_BUS_MODE + i * 4);
|
||||
|
||||
reg_space[DMA_CUR_TX_BUF_ADDR / 4] =
|
||||
readl(ioaddr + DMA_CUR_TX_BUF_ADDR);
|
||||
reg_space[DMA_CUR_RX_BUF_ADDR / 4] =
|
||||
readl(ioaddr + DMA_CUR_RX_BUF_ADDR);
|
||||
}
|
||||
|
||||
/* DMA controller has two counters to track the number of the missed frames. */
|
||||
static void dwmac100_dma_diagnostic_fr(struct stmmac_extra_stats *x,
|
||||
void __iomem *ioaddr)
|
||||
{
|
||||
u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
|
||||
|
||||
if (unlikely(csr8)) {
|
||||
if (csr8 & DMA_MISSED_FRAME_OVE) {
|
||||
x->rx_overflow_cntr += 0x800;
|
||||
} else {
|
||||
unsigned int ove_cntr;
|
||||
ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
|
||||
x->rx_overflow_cntr += ove_cntr;
|
||||
}
|
||||
|
||||
if (csr8 & DMA_MISSED_FRAME_OVE_M) {
|
||||
x->rx_missed_cntr += 0xffff;
|
||||
} else {
|
||||
unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
|
||||
x->rx_missed_cntr += miss_f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const struct stmmac_dma_ops dwmac100_dma_ops = {
|
||||
.reset = dwmac_dma_reset,
|
||||
.init = dwmac100_dma_init,
|
||||
.init_rx_chan = dwmac100_dma_init_rx,
|
||||
.init_tx_chan = dwmac100_dma_init_tx,
|
||||
.dump_regs = dwmac100_dump_dma_regs,
|
||||
.dma_tx_mode = dwmac100_dma_operation_mode_tx,
|
||||
.dma_diagnostic_fr = dwmac100_dma_diagnostic_fr,
|
||||
.enable_dma_transmission = dwmac_enable_dma_transmission,
|
||||
.enable_dma_irq = dwmac_enable_dma_irq,
|
||||
.disable_dma_irq = dwmac_disable_dma_irq,
|
||||
.start_tx = dwmac_dma_start_tx,
|
||||
.stop_tx = dwmac_dma_stop_tx,
|
||||
.start_rx = dwmac_dma_start_rx,
|
||||
.stop_rx = dwmac_dma_stop_rx,
|
||||
.dma_interrupt = dwmac_dma_interrupt,
|
||||
};
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This is the driver for the MAC 10/100 on-chip Ethernet controller
|
||||
currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
|
||||
|
||||
DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
|
||||
this code.
|
||||
|
||||
This contains the functions to handle the dma.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include "dwmac100.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
static void dwmac100_dma_init(void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg)
|
||||
{
|
||||
/* Enable Application Access by writing to DMA CSR0 */
|
||||
writel(DMA_BUS_MODE_DEFAULT | (dma_cfg->pbl << DMA_BUS_MODE_PBL_SHIFT),
|
||||
ioaddr + DMA_BUS_MODE);
|
||||
|
||||
/* Mask interrupts by writing to CSR7 */
|
||||
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
|
||||
}
|
||||
|
||||
static void dwmac100_dma_init_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t dma_rx_phy, u32 chan)
|
||||
{
|
||||
/* RX descriptor base addr lists must be written into DMA CSR3 */
|
||||
writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR);
|
||||
}
|
||||
|
||||
static void dwmac100_dma_init_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t dma_tx_phy, u32 chan)
|
||||
{
|
||||
/* TX descriptor base addr lists must be written into DMA CSR4 */
|
||||
writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_TX_BASE_ADDR);
|
||||
}
|
||||
|
||||
/* Store and Forward capability is not used at all.
|
||||
*
|
||||
* The transmit threshold can be programmed by setting the TTC bits in the DMA
|
||||
* control register.
|
||||
*/
|
||||
static void dwmac100_dma_operation_mode_tx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, int mode,
|
||||
u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CONTROL);
|
||||
|
||||
if (mode <= 32)
|
||||
csr6 |= DMA_CONTROL_TTC_32;
|
||||
else if (mode <= 64)
|
||||
csr6 |= DMA_CONTROL_TTC_64;
|
||||
else
|
||||
csr6 |= DMA_CONTROL_TTC_128;
|
||||
|
||||
writel(csr6, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
static void dwmac100_dump_dma_regs(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 *reg_space)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_DWMAC100_DMA_REGS; i++)
|
||||
reg_space[DMA_BUS_MODE / 4 + i] =
|
||||
readl(ioaddr + DMA_BUS_MODE + i * 4);
|
||||
|
||||
reg_space[DMA_CUR_TX_BUF_ADDR / 4] =
|
||||
readl(ioaddr + DMA_CUR_TX_BUF_ADDR);
|
||||
reg_space[DMA_CUR_RX_BUF_ADDR / 4] =
|
||||
readl(ioaddr + DMA_CUR_RX_BUF_ADDR);
|
||||
}
|
||||
|
||||
/* DMA controller has two counters to track the number of the missed frames. */
|
||||
static void dwmac100_dma_diagnostic_fr(struct stmmac_extra_stats *x,
|
||||
void __iomem *ioaddr)
|
||||
{
|
||||
u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
|
||||
|
||||
if (unlikely(csr8)) {
|
||||
if (csr8 & DMA_MISSED_FRAME_OVE) {
|
||||
x->rx_overflow_cntr += 0x800;
|
||||
} else {
|
||||
unsigned int ove_cntr;
|
||||
ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
|
||||
x->rx_overflow_cntr += ove_cntr;
|
||||
}
|
||||
|
||||
if (csr8 & DMA_MISSED_FRAME_OVE_M) {
|
||||
x->rx_missed_cntr += 0xffff;
|
||||
} else {
|
||||
unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
|
||||
x->rx_missed_cntr += miss_f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const struct stmmac_dma_ops dwmac100_dma_ops = {
|
||||
.reset = dwmac_dma_reset,
|
||||
.init = dwmac100_dma_init,
|
||||
.init_rx_chan = dwmac100_dma_init_rx,
|
||||
.init_tx_chan = dwmac100_dma_init_tx,
|
||||
.dump_regs = dwmac100_dump_dma_regs,
|
||||
.dma_tx_mode = dwmac100_dma_operation_mode_tx,
|
||||
.dma_diagnostic_fr = dwmac100_dma_diagnostic_fr,
|
||||
.enable_dma_transmission = dwmac_enable_dma_transmission,
|
||||
.enable_dma_irq = dwmac_enable_dma_irq,
|
||||
.disable_dma_irq = dwmac_disable_dma_irq,
|
||||
.start_tx = dwmac_dma_start_tx,
|
||||
.stop_tx = dwmac_dma_stop_tx,
|
||||
.start_rx = dwmac_dma_start_rx,
|
||||
.stop_rx = dwmac_dma_stop_rx,
|
||||
.dma_interrupt = dwmac_dma_interrupt,
|
||||
};
|
||||
|
|
@ -0,0 +1,588 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* DWMAC4 Header file.
|
||||
*
|
||||
* Copyright (C) 2015 STMicroelectronics Ltd
|
||||
*
|
||||
* Author: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
*/
|
||||
|
||||
#ifndef __DWMAC4_H__
|
||||
#define __DWMAC4_H__
|
||||
|
||||
#include "common-6.12-ethercat.h"
|
||||
|
||||
/* MAC registers */
|
||||
#define GMAC_CONFIG 0x00000000
|
||||
#define GMAC_EXT_CONFIG 0x00000004
|
||||
#define GMAC_PACKET_FILTER 0x00000008
|
||||
#define GMAC_HASH_TAB(x) (0x10 + (x) * 4)
|
||||
#define GMAC_VLAN_TAG 0x00000050
|
||||
#define GMAC_VLAN_TAG_DATA 0x00000054
|
||||
#define GMAC_VLAN_HASH_TABLE 0x00000058
|
||||
#define GMAC_RX_FLOW_CTRL 0x00000090
|
||||
#define GMAC_VLAN_INCL 0x00000060
|
||||
#define GMAC_QX_TX_FLOW_CTRL(x) (0x70 + x * 4)
|
||||
#define GMAC_TXQ_PRTY_MAP0 0x98
|
||||
#define GMAC_TXQ_PRTY_MAP1 0x9C
|
||||
#define GMAC_RXQ_CTRL0 0x000000a0
|
||||
#define GMAC_RXQ_CTRL1 0x000000a4
|
||||
#define GMAC_RXQ_CTRL2 0x000000a8
|
||||
#define GMAC_RXQ_CTRL3 0x000000ac
|
||||
#define GMAC_INT_STATUS 0x000000b0
|
||||
#define GMAC_INT_EN 0x000000b4
|
||||
#define GMAC_1US_TIC_COUNTER 0x000000dc
|
||||
#define GMAC_PCS_BASE 0x000000e0
|
||||
#define GMAC_PHYIF_CONTROL_STATUS 0x000000f8
|
||||
#define GMAC_PMT 0x000000c0
|
||||
#define GMAC_DEBUG 0x00000114
|
||||
#define GMAC_HW_FEATURE0 0x0000011c
|
||||
#define GMAC_HW_FEATURE1 0x00000120
|
||||
#define GMAC_HW_FEATURE2 0x00000124
|
||||
#define GMAC_HW_FEATURE3 0x00000128
|
||||
#define GMAC_MDIO_ADDR 0x00000200
|
||||
#define GMAC_MDIO_DATA 0x00000204
|
||||
#define GMAC_GPIO_STATUS 0x0000020C
|
||||
#define GMAC_ARP_ADDR 0x00000210
|
||||
#define GMAC_EXT_CFG1 0x00000238
|
||||
#define GMAC_ADDR_HIGH(reg) (0x300 + reg * 8)
|
||||
#define GMAC_ADDR_LOW(reg) (0x304 + reg * 8)
|
||||
#define GMAC_L3L4_CTRL(reg) (0x900 + (reg) * 0x30)
|
||||
#define GMAC_L4_ADDR(reg) (0x904 + (reg) * 0x30)
|
||||
#define GMAC_L3_ADDR0(reg) (0x910 + (reg) * 0x30)
|
||||
#define GMAC_L3_ADDR1(reg) (0x914 + (reg) * 0x30)
|
||||
#define GMAC_TIMESTAMP_STATUS 0x00000b20
|
||||
|
||||
/* RX Queues Routing */
|
||||
#define GMAC_RXQCTRL_AVCPQ_MASK GENMASK(2, 0)
|
||||
#define GMAC_RXQCTRL_AVCPQ_SHIFT 0
|
||||
#define GMAC_RXQCTRL_PTPQ_MASK GENMASK(6, 4)
|
||||
#define GMAC_RXQCTRL_PTPQ_SHIFT 4
|
||||
#define GMAC_RXQCTRL_DCBCPQ_MASK GENMASK(10, 8)
|
||||
#define GMAC_RXQCTRL_DCBCPQ_SHIFT 8
|
||||
#define GMAC_RXQCTRL_UPQ_MASK GENMASK(14, 12)
|
||||
#define GMAC_RXQCTRL_UPQ_SHIFT 12
|
||||
#define GMAC_RXQCTRL_MCBCQ_MASK GENMASK(18, 16)
|
||||
#define GMAC_RXQCTRL_MCBCQ_SHIFT 16
|
||||
#define GMAC_RXQCTRL_MCBCQEN BIT(20)
|
||||
#define GMAC_RXQCTRL_MCBCQEN_SHIFT 20
|
||||
#define GMAC_RXQCTRL_TACPQE BIT(21)
|
||||
#define GMAC_RXQCTRL_TACPQE_SHIFT 21
|
||||
#define GMAC_RXQCTRL_FPRQ GENMASK(26, 24)
|
||||
#define GMAC_RXQCTRL_FPRQ_SHIFT 24
|
||||
|
||||
/* MAC Packet Filtering */
|
||||
#define GMAC_PACKET_FILTER_PR BIT(0)
|
||||
#define GMAC_PACKET_FILTER_HMC BIT(2)
|
||||
#define GMAC_PACKET_FILTER_PM BIT(4)
|
||||
#define GMAC_PACKET_FILTER_PCF BIT(7)
|
||||
#define GMAC_PACKET_FILTER_HPF BIT(10)
|
||||
#define GMAC_PACKET_FILTER_VTFE BIT(16)
|
||||
#define GMAC_PACKET_FILTER_IPFE BIT(20)
|
||||
#define GMAC_PACKET_FILTER_RA BIT(31)
|
||||
|
||||
#define GMAC_MAX_PERFECT_ADDRESSES 128
|
||||
|
||||
/* MAC VLAN */
|
||||
#define GMAC_VLAN_EDVLP BIT(26)
|
||||
#define GMAC_VLAN_VTHM BIT(25)
|
||||
#define GMAC_VLAN_DOVLTC BIT(20)
|
||||
#define GMAC_VLAN_ESVL BIT(18)
|
||||
#define GMAC_VLAN_ETV BIT(16)
|
||||
#define GMAC_VLAN_VID GENMASK(15, 0)
|
||||
#define GMAC_VLAN_VLTI BIT(20)
|
||||
#define GMAC_VLAN_CSVL BIT(19)
|
||||
#define GMAC_VLAN_VLC GENMASK(17, 16)
|
||||
#define GMAC_VLAN_VLC_SHIFT 16
|
||||
#define GMAC_VLAN_VLHT GENMASK(15, 0)
|
||||
|
||||
/* MAC VLAN Tag */
|
||||
#define GMAC_VLAN_TAG_VID GENMASK(15, 0)
|
||||
#define GMAC_VLAN_TAG_ETV BIT(16)
|
||||
|
||||
/* MAC VLAN Tag Control */
|
||||
#define GMAC_VLAN_TAG_CTRL_OB BIT(0)
|
||||
#define GMAC_VLAN_TAG_CTRL_CT BIT(1)
|
||||
#define GMAC_VLAN_TAG_CTRL_OFS_MASK GENMASK(6, 2)
|
||||
#define GMAC_VLAN_TAG_CTRL_OFS_SHIFT 2
|
||||
#define GMAC_VLAN_TAG_CTRL_EVLS_MASK GENMASK(22, 21)
|
||||
#define GMAC_VLAN_TAG_CTRL_EVLS_SHIFT 21
|
||||
#define GMAC_VLAN_TAG_CTRL_EVLRXS BIT(24)
|
||||
|
||||
#define GMAC_VLAN_TAG_STRIP_NONE (0x0 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT)
|
||||
#define GMAC_VLAN_TAG_STRIP_PASS (0x1 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT)
|
||||
#define GMAC_VLAN_TAG_STRIP_FAIL (0x2 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT)
|
||||
#define GMAC_VLAN_TAG_STRIP_ALL (0x3 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT)
|
||||
|
||||
/* MAC VLAN Tag Data/Filter */
|
||||
#define GMAC_VLAN_TAG_DATA_VID GENMASK(15, 0)
|
||||
#define GMAC_VLAN_TAG_DATA_VEN BIT(16)
|
||||
#define GMAC_VLAN_TAG_DATA_ETV BIT(17)
|
||||
|
||||
/* MAC RX Queue Enable */
|
||||
#define GMAC_RX_QUEUE_CLEAR(queue) ~(GENMASK(1, 0) << ((queue) * 2))
|
||||
#define GMAC_RX_AV_QUEUE_ENABLE(queue) BIT((queue) * 2)
|
||||
#define GMAC_RX_DCB_QUEUE_ENABLE(queue) BIT(((queue) * 2) + 1)
|
||||
|
||||
/* MAC Flow Control RX */
|
||||
#define GMAC_RX_FLOW_CTRL_RFE BIT(0)
|
||||
|
||||
/* RX Queues Priorities */
|
||||
#define GMAC_RXQCTRL_PSRQX_MASK(x) GENMASK(7 + ((x) * 8), 0 + ((x) * 8))
|
||||
#define GMAC_RXQCTRL_PSRQX_SHIFT(x) ((x) * 8)
|
||||
|
||||
/* TX Queues Priorities */
|
||||
#define GMAC_TXQCTRL_PSTQX_MASK(x) GENMASK(7 + ((x) * 8), 0 + ((x) * 8))
|
||||
#define GMAC_TXQCTRL_PSTQX_SHIFT(x) ((x) * 8)
|
||||
|
||||
/* MAC Flow Control TX */
|
||||
#define GMAC_TX_FLOW_CTRL_TFE BIT(1)
|
||||
#define GMAC_TX_FLOW_CTRL_PT_SHIFT 16
|
||||
|
||||
/* MAC Interrupt bitmap*/
|
||||
#define GMAC_INT_RGSMIIS BIT(0)
|
||||
#define GMAC_INT_PCS_LINK BIT(1)
|
||||
#define GMAC_INT_PCS_ANE BIT(2)
|
||||
#define GMAC_INT_PCS_PHYIS BIT(3)
|
||||
#define GMAC_INT_PMT_EN BIT(4)
|
||||
#define GMAC_INT_LPI_EN BIT(5)
|
||||
#define GMAC_INT_TSIE BIT(12)
|
||||
|
||||
#define GMAC_PCS_IRQ_DEFAULT (GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK | \
|
||||
GMAC_INT_PCS_ANE)
|
||||
|
||||
#define GMAC_INT_DEFAULT_ENABLE (GMAC_INT_PMT_EN | GMAC_INT_LPI_EN | \
|
||||
GMAC_INT_TSIE)
|
||||
|
||||
enum dwmac4_irq_status {
|
||||
time_stamp_irq = 0x00001000,
|
||||
mmc_rx_csum_offload_irq = 0x00000800,
|
||||
mmc_tx_irq = 0x00000400,
|
||||
mmc_rx_irq = 0x00000200,
|
||||
mmc_irq = 0x00000100,
|
||||
lpi_irq = 0x00000020,
|
||||
pmt_irq = 0x00000010,
|
||||
};
|
||||
|
||||
/* MAC PMT bitmap */
|
||||
enum power_event {
|
||||
pointer_reset = 0x80000000,
|
||||
global_unicast = 0x00000200,
|
||||
wake_up_rx_frame = 0x00000040,
|
||||
magic_frame = 0x00000020,
|
||||
wake_up_frame_en = 0x00000004,
|
||||
magic_pkt_en = 0x00000002,
|
||||
power_down = 0x00000001,
|
||||
};
|
||||
|
||||
/* Energy Efficient Ethernet (EEE) for GMAC4
|
||||
*
|
||||
* LPI status, timer and control register offset
|
||||
*/
|
||||
#define GMAC4_LPI_CTRL_STATUS 0xd0
|
||||
#define GMAC4_LPI_TIMER_CTRL 0xd4
|
||||
#define GMAC4_LPI_ENTRY_TIMER 0xd8
|
||||
#define GMAC4_MAC_ONEUS_TIC_COUNTER 0xdc
|
||||
|
||||
/* LPI control and status defines */
|
||||
#define GMAC4_LPI_CTRL_STATUS_LPITCSE BIT(21) /* LPI Tx Clock Stop Enable */
|
||||
#define GMAC4_LPI_CTRL_STATUS_LPIATE BIT(20) /* LPI Timer Enable */
|
||||
#define GMAC4_LPI_CTRL_STATUS_LPITXA BIT(19) /* Enable LPI TX Automate */
|
||||
#define GMAC4_LPI_CTRL_STATUS_PLS BIT(17) /* PHY Link Status */
|
||||
#define GMAC4_LPI_CTRL_STATUS_LPIEN BIT(16) /* LPI Enable */
|
||||
#define GMAC4_LPI_CTRL_STATUS_RLPIEX BIT(3) /* Receive LPI Exit */
|
||||
#define GMAC4_LPI_CTRL_STATUS_RLPIEN BIT(2) /* Receive LPI Entry */
|
||||
#define GMAC4_LPI_CTRL_STATUS_TLPIEX BIT(1) /* Transmit LPI Exit */
|
||||
#define GMAC4_LPI_CTRL_STATUS_TLPIEN BIT(0) /* Transmit LPI Entry */
|
||||
|
||||
/* MAC Debug bitmap */
|
||||
#define GMAC_DEBUG_TFCSTS_MASK GENMASK(18, 17)
|
||||
#define GMAC_DEBUG_TFCSTS_SHIFT 17
|
||||
#define GMAC_DEBUG_TFCSTS_IDLE 0
|
||||
#define GMAC_DEBUG_TFCSTS_WAIT 1
|
||||
#define GMAC_DEBUG_TFCSTS_GEN_PAUSE 2
|
||||
#define GMAC_DEBUG_TFCSTS_XFER 3
|
||||
#define GMAC_DEBUG_TPESTS BIT(16)
|
||||
#define GMAC_DEBUG_RFCFCSTS_MASK GENMASK(2, 1)
|
||||
#define GMAC_DEBUG_RFCFCSTS_SHIFT 1
|
||||
#define GMAC_DEBUG_RPESTS BIT(0)
|
||||
|
||||
/* MAC config */
|
||||
#define GMAC_CONFIG_ARPEN BIT(31)
|
||||
#define GMAC_CONFIG_SARC GENMASK(30, 28)
|
||||
#define GMAC_CONFIG_SARC_SHIFT 28
|
||||
#define GMAC_CONFIG_IPC BIT(27)
|
||||
#define GMAC_CONFIG_IPG GENMASK(26, 24)
|
||||
#define GMAC_CONFIG_IPG_SHIFT 24
|
||||
#define GMAC_CONFIG_2K BIT(22)
|
||||
#define GMAC_CONFIG_ACS BIT(20)
|
||||
#define GMAC_CONFIG_BE BIT(18)
|
||||
#define GMAC_CONFIG_JD BIT(17)
|
||||
#define GMAC_CONFIG_JE BIT(16)
|
||||
#define GMAC_CONFIG_PS BIT(15)
|
||||
#define GMAC_CONFIG_FES BIT(14)
|
||||
#define GMAC_CONFIG_FES_SHIFT 14
|
||||
#define GMAC_CONFIG_DM BIT(13)
|
||||
#define GMAC_CONFIG_LM BIT(12)
|
||||
#define GMAC_CONFIG_DCRS BIT(9)
|
||||
#define GMAC_CONFIG_TE BIT(1)
|
||||
#define GMAC_CONFIG_RE BIT(0)
|
||||
|
||||
/* MAC extended config */
|
||||
#define GMAC_CONFIG_EIPG GENMASK(29, 25)
|
||||
#define GMAC_CONFIG_EIPG_SHIFT 25
|
||||
#define GMAC_CONFIG_EIPG_EN BIT(24)
|
||||
#define GMAC_CONFIG_HDSMS GENMASK(22, 20)
|
||||
#define GMAC_CONFIG_HDSMS_SHIFT 20
|
||||
#define GMAC_CONFIG_HDSMS_256 (0x2 << GMAC_CONFIG_HDSMS_SHIFT)
|
||||
|
||||
/* MAC HW features0 bitmap */
|
||||
#define GMAC_HW_FEAT_SAVLANINS BIT(27)
|
||||
#define GMAC_HW_FEAT_ADDMAC BIT(18)
|
||||
#define GMAC_HW_FEAT_RXCOESEL BIT(16)
|
||||
#define GMAC_HW_FEAT_TXCOSEL BIT(14)
|
||||
#define GMAC_HW_FEAT_EEESEL BIT(13)
|
||||
#define GMAC_HW_FEAT_TSSEL BIT(12)
|
||||
#define GMAC_HW_FEAT_ARPOFFSEL BIT(9)
|
||||
#define GMAC_HW_FEAT_MMCSEL BIT(8)
|
||||
#define GMAC_HW_FEAT_MGKSEL BIT(7)
|
||||
#define GMAC_HW_FEAT_RWKSEL BIT(6)
|
||||
#define GMAC_HW_FEAT_SMASEL BIT(5)
|
||||
#define GMAC_HW_FEAT_VLHASH BIT(4)
|
||||
#define GMAC_HW_FEAT_PCSSEL BIT(3)
|
||||
#define GMAC_HW_FEAT_HDSEL BIT(2)
|
||||
#define GMAC_HW_FEAT_GMIISEL BIT(1)
|
||||
#define GMAC_HW_FEAT_MIISEL BIT(0)
|
||||
|
||||
/* MAC HW features1 bitmap */
|
||||
#define GMAC_HW_FEAT_L3L4FNUM GENMASK(30, 27)
|
||||
#define GMAC_HW_HASH_TB_SZ GENMASK(25, 24)
|
||||
#define GMAC_HW_FEAT_AVSEL BIT(20)
|
||||
#define GMAC_HW_TSOEN BIT(18)
|
||||
#define GMAC_HW_FEAT_SPHEN BIT(17)
|
||||
#define GMAC_HW_ADDR64 GENMASK(15, 14)
|
||||
#define GMAC_HW_TXFIFOSIZE GENMASK(10, 6)
|
||||
#define GMAC_HW_RXFIFOSIZE GENMASK(4, 0)
|
||||
|
||||
/* MAC HW features2 bitmap */
|
||||
#define GMAC_HW_FEAT_AUXSNAPNUM GENMASK(30, 28)
|
||||
#define GMAC_HW_FEAT_PPSOUTNUM GENMASK(26, 24)
|
||||
#define GMAC_HW_FEAT_TXCHCNT GENMASK(21, 18)
|
||||
#define GMAC_HW_FEAT_RXCHCNT GENMASK(15, 12)
|
||||
#define GMAC_HW_FEAT_TXQCNT GENMASK(9, 6)
|
||||
#define GMAC_HW_FEAT_RXQCNT GENMASK(3, 0)
|
||||
|
||||
/* MAC HW features3 bitmap */
|
||||
#define GMAC_HW_FEAT_ASP GENMASK(29, 28)
|
||||
#define GMAC_HW_FEAT_TBSSEL BIT(27)
|
||||
#define GMAC_HW_FEAT_FPESEL BIT(26)
|
||||
#define GMAC_HW_FEAT_ESTWID GENMASK(21, 20)
|
||||
#define GMAC_HW_FEAT_ESTDEP GENMASK(19, 17)
|
||||
#define GMAC_HW_FEAT_ESTSEL BIT(16)
|
||||
#define GMAC_HW_FEAT_FRPES GENMASK(14, 13)
|
||||
#define GMAC_HW_FEAT_FRPBS GENMASK(12, 11)
|
||||
#define GMAC_HW_FEAT_FRPSEL BIT(10)
|
||||
#define GMAC_HW_FEAT_DVLAN BIT(5)
|
||||
#define GMAC_HW_FEAT_NRVF GENMASK(2, 0)
|
||||
|
||||
/* MAC extended config 1 */
|
||||
#define GMAC_CONFIG1_SAVE_EN BIT(24)
|
||||
#define GMAC_CONFIG1_SPLM(v) FIELD_PREP(GENMASK(9, 8), v)
|
||||
|
||||
/* GMAC GPIO Status reg */
|
||||
#define GMAC_GPO0 BIT(16)
|
||||
#define GMAC_GPO1 BIT(17)
|
||||
#define GMAC_GPO2 BIT(18)
|
||||
#define GMAC_GPO3 BIT(19)
|
||||
|
||||
/* MAC HW ADDR regs */
|
||||
#define GMAC_HI_DCS GENMASK(18, 16)
|
||||
#define GMAC_HI_DCS_SHIFT 16
|
||||
#define GMAC_HI_REG_AE BIT(31)
|
||||
|
||||
/* L3/L4 Filters regs */
|
||||
#define GMAC_L4DPIM0 BIT(21)
|
||||
#define GMAC_L4DPM0 BIT(20)
|
||||
#define GMAC_L4SPIM0 BIT(19)
|
||||
#define GMAC_L4SPM0 BIT(18)
|
||||
#define GMAC_L4PEN0 BIT(16)
|
||||
#define GMAC_L3DAIM0 BIT(5)
|
||||
#define GMAC_L3DAM0 BIT(4)
|
||||
#define GMAC_L3SAIM0 BIT(3)
|
||||
#define GMAC_L3SAM0 BIT(2)
|
||||
#define GMAC_L3PEN0 BIT(0)
|
||||
#define GMAC_L4DP0 GENMASK(31, 16)
|
||||
#define GMAC_L4DP0_SHIFT 16
|
||||
#define GMAC_L4SP0 GENMASK(15, 0)
|
||||
|
||||
/* MAC Timestamp Status */
|
||||
#define GMAC_TIMESTAMP_AUXTSTRIG BIT(2)
|
||||
#define GMAC_TIMESTAMP_ATSNS_MASK GENMASK(29, 25)
|
||||
#define GMAC_TIMESTAMP_ATSNS_SHIFT 25
|
||||
|
||||
/* MTL registers */
|
||||
#define MTL_OPERATION_MODE 0x00000c00
|
||||
#define MTL_FRPE BIT(15)
|
||||
#define MTL_OPERATION_SCHALG_MASK GENMASK(6, 5)
|
||||
#define MTL_OPERATION_SCHALG_WRR (0x0 << 5)
|
||||
#define MTL_OPERATION_SCHALG_WFQ (0x1 << 5)
|
||||
#define MTL_OPERATION_SCHALG_DWRR (0x2 << 5)
|
||||
#define MTL_OPERATION_SCHALG_SP (0x3 << 5)
|
||||
#define MTL_OPERATION_RAA BIT(2)
|
||||
#define MTL_OPERATION_RAA_SP (0x0 << 2)
|
||||
#define MTL_OPERATION_RAA_WSP (0x1 << 2)
|
||||
|
||||
#define MTL_INT_STATUS 0x00000c20
|
||||
#define MTL_INT_QX(x) BIT(x)
|
||||
|
||||
#define MTL_RXQ_DMA_MAP0 0x00000c30 /* queue 0 to 3 */
|
||||
#define MTL_RXQ_DMA_MAP1 0x00000c34 /* queue 4 to 7 */
|
||||
#define MTL_RXQ_DMA_QXMDMACH_MASK(x) (0xf << 8 * (x))
|
||||
#define MTL_RXQ_DMA_QXMDMACH(chan, q) ((chan) << (8 * (q)))
|
||||
|
||||
#define MTL_CHAN_BASE_ADDR 0x00000d00
|
||||
#define MTL_CHAN_BASE_OFFSET 0x40
|
||||
|
||||
static inline u32 mtl_chanx_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->mtl_chan + (x * addrs->mtl_chan_offset);
|
||||
else
|
||||
addr = MTL_CHAN_BASE_ADDR + (x * MTL_CHAN_BASE_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define MTL_CHAN_TX_OP_MODE(addrs, x) mtl_chanx_base_addr(addrs, x)
|
||||
#define MTL_CHAN_TX_DEBUG(addrs, x) (mtl_chanx_base_addr(addrs, x) + 0x8)
|
||||
#define MTL_CHAN_INT_CTRL(addrs, x) (mtl_chanx_base_addr(addrs, x) + 0x2c)
|
||||
#define MTL_CHAN_RX_OP_MODE(addrs, x) (mtl_chanx_base_addr(addrs, x) + 0x30)
|
||||
#define MTL_CHAN_RX_DEBUG(addrs, x) (mtl_chanx_base_addr(addrs, x) + 0x38)
|
||||
|
||||
#define MTL_OP_MODE_RSF BIT(5)
|
||||
#define MTL_OP_MODE_TXQEN_MASK GENMASK(3, 2)
|
||||
#define MTL_OP_MODE_TXQEN_AV BIT(2)
|
||||
#define MTL_OP_MODE_TXQEN BIT(3)
|
||||
#define MTL_OP_MODE_TSF BIT(1)
|
||||
|
||||
#define MTL_OP_MODE_TQS_MASK GENMASK(24, 16)
|
||||
#define MTL_OP_MODE_TQS_SHIFT 16
|
||||
|
||||
#define MTL_OP_MODE_TTC_MASK 0x70
|
||||
#define MTL_OP_MODE_TTC_SHIFT 4
|
||||
|
||||
#define MTL_OP_MODE_TTC_32 0
|
||||
#define MTL_OP_MODE_TTC_64 (1 << MTL_OP_MODE_TTC_SHIFT)
|
||||
#define MTL_OP_MODE_TTC_96 (2 << MTL_OP_MODE_TTC_SHIFT)
|
||||
#define MTL_OP_MODE_TTC_128 (3 << MTL_OP_MODE_TTC_SHIFT)
|
||||
#define MTL_OP_MODE_TTC_192 (4 << MTL_OP_MODE_TTC_SHIFT)
|
||||
#define MTL_OP_MODE_TTC_256 (5 << MTL_OP_MODE_TTC_SHIFT)
|
||||
#define MTL_OP_MODE_TTC_384 (6 << MTL_OP_MODE_TTC_SHIFT)
|
||||
#define MTL_OP_MODE_TTC_512 (7 << MTL_OP_MODE_TTC_SHIFT)
|
||||
|
||||
#define MTL_OP_MODE_RQS_MASK GENMASK(29, 20)
|
||||
#define MTL_OP_MODE_RQS_SHIFT 20
|
||||
|
||||
#define MTL_OP_MODE_RFD_MASK GENMASK(19, 14)
|
||||
#define MTL_OP_MODE_RFD_SHIFT 14
|
||||
|
||||
#define MTL_OP_MODE_RFA_MASK GENMASK(13, 8)
|
||||
#define MTL_OP_MODE_RFA_SHIFT 8
|
||||
|
||||
#define MTL_OP_MODE_EHFC BIT(7)
|
||||
|
||||
#define MTL_OP_MODE_RTC_MASK 0x18
|
||||
#define MTL_OP_MODE_RTC_SHIFT 3
|
||||
|
||||
#define MTL_OP_MODE_RTC_32 (1 << MTL_OP_MODE_RTC_SHIFT)
|
||||
#define MTL_OP_MODE_RTC_64 0
|
||||
#define MTL_OP_MODE_RTC_96 (2 << MTL_OP_MODE_RTC_SHIFT)
|
||||
#define MTL_OP_MODE_RTC_128 (3 << MTL_OP_MODE_RTC_SHIFT)
|
||||
|
||||
/* MTL ETS Control register */
|
||||
#define MTL_ETS_CTRL_BASE_ADDR 0x00000d10
|
||||
#define MTL_ETS_CTRL_BASE_OFFSET 0x40
|
||||
|
||||
static inline u32 mtl_etsx_ctrl_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->mtl_ets_ctrl + (x * addrs->mtl_ets_ctrl_offset);
|
||||
else
|
||||
addr = MTL_ETS_CTRL_BASE_ADDR + (x * MTL_ETS_CTRL_BASE_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define MTL_ETS_CTRL_CC BIT(3)
|
||||
#define MTL_ETS_CTRL_AVALG BIT(2)
|
||||
|
||||
/* MTL Queue Quantum Weight */
|
||||
#define MTL_TXQ_WEIGHT_BASE_ADDR 0x00000d18
|
||||
#define MTL_TXQ_WEIGHT_BASE_OFFSET 0x40
|
||||
|
||||
static inline u32 mtl_txqx_weight_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->mtl_txq_weight + (x * addrs->mtl_txq_weight_offset);
|
||||
else
|
||||
addr = MTL_TXQ_WEIGHT_BASE_ADDR + (x * MTL_TXQ_WEIGHT_BASE_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define MTL_TXQ_WEIGHT_ISCQW_MASK GENMASK(20, 0)
|
||||
|
||||
/* MTL sendSlopeCredit register */
|
||||
#define MTL_SEND_SLP_CRED_BASE_ADDR 0x00000d1c
|
||||
#define MTL_SEND_SLP_CRED_OFFSET 0x40
|
||||
|
||||
static inline u32 mtl_send_slp_credx_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->mtl_send_slp_cred + (x * addrs->mtl_send_slp_cred_offset);
|
||||
else
|
||||
addr = MTL_SEND_SLP_CRED_BASE_ADDR + (x * MTL_SEND_SLP_CRED_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define MTL_SEND_SLP_CRED_SSC_MASK GENMASK(13, 0)
|
||||
|
||||
/* MTL hiCredit register */
|
||||
#define MTL_HIGH_CRED_BASE_ADDR 0x00000d20
|
||||
#define MTL_HIGH_CRED_OFFSET 0x40
|
||||
|
||||
static inline u32 mtl_high_credx_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->mtl_high_cred + (x * addrs->mtl_high_cred_offset);
|
||||
else
|
||||
addr = MTL_HIGH_CRED_BASE_ADDR + (x * MTL_HIGH_CRED_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define MTL_HIGH_CRED_HC_MASK GENMASK(28, 0)
|
||||
|
||||
/* MTL loCredit register */
|
||||
#define MTL_LOW_CRED_BASE_ADDR 0x00000d24
|
||||
#define MTL_LOW_CRED_OFFSET 0x40
|
||||
|
||||
static inline u32 mtl_low_credx_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->mtl_low_cred + (x * addrs->mtl_low_cred_offset);
|
||||
else
|
||||
addr = MTL_LOW_CRED_BASE_ADDR + (x * MTL_LOW_CRED_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define MTL_HIGH_CRED_LC_MASK GENMASK(28, 0)
|
||||
|
||||
/* MTL debug */
|
||||
#define MTL_DEBUG_TXSTSFSTS BIT(5)
|
||||
#define MTL_DEBUG_TXFSTS BIT(4)
|
||||
#define MTL_DEBUG_TWCSTS BIT(3)
|
||||
|
||||
/* MTL debug: Tx FIFO Read Controller Status */
|
||||
#define MTL_DEBUG_TRCSTS_MASK GENMASK(2, 1)
|
||||
#define MTL_DEBUG_TRCSTS_SHIFT 1
|
||||
#define MTL_DEBUG_TRCSTS_IDLE 0
|
||||
#define MTL_DEBUG_TRCSTS_READ 1
|
||||
#define MTL_DEBUG_TRCSTS_TXW 2
|
||||
#define MTL_DEBUG_TRCSTS_WRITE 3
|
||||
#define MTL_DEBUG_TXPAUSED BIT(0)
|
||||
|
||||
/* MAC debug: GMII or MII Transmit Protocol Engine Status */
|
||||
#define MTL_DEBUG_RXFSTS_MASK GENMASK(5, 4)
|
||||
#define MTL_DEBUG_RXFSTS_SHIFT 4
|
||||
#define MTL_DEBUG_RXFSTS_EMPTY 0
|
||||
#define MTL_DEBUG_RXFSTS_BT 1
|
||||
#define MTL_DEBUG_RXFSTS_AT 2
|
||||
#define MTL_DEBUG_RXFSTS_FULL 3
|
||||
#define MTL_DEBUG_RRCSTS_MASK GENMASK(2, 1)
|
||||
#define MTL_DEBUG_RRCSTS_SHIFT 1
|
||||
#define MTL_DEBUG_RRCSTS_IDLE 0
|
||||
#define MTL_DEBUG_RRCSTS_RDATA 1
|
||||
#define MTL_DEBUG_RRCSTS_RSTAT 2
|
||||
#define MTL_DEBUG_RRCSTS_FLUSH 3
|
||||
#define MTL_DEBUG_RWCSTS BIT(0)
|
||||
|
||||
/* MTL interrupt */
|
||||
#define MTL_RX_OVERFLOW_INT_EN BIT(24)
|
||||
#define MTL_RX_OVERFLOW_INT BIT(16)
|
||||
|
||||
/* Default operating mode of the MAC */
|
||||
#define GMAC_CORE_INIT (GMAC_CONFIG_JD | GMAC_CONFIG_PS | \
|
||||
GMAC_CONFIG_BE | GMAC_CONFIG_DCRS | \
|
||||
GMAC_CONFIG_JE)
|
||||
|
||||
/* To dump the core regs excluding the Address Registers */
|
||||
#define GMAC_REG_NUM 132
|
||||
|
||||
/* MTL debug */
|
||||
#define MTL_DEBUG_TXSTSFSTS BIT(5)
|
||||
#define MTL_DEBUG_TXFSTS BIT(4)
|
||||
#define MTL_DEBUG_TWCSTS BIT(3)
|
||||
|
||||
/* MTL debug: Tx FIFO Read Controller Status */
|
||||
#define MTL_DEBUG_TRCSTS_MASK GENMASK(2, 1)
|
||||
#define MTL_DEBUG_TRCSTS_SHIFT 1
|
||||
#define MTL_DEBUG_TRCSTS_IDLE 0
|
||||
#define MTL_DEBUG_TRCSTS_READ 1
|
||||
#define MTL_DEBUG_TRCSTS_TXW 2
|
||||
#define MTL_DEBUG_TRCSTS_WRITE 3
|
||||
#define MTL_DEBUG_TXPAUSED BIT(0)
|
||||
|
||||
/* MAC debug: GMII or MII Transmit Protocol Engine Status */
|
||||
#define MTL_DEBUG_RXFSTS_MASK GENMASK(5, 4)
|
||||
#define MTL_DEBUG_RXFSTS_SHIFT 4
|
||||
#define MTL_DEBUG_RXFSTS_EMPTY 0
|
||||
#define MTL_DEBUG_RXFSTS_BT 1
|
||||
#define MTL_DEBUG_RXFSTS_AT 2
|
||||
#define MTL_DEBUG_RXFSTS_FULL 3
|
||||
#define MTL_DEBUG_RRCSTS_MASK GENMASK(2, 1)
|
||||
#define MTL_DEBUG_RRCSTS_SHIFT 1
|
||||
#define MTL_DEBUG_RRCSTS_IDLE 0
|
||||
#define MTL_DEBUG_RRCSTS_RDATA 1
|
||||
#define MTL_DEBUG_RRCSTS_RSTAT 2
|
||||
#define MTL_DEBUG_RRCSTS_FLUSH 3
|
||||
#define MTL_DEBUG_RWCSTS BIT(0)
|
||||
|
||||
/* SGMII/RGMII status register */
|
||||
#define GMAC_PHYIF_CTRLSTATUS_TC BIT(0)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_LUD BIT(1)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SMIDRXS BIT(4)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_LNKMOD BIT(16)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED GENMASK(18, 17)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED_SHIFT 17
|
||||
#define GMAC_PHYIF_CTRLSTATUS_LNKSTS BIT(19)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_JABTO BIT(20)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_FALSECARDET BIT(21)
|
||||
/* LNKSPEED */
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED_125 0x2
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED_25 0x1
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED_2_5 0x0
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac4_dma_ops;
|
||||
extern const struct stmmac_dma_ops dwmac410_dma_ops;
|
||||
#endif /* __DWMAC4_H__ */
|
||||
|
|
@ -0,0 +1,588 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* DWMAC4 Header file.
|
||||
*
|
||||
* Copyright (C) 2015 STMicroelectronics Ltd
|
||||
*
|
||||
* Author: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
*/
|
||||
|
||||
#ifndef __DWMAC4_H__
|
||||
#define __DWMAC4_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* MAC registers */
|
||||
#define GMAC_CONFIG 0x00000000
|
||||
#define GMAC_EXT_CONFIG 0x00000004
|
||||
#define GMAC_PACKET_FILTER 0x00000008
|
||||
#define GMAC_HASH_TAB(x) (0x10 + (x) * 4)
|
||||
#define GMAC_VLAN_TAG 0x00000050
|
||||
#define GMAC_VLAN_TAG_DATA 0x00000054
|
||||
#define GMAC_VLAN_HASH_TABLE 0x00000058
|
||||
#define GMAC_RX_FLOW_CTRL 0x00000090
|
||||
#define GMAC_VLAN_INCL 0x00000060
|
||||
#define GMAC_QX_TX_FLOW_CTRL(x) (0x70 + x * 4)
|
||||
#define GMAC_TXQ_PRTY_MAP0 0x98
|
||||
#define GMAC_TXQ_PRTY_MAP1 0x9C
|
||||
#define GMAC_RXQ_CTRL0 0x000000a0
|
||||
#define GMAC_RXQ_CTRL1 0x000000a4
|
||||
#define GMAC_RXQ_CTRL2 0x000000a8
|
||||
#define GMAC_RXQ_CTRL3 0x000000ac
|
||||
#define GMAC_INT_STATUS 0x000000b0
|
||||
#define GMAC_INT_EN 0x000000b4
|
||||
#define GMAC_1US_TIC_COUNTER 0x000000dc
|
||||
#define GMAC_PCS_BASE 0x000000e0
|
||||
#define GMAC_PHYIF_CONTROL_STATUS 0x000000f8
|
||||
#define GMAC_PMT 0x000000c0
|
||||
#define GMAC_DEBUG 0x00000114
|
||||
#define GMAC_HW_FEATURE0 0x0000011c
|
||||
#define GMAC_HW_FEATURE1 0x00000120
|
||||
#define GMAC_HW_FEATURE2 0x00000124
|
||||
#define GMAC_HW_FEATURE3 0x00000128
|
||||
#define GMAC_MDIO_ADDR 0x00000200
|
||||
#define GMAC_MDIO_DATA 0x00000204
|
||||
#define GMAC_GPIO_STATUS 0x0000020C
|
||||
#define GMAC_ARP_ADDR 0x00000210
|
||||
#define GMAC_EXT_CFG1 0x00000238
|
||||
#define GMAC_ADDR_HIGH(reg) (0x300 + reg * 8)
|
||||
#define GMAC_ADDR_LOW(reg) (0x304 + reg * 8)
|
||||
#define GMAC_L3L4_CTRL(reg) (0x900 + (reg) * 0x30)
|
||||
#define GMAC_L4_ADDR(reg) (0x904 + (reg) * 0x30)
|
||||
#define GMAC_L3_ADDR0(reg) (0x910 + (reg) * 0x30)
|
||||
#define GMAC_L3_ADDR1(reg) (0x914 + (reg) * 0x30)
|
||||
#define GMAC_TIMESTAMP_STATUS 0x00000b20
|
||||
|
||||
/* RX Queues Routing */
|
||||
#define GMAC_RXQCTRL_AVCPQ_MASK GENMASK(2, 0)
|
||||
#define GMAC_RXQCTRL_AVCPQ_SHIFT 0
|
||||
#define GMAC_RXQCTRL_PTPQ_MASK GENMASK(6, 4)
|
||||
#define GMAC_RXQCTRL_PTPQ_SHIFT 4
|
||||
#define GMAC_RXQCTRL_DCBCPQ_MASK GENMASK(10, 8)
|
||||
#define GMAC_RXQCTRL_DCBCPQ_SHIFT 8
|
||||
#define GMAC_RXQCTRL_UPQ_MASK GENMASK(14, 12)
|
||||
#define GMAC_RXQCTRL_UPQ_SHIFT 12
|
||||
#define GMAC_RXQCTRL_MCBCQ_MASK GENMASK(18, 16)
|
||||
#define GMAC_RXQCTRL_MCBCQ_SHIFT 16
|
||||
#define GMAC_RXQCTRL_MCBCQEN BIT(20)
|
||||
#define GMAC_RXQCTRL_MCBCQEN_SHIFT 20
|
||||
#define GMAC_RXQCTRL_TACPQE BIT(21)
|
||||
#define GMAC_RXQCTRL_TACPQE_SHIFT 21
|
||||
#define GMAC_RXQCTRL_FPRQ GENMASK(26, 24)
|
||||
#define GMAC_RXQCTRL_FPRQ_SHIFT 24
|
||||
|
||||
/* MAC Packet Filtering */
|
||||
#define GMAC_PACKET_FILTER_PR BIT(0)
|
||||
#define GMAC_PACKET_FILTER_HMC BIT(2)
|
||||
#define GMAC_PACKET_FILTER_PM BIT(4)
|
||||
#define GMAC_PACKET_FILTER_PCF BIT(7)
|
||||
#define GMAC_PACKET_FILTER_HPF BIT(10)
|
||||
#define GMAC_PACKET_FILTER_VTFE BIT(16)
|
||||
#define GMAC_PACKET_FILTER_IPFE BIT(20)
|
||||
#define GMAC_PACKET_FILTER_RA BIT(31)
|
||||
|
||||
#define GMAC_MAX_PERFECT_ADDRESSES 128
|
||||
|
||||
/* MAC VLAN */
|
||||
#define GMAC_VLAN_EDVLP BIT(26)
|
||||
#define GMAC_VLAN_VTHM BIT(25)
|
||||
#define GMAC_VLAN_DOVLTC BIT(20)
|
||||
#define GMAC_VLAN_ESVL BIT(18)
|
||||
#define GMAC_VLAN_ETV BIT(16)
|
||||
#define GMAC_VLAN_VID GENMASK(15, 0)
|
||||
#define GMAC_VLAN_VLTI BIT(20)
|
||||
#define GMAC_VLAN_CSVL BIT(19)
|
||||
#define GMAC_VLAN_VLC GENMASK(17, 16)
|
||||
#define GMAC_VLAN_VLC_SHIFT 16
|
||||
#define GMAC_VLAN_VLHT GENMASK(15, 0)
|
||||
|
||||
/* MAC VLAN Tag */
|
||||
#define GMAC_VLAN_TAG_VID GENMASK(15, 0)
|
||||
#define GMAC_VLAN_TAG_ETV BIT(16)
|
||||
|
||||
/* MAC VLAN Tag Control */
|
||||
#define GMAC_VLAN_TAG_CTRL_OB BIT(0)
|
||||
#define GMAC_VLAN_TAG_CTRL_CT BIT(1)
|
||||
#define GMAC_VLAN_TAG_CTRL_OFS_MASK GENMASK(6, 2)
|
||||
#define GMAC_VLAN_TAG_CTRL_OFS_SHIFT 2
|
||||
#define GMAC_VLAN_TAG_CTRL_EVLS_MASK GENMASK(22, 21)
|
||||
#define GMAC_VLAN_TAG_CTRL_EVLS_SHIFT 21
|
||||
#define GMAC_VLAN_TAG_CTRL_EVLRXS BIT(24)
|
||||
|
||||
#define GMAC_VLAN_TAG_STRIP_NONE (0x0 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT)
|
||||
#define GMAC_VLAN_TAG_STRIP_PASS (0x1 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT)
|
||||
#define GMAC_VLAN_TAG_STRIP_FAIL (0x2 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT)
|
||||
#define GMAC_VLAN_TAG_STRIP_ALL (0x3 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT)
|
||||
|
||||
/* MAC VLAN Tag Data/Filter */
|
||||
#define GMAC_VLAN_TAG_DATA_VID GENMASK(15, 0)
|
||||
#define GMAC_VLAN_TAG_DATA_VEN BIT(16)
|
||||
#define GMAC_VLAN_TAG_DATA_ETV BIT(17)
|
||||
|
||||
/* MAC RX Queue Enable */
|
||||
#define GMAC_RX_QUEUE_CLEAR(queue) ~(GENMASK(1, 0) << ((queue) * 2))
|
||||
#define GMAC_RX_AV_QUEUE_ENABLE(queue) BIT((queue) * 2)
|
||||
#define GMAC_RX_DCB_QUEUE_ENABLE(queue) BIT(((queue) * 2) + 1)
|
||||
|
||||
/* MAC Flow Control RX */
|
||||
#define GMAC_RX_FLOW_CTRL_RFE BIT(0)
|
||||
|
||||
/* RX Queues Priorities */
|
||||
#define GMAC_RXQCTRL_PSRQX_MASK(x) GENMASK(7 + ((x) * 8), 0 + ((x) * 8))
|
||||
#define GMAC_RXQCTRL_PSRQX_SHIFT(x) ((x) * 8)
|
||||
|
||||
/* TX Queues Priorities */
|
||||
#define GMAC_TXQCTRL_PSTQX_MASK(x) GENMASK(7 + ((x) * 8), 0 + ((x) * 8))
|
||||
#define GMAC_TXQCTRL_PSTQX_SHIFT(x) ((x) * 8)
|
||||
|
||||
/* MAC Flow Control TX */
|
||||
#define GMAC_TX_FLOW_CTRL_TFE BIT(1)
|
||||
#define GMAC_TX_FLOW_CTRL_PT_SHIFT 16
|
||||
|
||||
/* MAC Interrupt bitmap*/
|
||||
#define GMAC_INT_RGSMIIS BIT(0)
|
||||
#define GMAC_INT_PCS_LINK BIT(1)
|
||||
#define GMAC_INT_PCS_ANE BIT(2)
|
||||
#define GMAC_INT_PCS_PHYIS BIT(3)
|
||||
#define GMAC_INT_PMT_EN BIT(4)
|
||||
#define GMAC_INT_LPI_EN BIT(5)
|
||||
#define GMAC_INT_TSIE BIT(12)
|
||||
|
||||
#define GMAC_PCS_IRQ_DEFAULT (GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK | \
|
||||
GMAC_INT_PCS_ANE)
|
||||
|
||||
#define GMAC_INT_DEFAULT_ENABLE (GMAC_INT_PMT_EN | GMAC_INT_LPI_EN | \
|
||||
GMAC_INT_TSIE)
|
||||
|
||||
enum dwmac4_irq_status {
|
||||
time_stamp_irq = 0x00001000,
|
||||
mmc_rx_csum_offload_irq = 0x00000800,
|
||||
mmc_tx_irq = 0x00000400,
|
||||
mmc_rx_irq = 0x00000200,
|
||||
mmc_irq = 0x00000100,
|
||||
lpi_irq = 0x00000020,
|
||||
pmt_irq = 0x00000010,
|
||||
};
|
||||
|
||||
/* MAC PMT bitmap */
|
||||
enum power_event {
|
||||
pointer_reset = 0x80000000,
|
||||
global_unicast = 0x00000200,
|
||||
wake_up_rx_frame = 0x00000040,
|
||||
magic_frame = 0x00000020,
|
||||
wake_up_frame_en = 0x00000004,
|
||||
magic_pkt_en = 0x00000002,
|
||||
power_down = 0x00000001,
|
||||
};
|
||||
|
||||
/* Energy Efficient Ethernet (EEE) for GMAC4
|
||||
*
|
||||
* LPI status, timer and control register offset
|
||||
*/
|
||||
#define GMAC4_LPI_CTRL_STATUS 0xd0
|
||||
#define GMAC4_LPI_TIMER_CTRL 0xd4
|
||||
#define GMAC4_LPI_ENTRY_TIMER 0xd8
|
||||
#define GMAC4_MAC_ONEUS_TIC_COUNTER 0xdc
|
||||
|
||||
/* LPI control and status defines */
|
||||
#define GMAC4_LPI_CTRL_STATUS_LPITCSE BIT(21) /* LPI Tx Clock Stop Enable */
|
||||
#define GMAC4_LPI_CTRL_STATUS_LPIATE BIT(20) /* LPI Timer Enable */
|
||||
#define GMAC4_LPI_CTRL_STATUS_LPITXA BIT(19) /* Enable LPI TX Automate */
|
||||
#define GMAC4_LPI_CTRL_STATUS_PLS BIT(17) /* PHY Link Status */
|
||||
#define GMAC4_LPI_CTRL_STATUS_LPIEN BIT(16) /* LPI Enable */
|
||||
#define GMAC4_LPI_CTRL_STATUS_RLPIEX BIT(3) /* Receive LPI Exit */
|
||||
#define GMAC4_LPI_CTRL_STATUS_RLPIEN BIT(2) /* Receive LPI Entry */
|
||||
#define GMAC4_LPI_CTRL_STATUS_TLPIEX BIT(1) /* Transmit LPI Exit */
|
||||
#define GMAC4_LPI_CTRL_STATUS_TLPIEN BIT(0) /* Transmit LPI Entry */
|
||||
|
||||
/* MAC Debug bitmap */
|
||||
#define GMAC_DEBUG_TFCSTS_MASK GENMASK(18, 17)
|
||||
#define GMAC_DEBUG_TFCSTS_SHIFT 17
|
||||
#define GMAC_DEBUG_TFCSTS_IDLE 0
|
||||
#define GMAC_DEBUG_TFCSTS_WAIT 1
|
||||
#define GMAC_DEBUG_TFCSTS_GEN_PAUSE 2
|
||||
#define GMAC_DEBUG_TFCSTS_XFER 3
|
||||
#define GMAC_DEBUG_TPESTS BIT(16)
|
||||
#define GMAC_DEBUG_RFCFCSTS_MASK GENMASK(2, 1)
|
||||
#define GMAC_DEBUG_RFCFCSTS_SHIFT 1
|
||||
#define GMAC_DEBUG_RPESTS BIT(0)
|
||||
|
||||
/* MAC config */
|
||||
#define GMAC_CONFIG_ARPEN BIT(31)
|
||||
#define GMAC_CONFIG_SARC GENMASK(30, 28)
|
||||
#define GMAC_CONFIG_SARC_SHIFT 28
|
||||
#define GMAC_CONFIG_IPC BIT(27)
|
||||
#define GMAC_CONFIG_IPG GENMASK(26, 24)
|
||||
#define GMAC_CONFIG_IPG_SHIFT 24
|
||||
#define GMAC_CONFIG_2K BIT(22)
|
||||
#define GMAC_CONFIG_ACS BIT(20)
|
||||
#define GMAC_CONFIG_BE BIT(18)
|
||||
#define GMAC_CONFIG_JD BIT(17)
|
||||
#define GMAC_CONFIG_JE BIT(16)
|
||||
#define GMAC_CONFIG_PS BIT(15)
|
||||
#define GMAC_CONFIG_FES BIT(14)
|
||||
#define GMAC_CONFIG_FES_SHIFT 14
|
||||
#define GMAC_CONFIG_DM BIT(13)
|
||||
#define GMAC_CONFIG_LM BIT(12)
|
||||
#define GMAC_CONFIG_DCRS BIT(9)
|
||||
#define GMAC_CONFIG_TE BIT(1)
|
||||
#define GMAC_CONFIG_RE BIT(0)
|
||||
|
||||
/* MAC extended config */
|
||||
#define GMAC_CONFIG_EIPG GENMASK(29, 25)
|
||||
#define GMAC_CONFIG_EIPG_SHIFT 25
|
||||
#define GMAC_CONFIG_EIPG_EN BIT(24)
|
||||
#define GMAC_CONFIG_HDSMS GENMASK(22, 20)
|
||||
#define GMAC_CONFIG_HDSMS_SHIFT 20
|
||||
#define GMAC_CONFIG_HDSMS_256 (0x2 << GMAC_CONFIG_HDSMS_SHIFT)
|
||||
|
||||
/* MAC HW features0 bitmap */
|
||||
#define GMAC_HW_FEAT_SAVLANINS BIT(27)
|
||||
#define GMAC_HW_FEAT_ADDMAC BIT(18)
|
||||
#define GMAC_HW_FEAT_RXCOESEL BIT(16)
|
||||
#define GMAC_HW_FEAT_TXCOSEL BIT(14)
|
||||
#define GMAC_HW_FEAT_EEESEL BIT(13)
|
||||
#define GMAC_HW_FEAT_TSSEL BIT(12)
|
||||
#define GMAC_HW_FEAT_ARPOFFSEL BIT(9)
|
||||
#define GMAC_HW_FEAT_MMCSEL BIT(8)
|
||||
#define GMAC_HW_FEAT_MGKSEL BIT(7)
|
||||
#define GMAC_HW_FEAT_RWKSEL BIT(6)
|
||||
#define GMAC_HW_FEAT_SMASEL BIT(5)
|
||||
#define GMAC_HW_FEAT_VLHASH BIT(4)
|
||||
#define GMAC_HW_FEAT_PCSSEL BIT(3)
|
||||
#define GMAC_HW_FEAT_HDSEL BIT(2)
|
||||
#define GMAC_HW_FEAT_GMIISEL BIT(1)
|
||||
#define GMAC_HW_FEAT_MIISEL BIT(0)
|
||||
|
||||
/* MAC HW features1 bitmap */
|
||||
#define GMAC_HW_FEAT_L3L4FNUM GENMASK(30, 27)
|
||||
#define GMAC_HW_HASH_TB_SZ GENMASK(25, 24)
|
||||
#define GMAC_HW_FEAT_AVSEL BIT(20)
|
||||
#define GMAC_HW_TSOEN BIT(18)
|
||||
#define GMAC_HW_FEAT_SPHEN BIT(17)
|
||||
#define GMAC_HW_ADDR64 GENMASK(15, 14)
|
||||
#define GMAC_HW_TXFIFOSIZE GENMASK(10, 6)
|
||||
#define GMAC_HW_RXFIFOSIZE GENMASK(4, 0)
|
||||
|
||||
/* MAC HW features2 bitmap */
|
||||
#define GMAC_HW_FEAT_AUXSNAPNUM GENMASK(30, 28)
|
||||
#define GMAC_HW_FEAT_PPSOUTNUM GENMASK(26, 24)
|
||||
#define GMAC_HW_FEAT_TXCHCNT GENMASK(21, 18)
|
||||
#define GMAC_HW_FEAT_RXCHCNT GENMASK(15, 12)
|
||||
#define GMAC_HW_FEAT_TXQCNT GENMASK(9, 6)
|
||||
#define GMAC_HW_FEAT_RXQCNT GENMASK(3, 0)
|
||||
|
||||
/* MAC HW features3 bitmap */
|
||||
#define GMAC_HW_FEAT_ASP GENMASK(29, 28)
|
||||
#define GMAC_HW_FEAT_TBSSEL BIT(27)
|
||||
#define GMAC_HW_FEAT_FPESEL BIT(26)
|
||||
#define GMAC_HW_FEAT_ESTWID GENMASK(21, 20)
|
||||
#define GMAC_HW_FEAT_ESTDEP GENMASK(19, 17)
|
||||
#define GMAC_HW_FEAT_ESTSEL BIT(16)
|
||||
#define GMAC_HW_FEAT_FRPES GENMASK(14, 13)
|
||||
#define GMAC_HW_FEAT_FRPBS GENMASK(12, 11)
|
||||
#define GMAC_HW_FEAT_FRPSEL BIT(10)
|
||||
#define GMAC_HW_FEAT_DVLAN BIT(5)
|
||||
#define GMAC_HW_FEAT_NRVF GENMASK(2, 0)
|
||||
|
||||
/* MAC extended config 1 */
|
||||
#define GMAC_CONFIG1_SAVE_EN BIT(24)
|
||||
#define GMAC_CONFIG1_SPLM(v) FIELD_PREP(GENMASK(9, 8), v)
|
||||
|
||||
/* GMAC GPIO Status reg */
|
||||
#define GMAC_GPO0 BIT(16)
|
||||
#define GMAC_GPO1 BIT(17)
|
||||
#define GMAC_GPO2 BIT(18)
|
||||
#define GMAC_GPO3 BIT(19)
|
||||
|
||||
/* MAC HW ADDR regs */
|
||||
#define GMAC_HI_DCS GENMASK(18, 16)
|
||||
#define GMAC_HI_DCS_SHIFT 16
|
||||
#define GMAC_HI_REG_AE BIT(31)
|
||||
|
||||
/* L3/L4 Filters regs */
|
||||
#define GMAC_L4DPIM0 BIT(21)
|
||||
#define GMAC_L4DPM0 BIT(20)
|
||||
#define GMAC_L4SPIM0 BIT(19)
|
||||
#define GMAC_L4SPM0 BIT(18)
|
||||
#define GMAC_L4PEN0 BIT(16)
|
||||
#define GMAC_L3DAIM0 BIT(5)
|
||||
#define GMAC_L3DAM0 BIT(4)
|
||||
#define GMAC_L3SAIM0 BIT(3)
|
||||
#define GMAC_L3SAM0 BIT(2)
|
||||
#define GMAC_L3PEN0 BIT(0)
|
||||
#define GMAC_L4DP0 GENMASK(31, 16)
|
||||
#define GMAC_L4DP0_SHIFT 16
|
||||
#define GMAC_L4SP0 GENMASK(15, 0)
|
||||
|
||||
/* MAC Timestamp Status */
|
||||
#define GMAC_TIMESTAMP_AUXTSTRIG BIT(2)
|
||||
#define GMAC_TIMESTAMP_ATSNS_MASK GENMASK(29, 25)
|
||||
#define GMAC_TIMESTAMP_ATSNS_SHIFT 25
|
||||
|
||||
/* MTL registers */
|
||||
#define MTL_OPERATION_MODE 0x00000c00
|
||||
#define MTL_FRPE BIT(15)
|
||||
#define MTL_OPERATION_SCHALG_MASK GENMASK(6, 5)
|
||||
#define MTL_OPERATION_SCHALG_WRR (0x0 << 5)
|
||||
#define MTL_OPERATION_SCHALG_WFQ (0x1 << 5)
|
||||
#define MTL_OPERATION_SCHALG_DWRR (0x2 << 5)
|
||||
#define MTL_OPERATION_SCHALG_SP (0x3 << 5)
|
||||
#define MTL_OPERATION_RAA BIT(2)
|
||||
#define MTL_OPERATION_RAA_SP (0x0 << 2)
|
||||
#define MTL_OPERATION_RAA_WSP (0x1 << 2)
|
||||
|
||||
#define MTL_INT_STATUS 0x00000c20
|
||||
#define MTL_INT_QX(x) BIT(x)
|
||||
|
||||
#define MTL_RXQ_DMA_MAP0 0x00000c30 /* queue 0 to 3 */
|
||||
#define MTL_RXQ_DMA_MAP1 0x00000c34 /* queue 4 to 7 */
|
||||
#define MTL_RXQ_DMA_QXMDMACH_MASK(x) (0xf << 8 * (x))
|
||||
#define MTL_RXQ_DMA_QXMDMACH(chan, q) ((chan) << (8 * (q)))
|
||||
|
||||
#define MTL_CHAN_BASE_ADDR 0x00000d00
|
||||
#define MTL_CHAN_BASE_OFFSET 0x40
|
||||
|
||||
static inline u32 mtl_chanx_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->mtl_chan + (x * addrs->mtl_chan_offset);
|
||||
else
|
||||
addr = MTL_CHAN_BASE_ADDR + (x * MTL_CHAN_BASE_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define MTL_CHAN_TX_OP_MODE(addrs, x) mtl_chanx_base_addr(addrs, x)
|
||||
#define MTL_CHAN_TX_DEBUG(addrs, x) (mtl_chanx_base_addr(addrs, x) + 0x8)
|
||||
#define MTL_CHAN_INT_CTRL(addrs, x) (mtl_chanx_base_addr(addrs, x) + 0x2c)
|
||||
#define MTL_CHAN_RX_OP_MODE(addrs, x) (mtl_chanx_base_addr(addrs, x) + 0x30)
|
||||
#define MTL_CHAN_RX_DEBUG(addrs, x) (mtl_chanx_base_addr(addrs, x) + 0x38)
|
||||
|
||||
#define MTL_OP_MODE_RSF BIT(5)
|
||||
#define MTL_OP_MODE_TXQEN_MASK GENMASK(3, 2)
|
||||
#define MTL_OP_MODE_TXQEN_AV BIT(2)
|
||||
#define MTL_OP_MODE_TXQEN BIT(3)
|
||||
#define MTL_OP_MODE_TSF BIT(1)
|
||||
|
||||
#define MTL_OP_MODE_TQS_MASK GENMASK(24, 16)
|
||||
#define MTL_OP_MODE_TQS_SHIFT 16
|
||||
|
||||
#define MTL_OP_MODE_TTC_MASK 0x70
|
||||
#define MTL_OP_MODE_TTC_SHIFT 4
|
||||
|
||||
#define MTL_OP_MODE_TTC_32 0
|
||||
#define MTL_OP_MODE_TTC_64 (1 << MTL_OP_MODE_TTC_SHIFT)
|
||||
#define MTL_OP_MODE_TTC_96 (2 << MTL_OP_MODE_TTC_SHIFT)
|
||||
#define MTL_OP_MODE_TTC_128 (3 << MTL_OP_MODE_TTC_SHIFT)
|
||||
#define MTL_OP_MODE_TTC_192 (4 << MTL_OP_MODE_TTC_SHIFT)
|
||||
#define MTL_OP_MODE_TTC_256 (5 << MTL_OP_MODE_TTC_SHIFT)
|
||||
#define MTL_OP_MODE_TTC_384 (6 << MTL_OP_MODE_TTC_SHIFT)
|
||||
#define MTL_OP_MODE_TTC_512 (7 << MTL_OP_MODE_TTC_SHIFT)
|
||||
|
||||
#define MTL_OP_MODE_RQS_MASK GENMASK(29, 20)
|
||||
#define MTL_OP_MODE_RQS_SHIFT 20
|
||||
|
||||
#define MTL_OP_MODE_RFD_MASK GENMASK(19, 14)
|
||||
#define MTL_OP_MODE_RFD_SHIFT 14
|
||||
|
||||
#define MTL_OP_MODE_RFA_MASK GENMASK(13, 8)
|
||||
#define MTL_OP_MODE_RFA_SHIFT 8
|
||||
|
||||
#define MTL_OP_MODE_EHFC BIT(7)
|
||||
|
||||
#define MTL_OP_MODE_RTC_MASK 0x18
|
||||
#define MTL_OP_MODE_RTC_SHIFT 3
|
||||
|
||||
#define MTL_OP_MODE_RTC_32 (1 << MTL_OP_MODE_RTC_SHIFT)
|
||||
#define MTL_OP_MODE_RTC_64 0
|
||||
#define MTL_OP_MODE_RTC_96 (2 << MTL_OP_MODE_RTC_SHIFT)
|
||||
#define MTL_OP_MODE_RTC_128 (3 << MTL_OP_MODE_RTC_SHIFT)
|
||||
|
||||
/* MTL ETS Control register */
|
||||
#define MTL_ETS_CTRL_BASE_ADDR 0x00000d10
|
||||
#define MTL_ETS_CTRL_BASE_OFFSET 0x40
|
||||
|
||||
static inline u32 mtl_etsx_ctrl_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->mtl_ets_ctrl + (x * addrs->mtl_ets_ctrl_offset);
|
||||
else
|
||||
addr = MTL_ETS_CTRL_BASE_ADDR + (x * MTL_ETS_CTRL_BASE_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define MTL_ETS_CTRL_CC BIT(3)
|
||||
#define MTL_ETS_CTRL_AVALG BIT(2)
|
||||
|
||||
/* MTL Queue Quantum Weight */
|
||||
#define MTL_TXQ_WEIGHT_BASE_ADDR 0x00000d18
|
||||
#define MTL_TXQ_WEIGHT_BASE_OFFSET 0x40
|
||||
|
||||
static inline u32 mtl_txqx_weight_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->mtl_txq_weight + (x * addrs->mtl_txq_weight_offset);
|
||||
else
|
||||
addr = MTL_TXQ_WEIGHT_BASE_ADDR + (x * MTL_TXQ_WEIGHT_BASE_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define MTL_TXQ_WEIGHT_ISCQW_MASK GENMASK(20, 0)
|
||||
|
||||
/* MTL sendSlopeCredit register */
|
||||
#define MTL_SEND_SLP_CRED_BASE_ADDR 0x00000d1c
|
||||
#define MTL_SEND_SLP_CRED_OFFSET 0x40
|
||||
|
||||
static inline u32 mtl_send_slp_credx_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->mtl_send_slp_cred + (x * addrs->mtl_send_slp_cred_offset);
|
||||
else
|
||||
addr = MTL_SEND_SLP_CRED_BASE_ADDR + (x * MTL_SEND_SLP_CRED_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define MTL_SEND_SLP_CRED_SSC_MASK GENMASK(13, 0)
|
||||
|
||||
/* MTL hiCredit register */
|
||||
#define MTL_HIGH_CRED_BASE_ADDR 0x00000d20
|
||||
#define MTL_HIGH_CRED_OFFSET 0x40
|
||||
|
||||
static inline u32 mtl_high_credx_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->mtl_high_cred + (x * addrs->mtl_high_cred_offset);
|
||||
else
|
||||
addr = MTL_HIGH_CRED_BASE_ADDR + (x * MTL_HIGH_CRED_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define MTL_HIGH_CRED_HC_MASK GENMASK(28, 0)
|
||||
|
||||
/* MTL loCredit register */
|
||||
#define MTL_LOW_CRED_BASE_ADDR 0x00000d24
|
||||
#define MTL_LOW_CRED_OFFSET 0x40
|
||||
|
||||
static inline u32 mtl_low_credx_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->mtl_low_cred + (x * addrs->mtl_low_cred_offset);
|
||||
else
|
||||
addr = MTL_LOW_CRED_BASE_ADDR + (x * MTL_LOW_CRED_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define MTL_HIGH_CRED_LC_MASK GENMASK(28, 0)
|
||||
|
||||
/* MTL debug */
|
||||
#define MTL_DEBUG_TXSTSFSTS BIT(5)
|
||||
#define MTL_DEBUG_TXFSTS BIT(4)
|
||||
#define MTL_DEBUG_TWCSTS BIT(3)
|
||||
|
||||
/* MTL debug: Tx FIFO Read Controller Status */
|
||||
#define MTL_DEBUG_TRCSTS_MASK GENMASK(2, 1)
|
||||
#define MTL_DEBUG_TRCSTS_SHIFT 1
|
||||
#define MTL_DEBUG_TRCSTS_IDLE 0
|
||||
#define MTL_DEBUG_TRCSTS_READ 1
|
||||
#define MTL_DEBUG_TRCSTS_TXW 2
|
||||
#define MTL_DEBUG_TRCSTS_WRITE 3
|
||||
#define MTL_DEBUG_TXPAUSED BIT(0)
|
||||
|
||||
/* MAC debug: GMII or MII Transmit Protocol Engine Status */
|
||||
#define MTL_DEBUG_RXFSTS_MASK GENMASK(5, 4)
|
||||
#define MTL_DEBUG_RXFSTS_SHIFT 4
|
||||
#define MTL_DEBUG_RXFSTS_EMPTY 0
|
||||
#define MTL_DEBUG_RXFSTS_BT 1
|
||||
#define MTL_DEBUG_RXFSTS_AT 2
|
||||
#define MTL_DEBUG_RXFSTS_FULL 3
|
||||
#define MTL_DEBUG_RRCSTS_MASK GENMASK(2, 1)
|
||||
#define MTL_DEBUG_RRCSTS_SHIFT 1
|
||||
#define MTL_DEBUG_RRCSTS_IDLE 0
|
||||
#define MTL_DEBUG_RRCSTS_RDATA 1
|
||||
#define MTL_DEBUG_RRCSTS_RSTAT 2
|
||||
#define MTL_DEBUG_RRCSTS_FLUSH 3
|
||||
#define MTL_DEBUG_RWCSTS BIT(0)
|
||||
|
||||
/* MTL interrupt */
|
||||
#define MTL_RX_OVERFLOW_INT_EN BIT(24)
|
||||
#define MTL_RX_OVERFLOW_INT BIT(16)
|
||||
|
||||
/* Default operating mode of the MAC */
|
||||
#define GMAC_CORE_INIT (GMAC_CONFIG_JD | GMAC_CONFIG_PS | \
|
||||
GMAC_CONFIG_BE | GMAC_CONFIG_DCRS | \
|
||||
GMAC_CONFIG_JE)
|
||||
|
||||
/* To dump the core regs excluding the Address Registers */
|
||||
#define GMAC_REG_NUM 132
|
||||
|
||||
/* MTL debug */
|
||||
#define MTL_DEBUG_TXSTSFSTS BIT(5)
|
||||
#define MTL_DEBUG_TXFSTS BIT(4)
|
||||
#define MTL_DEBUG_TWCSTS BIT(3)
|
||||
|
||||
/* MTL debug: Tx FIFO Read Controller Status */
|
||||
#define MTL_DEBUG_TRCSTS_MASK GENMASK(2, 1)
|
||||
#define MTL_DEBUG_TRCSTS_SHIFT 1
|
||||
#define MTL_DEBUG_TRCSTS_IDLE 0
|
||||
#define MTL_DEBUG_TRCSTS_READ 1
|
||||
#define MTL_DEBUG_TRCSTS_TXW 2
|
||||
#define MTL_DEBUG_TRCSTS_WRITE 3
|
||||
#define MTL_DEBUG_TXPAUSED BIT(0)
|
||||
|
||||
/* MAC debug: GMII or MII Transmit Protocol Engine Status */
|
||||
#define MTL_DEBUG_RXFSTS_MASK GENMASK(5, 4)
|
||||
#define MTL_DEBUG_RXFSTS_SHIFT 4
|
||||
#define MTL_DEBUG_RXFSTS_EMPTY 0
|
||||
#define MTL_DEBUG_RXFSTS_BT 1
|
||||
#define MTL_DEBUG_RXFSTS_AT 2
|
||||
#define MTL_DEBUG_RXFSTS_FULL 3
|
||||
#define MTL_DEBUG_RRCSTS_MASK GENMASK(2, 1)
|
||||
#define MTL_DEBUG_RRCSTS_SHIFT 1
|
||||
#define MTL_DEBUG_RRCSTS_IDLE 0
|
||||
#define MTL_DEBUG_RRCSTS_RDATA 1
|
||||
#define MTL_DEBUG_RRCSTS_RSTAT 2
|
||||
#define MTL_DEBUG_RRCSTS_FLUSH 3
|
||||
#define MTL_DEBUG_RWCSTS BIT(0)
|
||||
|
||||
/* SGMII/RGMII status register */
|
||||
#define GMAC_PHYIF_CTRLSTATUS_TC BIT(0)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_LUD BIT(1)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SMIDRXS BIT(4)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_LNKMOD BIT(16)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED GENMASK(18, 17)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED_SHIFT 17
|
||||
#define GMAC_PHYIF_CTRLSTATUS_LNKSTS BIT(19)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_JABTO BIT(20)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_FALSECARDET BIT(21)
|
||||
/* LNKSPEED */
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED_125 0x2
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED_25 0x1
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED_2_5 0x0
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac4_dma_ops;
|
||||
extern const struct stmmac_dma_ops dwmac410_dma_ops;
|
||||
#endif /* __DWMAC4_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,594 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* This contains the functions to handle the descriptors for DesignWare databook
|
||||
* 4.xx.
|
||||
*
|
||||
* Copyright (C) 2015 STMicroelectronics Ltd
|
||||
*
|
||||
* Author: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/stmmac.h>
|
||||
#include "common-6.12-ethercat.h"
|
||||
#include "dwmac4-6.12-ethercat.h"
|
||||
#include "dwmac4_descs-6.12-ethercat.h"
|
||||
|
||||
static int dwmac4_wrback_get_tx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p,
|
||||
void __iomem *ioaddr)
|
||||
{
|
||||
unsigned int tdes3;
|
||||
int ret = tx_done;
|
||||
|
||||
tdes3 = le32_to_cpu(p->des3);
|
||||
|
||||
/* Get tx owner first */
|
||||
if (unlikely(tdes3 & TDES3_OWN))
|
||||
return tx_dma_own;
|
||||
|
||||
/* Verify tx error by looking at the last segment. */
|
||||
if (likely(!(tdes3 & TDES3_LAST_DESCRIPTOR)))
|
||||
return tx_not_ls;
|
||||
|
||||
if (unlikely(tdes3 & TDES3_ERROR_SUMMARY)) {
|
||||
ret = tx_err;
|
||||
|
||||
if (unlikely(tdes3 & TDES3_JABBER_TIMEOUT))
|
||||
x->tx_jabber++;
|
||||
if (unlikely(tdes3 & TDES3_PACKET_FLUSHED))
|
||||
x->tx_frame_flushed++;
|
||||
if (unlikely(tdes3 & TDES3_LOSS_CARRIER)) {
|
||||
x->tx_losscarrier++;
|
||||
}
|
||||
if (unlikely(tdes3 & TDES3_NO_CARRIER)) {
|
||||
x->tx_carrier++;
|
||||
}
|
||||
if (unlikely((tdes3 & TDES3_LATE_COLLISION) ||
|
||||
(tdes3 & TDES3_EXCESSIVE_COLLISION)))
|
||||
x->tx_collision +=
|
||||
(tdes3 & TDES3_COLLISION_COUNT_MASK)
|
||||
>> TDES3_COLLISION_COUNT_SHIFT;
|
||||
|
||||
if (unlikely(tdes3 & TDES3_EXCESSIVE_DEFERRAL))
|
||||
x->tx_deferred++;
|
||||
|
||||
if (unlikely(tdes3 & TDES3_UNDERFLOW_ERROR)) {
|
||||
x->tx_underflow++;
|
||||
ret |= tx_err_bump_tc;
|
||||
}
|
||||
|
||||
if (unlikely(tdes3 & TDES3_IP_HDR_ERROR))
|
||||
x->tx_ip_header_error++;
|
||||
|
||||
if (unlikely(tdes3 & TDES3_PAYLOAD_ERROR))
|
||||
x->tx_payload_error++;
|
||||
}
|
||||
|
||||
if (unlikely(tdes3 & TDES3_DEFERRED))
|
||||
x->tx_deferred++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwmac4_wrback_get_rx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p)
|
||||
{
|
||||
unsigned int rdes1 = le32_to_cpu(p->des1);
|
||||
unsigned int rdes2 = le32_to_cpu(p->des2);
|
||||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
int message_type;
|
||||
int ret = good_frame;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_OWN))
|
||||
return dma_own;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_CONTEXT_DESCRIPTOR))
|
||||
return discard_frame;
|
||||
if (likely(!(rdes3 & RDES3_LAST_DESCRIPTOR)))
|
||||
return rx_not_ls;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_ERROR_SUMMARY)) {
|
||||
if (unlikely(rdes3 & RDES3_GIANT_PACKET))
|
||||
x->rx_length++;
|
||||
if (unlikely(rdes3 & RDES3_OVERFLOW_ERROR))
|
||||
x->rx_gmac_overflow++;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_RECEIVE_WATCHDOG))
|
||||
x->rx_watchdog++;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_RECEIVE_ERROR))
|
||||
x->rx_mii++;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_CRC_ERROR))
|
||||
x->rx_crc_errors++;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_DRIBBLE_ERROR))
|
||||
x->dribbling_bit++;
|
||||
|
||||
ret = discard_frame;
|
||||
}
|
||||
|
||||
message_type = (rdes1 & ERDES4_MSG_TYPE_MASK) >> 8;
|
||||
|
||||
if (rdes1 & RDES1_IP_HDR_ERROR)
|
||||
x->ip_hdr_err++;
|
||||
if (rdes1 & RDES1_IP_CSUM_BYPASSED)
|
||||
x->ip_csum_bypassed++;
|
||||
if (rdes1 & RDES1_IPV4_HEADER)
|
||||
x->ipv4_pkt_rcvd++;
|
||||
if (rdes1 & RDES1_IPV6_HEADER)
|
||||
x->ipv6_pkt_rcvd++;
|
||||
|
||||
if (message_type == RDES_EXT_NO_PTP)
|
||||
x->no_ptp_rx_msg_type_ext++;
|
||||
else if (message_type == RDES_EXT_SYNC)
|
||||
x->ptp_rx_msg_type_sync++;
|
||||
else if (message_type == RDES_EXT_FOLLOW_UP)
|
||||
x->ptp_rx_msg_type_follow_up++;
|
||||
else if (message_type == RDES_EXT_DELAY_REQ)
|
||||
x->ptp_rx_msg_type_delay_req++;
|
||||
else if (message_type == RDES_EXT_DELAY_RESP)
|
||||
x->ptp_rx_msg_type_delay_resp++;
|
||||
else if (message_type == RDES_EXT_PDELAY_REQ)
|
||||
x->ptp_rx_msg_type_pdelay_req++;
|
||||
else if (message_type == RDES_EXT_PDELAY_RESP)
|
||||
x->ptp_rx_msg_type_pdelay_resp++;
|
||||
else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP)
|
||||
x->ptp_rx_msg_type_pdelay_follow_up++;
|
||||
else if (message_type == RDES_PTP_ANNOUNCE)
|
||||
x->ptp_rx_msg_type_announce++;
|
||||
else if (message_type == RDES_PTP_MANAGEMENT)
|
||||
x->ptp_rx_msg_type_management++;
|
||||
else if (message_type == RDES_PTP_PKT_RESERVED_TYPE)
|
||||
x->ptp_rx_msg_pkt_reserved_type++;
|
||||
|
||||
if (rdes1 & RDES1_PTP_PACKET_TYPE)
|
||||
x->ptp_frame_type++;
|
||||
if (rdes1 & RDES1_PTP_VER)
|
||||
x->ptp_ver++;
|
||||
if (rdes1 & RDES1_TIMESTAMP_DROPPED)
|
||||
x->timestamp_dropped++;
|
||||
|
||||
if (unlikely(rdes2 & RDES2_SA_FILTER_FAIL)) {
|
||||
x->sa_rx_filter_fail++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(rdes2 & RDES2_DA_FILTER_FAIL)) {
|
||||
x->da_rx_filter_fail++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
|
||||
if (rdes2 & RDES2_L3_FILTER_MATCH)
|
||||
x->l3_filter_match++;
|
||||
if (rdes2 & RDES2_L4_FILTER_MATCH)
|
||||
x->l4_filter_match++;
|
||||
if ((rdes2 & RDES2_L3_L4_FILT_NB_MATCH_MASK)
|
||||
>> RDES2_L3_L4_FILT_NB_MATCH_SHIFT)
|
||||
x->l3_l4_filter_no_match++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwmac4_rd_get_tx_len(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des2) & TDES2_BUFFER1_SIZE_MASK);
|
||||
}
|
||||
|
||||
static int dwmac4_get_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des3) & TDES3_OWN) >> TDES3_OWN_SHIFT;
|
||||
}
|
||||
|
||||
static void dwmac4_set_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des3 |= cpu_to_le32(TDES3_OWN);
|
||||
}
|
||||
|
||||
static void dwmac4_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
|
||||
{
|
||||
u32 flags = (RDES3_OWN | RDES3_BUFFER1_VALID_ADDR);
|
||||
|
||||
if (!disable_rx_ic)
|
||||
flags |= RDES3_INT_ON_COMPLETION_EN;
|
||||
|
||||
p->des3 |= cpu_to_le32(flags);
|
||||
}
|
||||
|
||||
static int dwmac4_get_tx_ls(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des3) & TDES3_LAST_DESCRIPTOR)
|
||||
>> TDES3_LAST_DESCRIPTOR_SHIFT;
|
||||
}
|
||||
|
||||
static u16 dwmac4_wrback_get_rx_vlan_tci(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des0) & RDES0_VLAN_TAG_MASK);
|
||||
}
|
||||
|
||||
static bool dwmac4_wrback_get_rx_vlan_valid(struct dma_desc *p)
|
||||
{
|
||||
return ((le32_to_cpu(p->des3) & RDES3_LAST_DESCRIPTOR) &&
|
||||
(le32_to_cpu(p->des3) & RDES3_RDES0_VALID));
|
||||
}
|
||||
|
||||
static int dwmac4_wrback_get_rx_frame_len(struct dma_desc *p, int rx_coe)
|
||||
{
|
||||
return (le32_to_cpu(p->des3) & RDES3_PACKET_SIZE_MASK);
|
||||
}
|
||||
|
||||
static void dwmac4_rd_enable_tx_timestamp(struct dma_desc *p)
|
||||
{
|
||||
p->des2 |= cpu_to_le32(TDES2_TIMESTAMP_ENABLE);
|
||||
}
|
||||
|
||||
static int dwmac4_wrback_get_tx_timestamp_status(struct dma_desc *p)
|
||||
{
|
||||
/* Context type from W/B descriptor must be zero */
|
||||
if (le32_to_cpu(p->des3) & TDES3_CONTEXT_TYPE)
|
||||
return 0;
|
||||
|
||||
/* Tx Timestamp Status is 1 so des0 and des1'll have valid values */
|
||||
if (le32_to_cpu(p->des3) & TDES3_TIMESTAMP_STATUS)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dwmac4_get_timestamp(void *desc, u32 ats, u64 *ts)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
u64 ns;
|
||||
|
||||
ns = le32_to_cpu(p->des0);
|
||||
/* convert high/sec time stamp value to nanosecond */
|
||||
ns += le32_to_cpu(p->des1) * 1000000000ULL;
|
||||
|
||||
*ts = ns;
|
||||
}
|
||||
|
||||
static int dwmac4_rx_check_timestamp(void *desc)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
unsigned int rdes0 = le32_to_cpu(p->des0);
|
||||
unsigned int rdes1 = le32_to_cpu(p->des1);
|
||||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
u32 own, ctxt;
|
||||
int ret = 1;
|
||||
|
||||
own = rdes3 & RDES3_OWN;
|
||||
ctxt = ((rdes3 & RDES3_CONTEXT_DESCRIPTOR)
|
||||
>> RDES3_CONTEXT_DESCRIPTOR_SHIFT);
|
||||
|
||||
if (likely(!own && ctxt)) {
|
||||
if ((rdes0 == 0xffffffff) && (rdes1 == 0xffffffff))
|
||||
/* Corrupted value */
|
||||
ret = -EINVAL;
|
||||
else
|
||||
/* A valid Timestamp is ready to be read */
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Timestamp not ready */
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwmac4_wrback_get_rx_timestamp_status(void *desc, void *next_desc,
|
||||
u32 ats)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
int ret = -EINVAL;
|
||||
|
||||
/* Get the status from normal w/b descriptor */
|
||||
if (likely(le32_to_cpu(p->des3) & RDES3_RDES1_VALID)) {
|
||||
if (likely(le32_to_cpu(p->des1) & RDES1_TIMESTAMP_AVAILABLE)) {
|
||||
int i = 0;
|
||||
|
||||
/* Check if timestamp is OK from context descriptor */
|
||||
do {
|
||||
ret = dwmac4_rx_check_timestamp(next_desc);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
i++;
|
||||
|
||||
} while ((ret == 1) && (i < 10));
|
||||
|
||||
if (i == 10)
|
||||
ret = -EBUSY;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
if (likely(ret == 0))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwmac4_rd_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
|
||||
int mode, int end, int bfsize)
|
||||
{
|
||||
dwmac4_set_rx_owner(p, disable_rx_ic);
|
||||
}
|
||||
|
||||
static void dwmac4_rd_init_tx_desc(struct dma_desc *p, int mode, int end)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static void dwmac4_rd_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
bool csum_flag, int mode, bool tx_own,
|
||||
bool ls, unsigned int tot_pkt_len)
|
||||
{
|
||||
unsigned int tdes3 = le32_to_cpu(p->des3);
|
||||
|
||||
p->des2 |= cpu_to_le32(len & TDES2_BUFFER1_SIZE_MASK);
|
||||
|
||||
tdes3 |= tot_pkt_len & TDES3_PACKET_SIZE_MASK;
|
||||
if (is_fs)
|
||||
tdes3 |= TDES3_FIRST_DESCRIPTOR;
|
||||
else
|
||||
tdes3 &= ~TDES3_FIRST_DESCRIPTOR;
|
||||
|
||||
if (likely(csum_flag))
|
||||
tdes3 |= (TX_CIC_FULL << TDES3_CHECKSUM_INSERTION_SHIFT);
|
||||
else
|
||||
tdes3 &= ~(TX_CIC_FULL << TDES3_CHECKSUM_INSERTION_SHIFT);
|
||||
|
||||
if (ls)
|
||||
tdes3 |= TDES3_LAST_DESCRIPTOR;
|
||||
else
|
||||
tdes3 &= ~TDES3_LAST_DESCRIPTOR;
|
||||
|
||||
/* Finally set the OWN bit. Later the DMA will start! */
|
||||
if (tx_own)
|
||||
tdes3 |= TDES3_OWN;
|
||||
|
||||
if (is_fs && tx_own)
|
||||
/* When the own bit, for the first frame, has to be set, all
|
||||
* descriptors for the same frame has to be set before, to
|
||||
* avoid race condition.
|
||||
*/
|
||||
dma_wmb();
|
||||
|
||||
p->des3 = cpu_to_le32(tdes3);
|
||||
}
|
||||
|
||||
static void dwmac4_rd_prepare_tso_tx_desc(struct dma_desc *p, int is_fs,
|
||||
int len1, int len2, bool tx_own,
|
||||
bool ls, unsigned int tcphdrlen,
|
||||
unsigned int tcppayloadlen)
|
||||
{
|
||||
unsigned int tdes3 = le32_to_cpu(p->des3);
|
||||
|
||||
if (len1)
|
||||
p->des2 |= cpu_to_le32((len1 & TDES2_BUFFER1_SIZE_MASK));
|
||||
|
||||
if (len2)
|
||||
p->des2 |= cpu_to_le32((len2 << TDES2_BUFFER2_SIZE_MASK_SHIFT)
|
||||
& TDES2_BUFFER2_SIZE_MASK);
|
||||
|
||||
if (is_fs) {
|
||||
tdes3 |= TDES3_FIRST_DESCRIPTOR |
|
||||
TDES3_TCP_SEGMENTATION_ENABLE |
|
||||
((tcphdrlen << TDES3_HDR_LEN_SHIFT) &
|
||||
TDES3_SLOT_NUMBER_MASK) |
|
||||
((tcppayloadlen & TDES3_TCP_PKT_PAYLOAD_MASK));
|
||||
} else {
|
||||
tdes3 &= ~TDES3_FIRST_DESCRIPTOR;
|
||||
}
|
||||
|
||||
if (ls)
|
||||
tdes3 |= TDES3_LAST_DESCRIPTOR;
|
||||
else
|
||||
tdes3 &= ~TDES3_LAST_DESCRIPTOR;
|
||||
|
||||
/* Finally set the OWN bit. Later the DMA will start! */
|
||||
if (tx_own)
|
||||
tdes3 |= TDES3_OWN;
|
||||
|
||||
if (is_fs && tx_own)
|
||||
/* When the own bit, for the first frame, has to be set, all
|
||||
* descriptors for the same frame has to be set before, to
|
||||
* avoid race condition.
|
||||
*/
|
||||
dma_wmb();
|
||||
|
||||
p->des3 = cpu_to_le32(tdes3);
|
||||
}
|
||||
|
||||
static void dwmac4_release_tx_desc(struct dma_desc *p, int mode)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static void dwmac4_rd_set_tx_ic(struct dma_desc *p)
|
||||
{
|
||||
p->des2 |= cpu_to_le32(TDES2_INTERRUPT_ON_COMPLETION);
|
||||
}
|
||||
|
||||
static void dwmac4_display_ring(void *head, unsigned int size, bool rx,
|
||||
dma_addr_t dma_rx_phy, unsigned int desc_size)
|
||||
{
|
||||
dma_addr_t dma_addr;
|
||||
int i;
|
||||
|
||||
pr_info("%s descriptor ring:\n", rx ? "RX" : "TX");
|
||||
|
||||
if (desc_size == sizeof(struct dma_desc)) {
|
||||
struct dma_desc *p = (struct dma_desc *)head;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
dma_addr = dma_rx_phy + i * sizeof(*p);
|
||||
pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x\n",
|
||||
i, &dma_addr,
|
||||
le32_to_cpu(p->des0), le32_to_cpu(p->des1),
|
||||
le32_to_cpu(p->des2), le32_to_cpu(p->des3));
|
||||
p++;
|
||||
}
|
||||
} else if (desc_size == sizeof(struct dma_extended_desc)) {
|
||||
struct dma_extended_desc *extp = (struct dma_extended_desc *)head;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
dma_addr = dma_rx_phy + i * sizeof(*extp);
|
||||
pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
|
||||
i, &dma_addr,
|
||||
le32_to_cpu(extp->basic.des0), le32_to_cpu(extp->basic.des1),
|
||||
le32_to_cpu(extp->basic.des2), le32_to_cpu(extp->basic.des3),
|
||||
le32_to_cpu(extp->des4), le32_to_cpu(extp->des5),
|
||||
le32_to_cpu(extp->des6), le32_to_cpu(extp->des7));
|
||||
extp++;
|
||||
}
|
||||
} else if (desc_size == sizeof(struct dma_edesc)) {
|
||||
struct dma_edesc *ep = (struct dma_edesc *)head;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
dma_addr = dma_rx_phy + i * sizeof(*ep);
|
||||
pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
|
||||
i, &dma_addr,
|
||||
le32_to_cpu(ep->des4), le32_to_cpu(ep->des5),
|
||||
le32_to_cpu(ep->des6), le32_to_cpu(ep->des7),
|
||||
le32_to_cpu(ep->basic.des0), le32_to_cpu(ep->basic.des1),
|
||||
le32_to_cpu(ep->basic.des2), le32_to_cpu(ep->basic.des3));
|
||||
ep++;
|
||||
}
|
||||
} else {
|
||||
pr_err("unsupported descriptor!");
|
||||
}
|
||||
}
|
||||
|
||||
static void dwmac4_set_mss_ctxt(struct dma_desc *p, unsigned int mss)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = cpu_to_le32(mss);
|
||||
p->des3 = cpu_to_le32(TDES3_CONTEXT_TYPE | TDES3_CTXT_TCMSSV);
|
||||
}
|
||||
|
||||
static void dwmac4_set_addr(struct dma_desc *p, dma_addr_t addr)
|
||||
{
|
||||
p->des0 = cpu_to_le32(lower_32_bits(addr));
|
||||
p->des1 = cpu_to_le32(upper_32_bits(addr));
|
||||
}
|
||||
|
||||
static void dwmac4_clear(struct dma_desc *p)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static void dwmac4_set_sarc(struct dma_desc *p, u32 sarc_type)
|
||||
{
|
||||
sarc_type <<= TDES3_SA_INSERT_CTRL_SHIFT;
|
||||
|
||||
p->des3 |= cpu_to_le32(sarc_type & TDES3_SA_INSERT_CTRL_MASK);
|
||||
}
|
||||
|
||||
static int set_16kib_bfsize(int mtu)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(mtu >= BUF_SIZE_8KiB))
|
||||
ret = BUF_SIZE_16KiB;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwmac4_set_vlan_tag(struct dma_desc *p, u16 tag, u16 inner_tag,
|
||||
u32 inner_type)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
|
||||
/* Inner VLAN */
|
||||
if (inner_type) {
|
||||
u32 des = inner_tag << TDES2_IVT_SHIFT;
|
||||
|
||||
des &= TDES2_IVT_MASK;
|
||||
p->des2 = cpu_to_le32(des);
|
||||
|
||||
des = inner_type << TDES3_IVTIR_SHIFT;
|
||||
des &= TDES3_IVTIR_MASK;
|
||||
p->des3 = cpu_to_le32(des | TDES3_IVLTV);
|
||||
}
|
||||
|
||||
/* Outer VLAN */
|
||||
p->des3 |= cpu_to_le32(tag & TDES3_VLAN_TAG);
|
||||
p->des3 |= cpu_to_le32(TDES3_VLTV);
|
||||
|
||||
p->des3 |= cpu_to_le32(TDES3_CONTEXT_TYPE);
|
||||
}
|
||||
|
||||
static void dwmac4_set_vlan(struct dma_desc *p, u32 type)
|
||||
{
|
||||
type <<= TDES2_VLAN_TAG_SHIFT;
|
||||
p->des2 |= cpu_to_le32(type & TDES2_VLAN_TAG_MASK);
|
||||
}
|
||||
|
||||
static void dwmac4_get_rx_header_len(struct dma_desc *p, unsigned int *len)
|
||||
{
|
||||
*len = le32_to_cpu(p->des2) & RDES2_HL;
|
||||
}
|
||||
|
||||
static void dwmac4_set_sec_addr(struct dma_desc *p, dma_addr_t addr, bool buf2_valid)
|
||||
{
|
||||
p->des2 = cpu_to_le32(lower_32_bits(addr));
|
||||
p->des3 = cpu_to_le32(upper_32_bits(addr));
|
||||
|
||||
if (buf2_valid)
|
||||
p->des3 |= cpu_to_le32(RDES3_BUFFER2_VALID_ADDR);
|
||||
else
|
||||
p->des3 &= cpu_to_le32(~RDES3_BUFFER2_VALID_ADDR);
|
||||
}
|
||||
|
||||
static void dwmac4_set_tbs(struct dma_edesc *p, u32 sec, u32 nsec)
|
||||
{
|
||||
p->des4 = cpu_to_le32((sec & TDES4_LT) | TDES4_LTV);
|
||||
p->des5 = cpu_to_le32(nsec & TDES5_LT);
|
||||
p->des6 = 0;
|
||||
p->des7 = 0;
|
||||
}
|
||||
|
||||
const struct stmmac_desc_ops dwmac4_desc_ops = {
|
||||
.tx_status = dwmac4_wrback_get_tx_status,
|
||||
.rx_status = dwmac4_wrback_get_rx_status,
|
||||
.get_tx_len = dwmac4_rd_get_tx_len,
|
||||
.get_tx_owner = dwmac4_get_tx_owner,
|
||||
.set_tx_owner = dwmac4_set_tx_owner,
|
||||
.set_rx_owner = dwmac4_set_rx_owner,
|
||||
.get_tx_ls = dwmac4_get_tx_ls,
|
||||
.get_rx_vlan_tci = dwmac4_wrback_get_rx_vlan_tci,
|
||||
.get_rx_vlan_valid = dwmac4_wrback_get_rx_vlan_valid,
|
||||
.get_rx_frame_len = dwmac4_wrback_get_rx_frame_len,
|
||||
.enable_tx_timestamp = dwmac4_rd_enable_tx_timestamp,
|
||||
.get_tx_timestamp_status = dwmac4_wrback_get_tx_timestamp_status,
|
||||
.get_rx_timestamp_status = dwmac4_wrback_get_rx_timestamp_status,
|
||||
.get_timestamp = dwmac4_get_timestamp,
|
||||
.set_tx_ic = dwmac4_rd_set_tx_ic,
|
||||
.prepare_tx_desc = dwmac4_rd_prepare_tx_desc,
|
||||
.prepare_tso_tx_desc = dwmac4_rd_prepare_tso_tx_desc,
|
||||
.release_tx_desc = dwmac4_release_tx_desc,
|
||||
.init_rx_desc = dwmac4_rd_init_rx_desc,
|
||||
.init_tx_desc = dwmac4_rd_init_tx_desc,
|
||||
.display_ring = dwmac4_display_ring,
|
||||
.set_mss = dwmac4_set_mss_ctxt,
|
||||
.set_addr = dwmac4_set_addr,
|
||||
.clear = dwmac4_clear,
|
||||
.set_sarc = dwmac4_set_sarc,
|
||||
.set_vlan_tag = dwmac4_set_vlan_tag,
|
||||
.set_vlan = dwmac4_set_vlan,
|
||||
.get_rx_header_len = dwmac4_get_rx_header_len,
|
||||
.set_sec_addr = dwmac4_set_sec_addr,
|
||||
.set_tbs = dwmac4_set_tbs,
|
||||
};
|
||||
|
||||
const struct stmmac_mode_ops dwmac4_ring_mode_ops = {
|
||||
.set_16kib_bfsize = set_16kib_bfsize,
|
||||
};
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Header File to describe the DMA descriptors and related definitions specific
|
||||
* for DesignWare databook 4.xx.
|
||||
*
|
||||
* Copyright (C) 2015 STMicroelectronics Ltd
|
||||
*
|
||||
* Author: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
*/
|
||||
|
||||
#ifndef __DWMAC4_DESCS_H__
|
||||
#define __DWMAC4_DESCS_H__
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/* Normal transmit descriptor defines (without split feature) */
|
||||
|
||||
/* TDES2 (read format) */
|
||||
#define TDES2_BUFFER1_SIZE_MASK GENMASK(13, 0)
|
||||
#define TDES2_VLAN_TAG_MASK GENMASK(15, 14)
|
||||
#define TDES2_VLAN_TAG_SHIFT 14
|
||||
#define TDES2_BUFFER2_SIZE_MASK GENMASK(29, 16)
|
||||
#define TDES2_BUFFER2_SIZE_MASK_SHIFT 16
|
||||
#define TDES3_IVTIR_MASK GENMASK(19, 18)
|
||||
#define TDES3_IVTIR_SHIFT 18
|
||||
#define TDES3_IVLTV BIT(17)
|
||||
#define TDES2_TIMESTAMP_ENABLE BIT(30)
|
||||
#define TDES2_IVT_MASK GENMASK(31, 16)
|
||||
#define TDES2_IVT_SHIFT 16
|
||||
#define TDES2_INTERRUPT_ON_COMPLETION BIT(31)
|
||||
|
||||
/* TDES3 (read format) */
|
||||
#define TDES3_PACKET_SIZE_MASK GENMASK(14, 0)
|
||||
#define TDES3_VLAN_TAG GENMASK(15, 0)
|
||||
#define TDES3_VLTV BIT(16)
|
||||
#define TDES3_CHECKSUM_INSERTION_MASK GENMASK(17, 16)
|
||||
#define TDES3_CHECKSUM_INSERTION_SHIFT 16
|
||||
#define TDES3_TCP_PKT_PAYLOAD_MASK GENMASK(17, 0)
|
||||
#define TDES3_TCP_SEGMENTATION_ENABLE BIT(18)
|
||||
#define TDES3_HDR_LEN_SHIFT 19
|
||||
#define TDES3_SLOT_NUMBER_MASK GENMASK(22, 19)
|
||||
#define TDES3_SA_INSERT_CTRL_MASK GENMASK(25, 23)
|
||||
#define TDES3_SA_INSERT_CTRL_SHIFT 23
|
||||
#define TDES3_CRC_PAD_CTRL_MASK GENMASK(27, 26)
|
||||
|
||||
/* TDES3 (write back format) */
|
||||
#define TDES3_IP_HDR_ERROR BIT(0)
|
||||
#define TDES3_DEFERRED BIT(1)
|
||||
#define TDES3_UNDERFLOW_ERROR BIT(2)
|
||||
#define TDES3_EXCESSIVE_DEFERRAL BIT(3)
|
||||
#define TDES3_COLLISION_COUNT_MASK GENMASK(7, 4)
|
||||
#define TDES3_COLLISION_COUNT_SHIFT 4
|
||||
#define TDES3_EXCESSIVE_COLLISION BIT(8)
|
||||
#define TDES3_LATE_COLLISION BIT(9)
|
||||
#define TDES3_NO_CARRIER BIT(10)
|
||||
#define TDES3_LOSS_CARRIER BIT(11)
|
||||
#define TDES3_PAYLOAD_ERROR BIT(12)
|
||||
#define TDES3_PACKET_FLUSHED BIT(13)
|
||||
#define TDES3_JABBER_TIMEOUT BIT(14)
|
||||
#define TDES3_ERROR_SUMMARY BIT(15)
|
||||
#define TDES3_TIMESTAMP_STATUS BIT(17)
|
||||
#define TDES3_TIMESTAMP_STATUS_SHIFT 17
|
||||
|
||||
/* TDES3 context */
|
||||
#define TDES3_CTXT_TCMSSV BIT(26)
|
||||
|
||||
/* TDES3 Common */
|
||||
#define TDES3_RS1V BIT(26)
|
||||
#define TDES3_RS1V_SHIFT 26
|
||||
#define TDES3_LAST_DESCRIPTOR BIT(28)
|
||||
#define TDES3_LAST_DESCRIPTOR_SHIFT 28
|
||||
#define TDES3_FIRST_DESCRIPTOR BIT(29)
|
||||
#define TDES3_CONTEXT_TYPE BIT(30)
|
||||
#define TDES3_CONTEXT_TYPE_SHIFT 30
|
||||
|
||||
/* TDES4 */
|
||||
#define TDES4_LTV BIT(31)
|
||||
#define TDES4_LT GENMASK(7, 0)
|
||||
|
||||
/* TDES5 */
|
||||
#define TDES5_LT GENMASK(31, 8)
|
||||
|
||||
/* TDS3 use for both format (read and write back) */
|
||||
#define TDES3_OWN BIT(31)
|
||||
#define TDES3_OWN_SHIFT 31
|
||||
|
||||
/* Normal receive descriptor defines (without split feature) */
|
||||
|
||||
/* RDES0 (write back format) */
|
||||
#define RDES0_VLAN_TAG_MASK GENMASK(15, 0)
|
||||
|
||||
/* RDES1 (write back format) */
|
||||
#define RDES1_IP_PAYLOAD_TYPE_MASK GENMASK(2, 0)
|
||||
#define RDES1_IP_HDR_ERROR BIT(3)
|
||||
#define RDES1_IPV4_HEADER BIT(4)
|
||||
#define RDES1_IPV6_HEADER BIT(5)
|
||||
#define RDES1_IP_CSUM_BYPASSED BIT(6)
|
||||
#define RDES1_IP_CSUM_ERROR BIT(7)
|
||||
#define RDES1_PTP_MSG_TYPE_MASK GENMASK(11, 8)
|
||||
#define RDES1_PTP_PACKET_TYPE BIT(12)
|
||||
#define RDES1_PTP_VER BIT(13)
|
||||
#define RDES1_TIMESTAMP_AVAILABLE BIT(14)
|
||||
#define RDES1_TIMESTAMP_AVAILABLE_SHIFT 14
|
||||
#define RDES1_TIMESTAMP_DROPPED BIT(15)
|
||||
#define RDES1_IP_TYPE1_CSUM_MASK GENMASK(31, 16)
|
||||
|
||||
/* RDES2 (write back format) */
|
||||
#define RDES2_L3_L4_HEADER_SIZE_MASK GENMASK(9, 0)
|
||||
#define RDES2_VLAN_FILTER_STATUS BIT(15)
|
||||
#define RDES2_SA_FILTER_FAIL BIT(16)
|
||||
#define RDES2_DA_FILTER_FAIL BIT(17)
|
||||
#define RDES2_HASH_FILTER_STATUS BIT(18)
|
||||
#define RDES2_MAC_ADDR_MATCH_MASK GENMASK(26, 19)
|
||||
#define RDES2_HASH_VALUE_MATCH_MASK GENMASK(26, 19)
|
||||
#define RDES2_L3_FILTER_MATCH BIT(27)
|
||||
#define RDES2_L4_FILTER_MATCH BIT(28)
|
||||
#define RDES2_L3_L4_FILT_NB_MATCH_MASK GENMASK(27, 26)
|
||||
#define RDES2_L3_L4_FILT_NB_MATCH_SHIFT 26
|
||||
#define RDES2_HL GENMASK(9, 0)
|
||||
|
||||
/* RDES3 (write back format) */
|
||||
#define RDES3_PACKET_SIZE_MASK GENMASK(14, 0)
|
||||
#define RDES3_ERROR_SUMMARY BIT(15)
|
||||
#define RDES3_PACKET_LEN_TYPE_MASK GENMASK(18, 16)
|
||||
#define RDES3_DRIBBLE_ERROR BIT(19)
|
||||
#define RDES3_RECEIVE_ERROR BIT(20)
|
||||
#define RDES3_OVERFLOW_ERROR BIT(21)
|
||||
#define RDES3_RECEIVE_WATCHDOG BIT(22)
|
||||
#define RDES3_GIANT_PACKET BIT(23)
|
||||
#define RDES3_CRC_ERROR BIT(24)
|
||||
#define RDES3_RDES0_VALID BIT(25)
|
||||
#define RDES3_RDES1_VALID BIT(26)
|
||||
#define RDES3_RDES2_VALID BIT(27)
|
||||
#define RDES3_LAST_DESCRIPTOR BIT(28)
|
||||
#define RDES3_FIRST_DESCRIPTOR BIT(29)
|
||||
#define RDES3_CONTEXT_DESCRIPTOR BIT(30)
|
||||
#define RDES3_CONTEXT_DESCRIPTOR_SHIFT 30
|
||||
|
||||
/* RDES3 (read format) */
|
||||
#define RDES3_BUFFER1_VALID_ADDR BIT(24)
|
||||
#define RDES3_BUFFER2_VALID_ADDR BIT(25)
|
||||
#define RDES3_INT_ON_COMPLETION_EN BIT(30)
|
||||
|
||||
/* TDS3 use for both format (read and write back) */
|
||||
#define RDES3_OWN BIT(31)
|
||||
|
||||
#endif /* __DWMAC4_DESCS_H__ */
|
||||
|
|
@ -0,0 +1,594 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* This contains the functions to handle the descriptors for DesignWare databook
|
||||
* 4.xx.
|
||||
*
|
||||
* Copyright (C) 2015 STMicroelectronics Ltd
|
||||
*
|
||||
* Author: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/stmmac.h>
|
||||
#include "common.h"
|
||||
#include "dwmac4.h"
|
||||
#include "dwmac4_descs.h"
|
||||
|
||||
static int dwmac4_wrback_get_tx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p,
|
||||
void __iomem *ioaddr)
|
||||
{
|
||||
unsigned int tdes3;
|
||||
int ret = tx_done;
|
||||
|
||||
tdes3 = le32_to_cpu(p->des3);
|
||||
|
||||
/* Get tx owner first */
|
||||
if (unlikely(tdes3 & TDES3_OWN))
|
||||
return tx_dma_own;
|
||||
|
||||
/* Verify tx error by looking at the last segment. */
|
||||
if (likely(!(tdes3 & TDES3_LAST_DESCRIPTOR)))
|
||||
return tx_not_ls;
|
||||
|
||||
if (unlikely(tdes3 & TDES3_ERROR_SUMMARY)) {
|
||||
ret = tx_err;
|
||||
|
||||
if (unlikely(tdes3 & TDES3_JABBER_TIMEOUT))
|
||||
x->tx_jabber++;
|
||||
if (unlikely(tdes3 & TDES3_PACKET_FLUSHED))
|
||||
x->tx_frame_flushed++;
|
||||
if (unlikely(tdes3 & TDES3_LOSS_CARRIER)) {
|
||||
x->tx_losscarrier++;
|
||||
}
|
||||
if (unlikely(tdes3 & TDES3_NO_CARRIER)) {
|
||||
x->tx_carrier++;
|
||||
}
|
||||
if (unlikely((tdes3 & TDES3_LATE_COLLISION) ||
|
||||
(tdes3 & TDES3_EXCESSIVE_COLLISION)))
|
||||
x->tx_collision +=
|
||||
(tdes3 & TDES3_COLLISION_COUNT_MASK)
|
||||
>> TDES3_COLLISION_COUNT_SHIFT;
|
||||
|
||||
if (unlikely(tdes3 & TDES3_EXCESSIVE_DEFERRAL))
|
||||
x->tx_deferred++;
|
||||
|
||||
if (unlikely(tdes3 & TDES3_UNDERFLOW_ERROR)) {
|
||||
x->tx_underflow++;
|
||||
ret |= tx_err_bump_tc;
|
||||
}
|
||||
|
||||
if (unlikely(tdes3 & TDES3_IP_HDR_ERROR))
|
||||
x->tx_ip_header_error++;
|
||||
|
||||
if (unlikely(tdes3 & TDES3_PAYLOAD_ERROR))
|
||||
x->tx_payload_error++;
|
||||
}
|
||||
|
||||
if (unlikely(tdes3 & TDES3_DEFERRED))
|
||||
x->tx_deferred++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwmac4_wrback_get_rx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p)
|
||||
{
|
||||
unsigned int rdes1 = le32_to_cpu(p->des1);
|
||||
unsigned int rdes2 = le32_to_cpu(p->des2);
|
||||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
int message_type;
|
||||
int ret = good_frame;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_OWN))
|
||||
return dma_own;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_CONTEXT_DESCRIPTOR))
|
||||
return discard_frame;
|
||||
if (likely(!(rdes3 & RDES3_LAST_DESCRIPTOR)))
|
||||
return rx_not_ls;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_ERROR_SUMMARY)) {
|
||||
if (unlikely(rdes3 & RDES3_GIANT_PACKET))
|
||||
x->rx_length++;
|
||||
if (unlikely(rdes3 & RDES3_OVERFLOW_ERROR))
|
||||
x->rx_gmac_overflow++;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_RECEIVE_WATCHDOG))
|
||||
x->rx_watchdog++;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_RECEIVE_ERROR))
|
||||
x->rx_mii++;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_CRC_ERROR))
|
||||
x->rx_crc_errors++;
|
||||
|
||||
if (unlikely(rdes3 & RDES3_DRIBBLE_ERROR))
|
||||
x->dribbling_bit++;
|
||||
|
||||
ret = discard_frame;
|
||||
}
|
||||
|
||||
message_type = (rdes1 & ERDES4_MSG_TYPE_MASK) >> 8;
|
||||
|
||||
if (rdes1 & RDES1_IP_HDR_ERROR)
|
||||
x->ip_hdr_err++;
|
||||
if (rdes1 & RDES1_IP_CSUM_BYPASSED)
|
||||
x->ip_csum_bypassed++;
|
||||
if (rdes1 & RDES1_IPV4_HEADER)
|
||||
x->ipv4_pkt_rcvd++;
|
||||
if (rdes1 & RDES1_IPV6_HEADER)
|
||||
x->ipv6_pkt_rcvd++;
|
||||
|
||||
if (message_type == RDES_EXT_NO_PTP)
|
||||
x->no_ptp_rx_msg_type_ext++;
|
||||
else if (message_type == RDES_EXT_SYNC)
|
||||
x->ptp_rx_msg_type_sync++;
|
||||
else if (message_type == RDES_EXT_FOLLOW_UP)
|
||||
x->ptp_rx_msg_type_follow_up++;
|
||||
else if (message_type == RDES_EXT_DELAY_REQ)
|
||||
x->ptp_rx_msg_type_delay_req++;
|
||||
else if (message_type == RDES_EXT_DELAY_RESP)
|
||||
x->ptp_rx_msg_type_delay_resp++;
|
||||
else if (message_type == RDES_EXT_PDELAY_REQ)
|
||||
x->ptp_rx_msg_type_pdelay_req++;
|
||||
else if (message_type == RDES_EXT_PDELAY_RESP)
|
||||
x->ptp_rx_msg_type_pdelay_resp++;
|
||||
else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP)
|
||||
x->ptp_rx_msg_type_pdelay_follow_up++;
|
||||
else if (message_type == RDES_PTP_ANNOUNCE)
|
||||
x->ptp_rx_msg_type_announce++;
|
||||
else if (message_type == RDES_PTP_MANAGEMENT)
|
||||
x->ptp_rx_msg_type_management++;
|
||||
else if (message_type == RDES_PTP_PKT_RESERVED_TYPE)
|
||||
x->ptp_rx_msg_pkt_reserved_type++;
|
||||
|
||||
if (rdes1 & RDES1_PTP_PACKET_TYPE)
|
||||
x->ptp_frame_type++;
|
||||
if (rdes1 & RDES1_PTP_VER)
|
||||
x->ptp_ver++;
|
||||
if (rdes1 & RDES1_TIMESTAMP_DROPPED)
|
||||
x->timestamp_dropped++;
|
||||
|
||||
if (unlikely(rdes2 & RDES2_SA_FILTER_FAIL)) {
|
||||
x->sa_rx_filter_fail++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(rdes2 & RDES2_DA_FILTER_FAIL)) {
|
||||
x->da_rx_filter_fail++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
|
||||
if (rdes2 & RDES2_L3_FILTER_MATCH)
|
||||
x->l3_filter_match++;
|
||||
if (rdes2 & RDES2_L4_FILTER_MATCH)
|
||||
x->l4_filter_match++;
|
||||
if ((rdes2 & RDES2_L3_L4_FILT_NB_MATCH_MASK)
|
||||
>> RDES2_L3_L4_FILT_NB_MATCH_SHIFT)
|
||||
x->l3_l4_filter_no_match++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwmac4_rd_get_tx_len(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des2) & TDES2_BUFFER1_SIZE_MASK);
|
||||
}
|
||||
|
||||
static int dwmac4_get_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des3) & TDES3_OWN) >> TDES3_OWN_SHIFT;
|
||||
}
|
||||
|
||||
static void dwmac4_set_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des3 |= cpu_to_le32(TDES3_OWN);
|
||||
}
|
||||
|
||||
static void dwmac4_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
|
||||
{
|
||||
u32 flags = (RDES3_OWN | RDES3_BUFFER1_VALID_ADDR);
|
||||
|
||||
if (!disable_rx_ic)
|
||||
flags |= RDES3_INT_ON_COMPLETION_EN;
|
||||
|
||||
p->des3 |= cpu_to_le32(flags);
|
||||
}
|
||||
|
||||
static int dwmac4_get_tx_ls(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des3) & TDES3_LAST_DESCRIPTOR)
|
||||
>> TDES3_LAST_DESCRIPTOR_SHIFT;
|
||||
}
|
||||
|
||||
static u16 dwmac4_wrback_get_rx_vlan_tci(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des0) & RDES0_VLAN_TAG_MASK);
|
||||
}
|
||||
|
||||
static bool dwmac4_wrback_get_rx_vlan_valid(struct dma_desc *p)
|
||||
{
|
||||
return ((le32_to_cpu(p->des3) & RDES3_LAST_DESCRIPTOR) &&
|
||||
(le32_to_cpu(p->des3) & RDES3_RDES0_VALID));
|
||||
}
|
||||
|
||||
static int dwmac4_wrback_get_rx_frame_len(struct dma_desc *p, int rx_coe)
|
||||
{
|
||||
return (le32_to_cpu(p->des3) & RDES3_PACKET_SIZE_MASK);
|
||||
}
|
||||
|
||||
static void dwmac4_rd_enable_tx_timestamp(struct dma_desc *p)
|
||||
{
|
||||
p->des2 |= cpu_to_le32(TDES2_TIMESTAMP_ENABLE);
|
||||
}
|
||||
|
||||
static int dwmac4_wrback_get_tx_timestamp_status(struct dma_desc *p)
|
||||
{
|
||||
/* Context type from W/B descriptor must be zero */
|
||||
if (le32_to_cpu(p->des3) & TDES3_CONTEXT_TYPE)
|
||||
return 0;
|
||||
|
||||
/* Tx Timestamp Status is 1 so des0 and des1'll have valid values */
|
||||
if (le32_to_cpu(p->des3) & TDES3_TIMESTAMP_STATUS)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dwmac4_get_timestamp(void *desc, u32 ats, u64 *ts)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
u64 ns;
|
||||
|
||||
ns = le32_to_cpu(p->des0);
|
||||
/* convert high/sec time stamp value to nanosecond */
|
||||
ns += le32_to_cpu(p->des1) * 1000000000ULL;
|
||||
|
||||
*ts = ns;
|
||||
}
|
||||
|
||||
static int dwmac4_rx_check_timestamp(void *desc)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
unsigned int rdes0 = le32_to_cpu(p->des0);
|
||||
unsigned int rdes1 = le32_to_cpu(p->des1);
|
||||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
u32 own, ctxt;
|
||||
int ret = 1;
|
||||
|
||||
own = rdes3 & RDES3_OWN;
|
||||
ctxt = ((rdes3 & RDES3_CONTEXT_DESCRIPTOR)
|
||||
>> RDES3_CONTEXT_DESCRIPTOR_SHIFT);
|
||||
|
||||
if (likely(!own && ctxt)) {
|
||||
if ((rdes0 == 0xffffffff) && (rdes1 == 0xffffffff))
|
||||
/* Corrupted value */
|
||||
ret = -EINVAL;
|
||||
else
|
||||
/* A valid Timestamp is ready to be read */
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Timestamp not ready */
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwmac4_wrback_get_rx_timestamp_status(void *desc, void *next_desc,
|
||||
u32 ats)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
int ret = -EINVAL;
|
||||
|
||||
/* Get the status from normal w/b descriptor */
|
||||
if (likely(le32_to_cpu(p->des3) & RDES3_RDES1_VALID)) {
|
||||
if (likely(le32_to_cpu(p->des1) & RDES1_TIMESTAMP_AVAILABLE)) {
|
||||
int i = 0;
|
||||
|
||||
/* Check if timestamp is OK from context descriptor */
|
||||
do {
|
||||
ret = dwmac4_rx_check_timestamp(next_desc);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
i++;
|
||||
|
||||
} while ((ret == 1) && (i < 10));
|
||||
|
||||
if (i == 10)
|
||||
ret = -EBUSY;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
if (likely(ret == 0))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwmac4_rd_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
|
||||
int mode, int end, int bfsize)
|
||||
{
|
||||
dwmac4_set_rx_owner(p, disable_rx_ic);
|
||||
}
|
||||
|
||||
static void dwmac4_rd_init_tx_desc(struct dma_desc *p, int mode, int end)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static void dwmac4_rd_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
bool csum_flag, int mode, bool tx_own,
|
||||
bool ls, unsigned int tot_pkt_len)
|
||||
{
|
||||
unsigned int tdes3 = le32_to_cpu(p->des3);
|
||||
|
||||
p->des2 |= cpu_to_le32(len & TDES2_BUFFER1_SIZE_MASK);
|
||||
|
||||
tdes3 |= tot_pkt_len & TDES3_PACKET_SIZE_MASK;
|
||||
if (is_fs)
|
||||
tdes3 |= TDES3_FIRST_DESCRIPTOR;
|
||||
else
|
||||
tdes3 &= ~TDES3_FIRST_DESCRIPTOR;
|
||||
|
||||
if (likely(csum_flag))
|
||||
tdes3 |= (TX_CIC_FULL << TDES3_CHECKSUM_INSERTION_SHIFT);
|
||||
else
|
||||
tdes3 &= ~(TX_CIC_FULL << TDES3_CHECKSUM_INSERTION_SHIFT);
|
||||
|
||||
if (ls)
|
||||
tdes3 |= TDES3_LAST_DESCRIPTOR;
|
||||
else
|
||||
tdes3 &= ~TDES3_LAST_DESCRIPTOR;
|
||||
|
||||
/* Finally set the OWN bit. Later the DMA will start! */
|
||||
if (tx_own)
|
||||
tdes3 |= TDES3_OWN;
|
||||
|
||||
if (is_fs && tx_own)
|
||||
/* When the own bit, for the first frame, has to be set, all
|
||||
* descriptors for the same frame has to be set before, to
|
||||
* avoid race condition.
|
||||
*/
|
||||
dma_wmb();
|
||||
|
||||
p->des3 = cpu_to_le32(tdes3);
|
||||
}
|
||||
|
||||
static void dwmac4_rd_prepare_tso_tx_desc(struct dma_desc *p, int is_fs,
|
||||
int len1, int len2, bool tx_own,
|
||||
bool ls, unsigned int tcphdrlen,
|
||||
unsigned int tcppayloadlen)
|
||||
{
|
||||
unsigned int tdes3 = le32_to_cpu(p->des3);
|
||||
|
||||
if (len1)
|
||||
p->des2 |= cpu_to_le32((len1 & TDES2_BUFFER1_SIZE_MASK));
|
||||
|
||||
if (len2)
|
||||
p->des2 |= cpu_to_le32((len2 << TDES2_BUFFER2_SIZE_MASK_SHIFT)
|
||||
& TDES2_BUFFER2_SIZE_MASK);
|
||||
|
||||
if (is_fs) {
|
||||
tdes3 |= TDES3_FIRST_DESCRIPTOR |
|
||||
TDES3_TCP_SEGMENTATION_ENABLE |
|
||||
((tcphdrlen << TDES3_HDR_LEN_SHIFT) &
|
||||
TDES3_SLOT_NUMBER_MASK) |
|
||||
((tcppayloadlen & TDES3_TCP_PKT_PAYLOAD_MASK));
|
||||
} else {
|
||||
tdes3 &= ~TDES3_FIRST_DESCRIPTOR;
|
||||
}
|
||||
|
||||
if (ls)
|
||||
tdes3 |= TDES3_LAST_DESCRIPTOR;
|
||||
else
|
||||
tdes3 &= ~TDES3_LAST_DESCRIPTOR;
|
||||
|
||||
/* Finally set the OWN bit. Later the DMA will start! */
|
||||
if (tx_own)
|
||||
tdes3 |= TDES3_OWN;
|
||||
|
||||
if (is_fs && tx_own)
|
||||
/* When the own bit, for the first frame, has to be set, all
|
||||
* descriptors for the same frame has to be set before, to
|
||||
* avoid race condition.
|
||||
*/
|
||||
dma_wmb();
|
||||
|
||||
p->des3 = cpu_to_le32(tdes3);
|
||||
}
|
||||
|
||||
static void dwmac4_release_tx_desc(struct dma_desc *p, int mode)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static void dwmac4_rd_set_tx_ic(struct dma_desc *p)
|
||||
{
|
||||
p->des2 |= cpu_to_le32(TDES2_INTERRUPT_ON_COMPLETION);
|
||||
}
|
||||
|
||||
static void dwmac4_display_ring(void *head, unsigned int size, bool rx,
|
||||
dma_addr_t dma_rx_phy, unsigned int desc_size)
|
||||
{
|
||||
dma_addr_t dma_addr;
|
||||
int i;
|
||||
|
||||
pr_info("%s descriptor ring:\n", rx ? "RX" : "TX");
|
||||
|
||||
if (desc_size == sizeof(struct dma_desc)) {
|
||||
struct dma_desc *p = (struct dma_desc *)head;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
dma_addr = dma_rx_phy + i * sizeof(*p);
|
||||
pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x\n",
|
||||
i, &dma_addr,
|
||||
le32_to_cpu(p->des0), le32_to_cpu(p->des1),
|
||||
le32_to_cpu(p->des2), le32_to_cpu(p->des3));
|
||||
p++;
|
||||
}
|
||||
} else if (desc_size == sizeof(struct dma_extended_desc)) {
|
||||
struct dma_extended_desc *extp = (struct dma_extended_desc *)head;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
dma_addr = dma_rx_phy + i * sizeof(*extp);
|
||||
pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
|
||||
i, &dma_addr,
|
||||
le32_to_cpu(extp->basic.des0), le32_to_cpu(extp->basic.des1),
|
||||
le32_to_cpu(extp->basic.des2), le32_to_cpu(extp->basic.des3),
|
||||
le32_to_cpu(extp->des4), le32_to_cpu(extp->des5),
|
||||
le32_to_cpu(extp->des6), le32_to_cpu(extp->des7));
|
||||
extp++;
|
||||
}
|
||||
} else if (desc_size == sizeof(struct dma_edesc)) {
|
||||
struct dma_edesc *ep = (struct dma_edesc *)head;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
dma_addr = dma_rx_phy + i * sizeof(*ep);
|
||||
pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
|
||||
i, &dma_addr,
|
||||
le32_to_cpu(ep->des4), le32_to_cpu(ep->des5),
|
||||
le32_to_cpu(ep->des6), le32_to_cpu(ep->des7),
|
||||
le32_to_cpu(ep->basic.des0), le32_to_cpu(ep->basic.des1),
|
||||
le32_to_cpu(ep->basic.des2), le32_to_cpu(ep->basic.des3));
|
||||
ep++;
|
||||
}
|
||||
} else {
|
||||
pr_err("unsupported descriptor!");
|
||||
}
|
||||
}
|
||||
|
||||
static void dwmac4_set_mss_ctxt(struct dma_desc *p, unsigned int mss)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = cpu_to_le32(mss);
|
||||
p->des3 = cpu_to_le32(TDES3_CONTEXT_TYPE | TDES3_CTXT_TCMSSV);
|
||||
}
|
||||
|
||||
static void dwmac4_set_addr(struct dma_desc *p, dma_addr_t addr)
|
||||
{
|
||||
p->des0 = cpu_to_le32(lower_32_bits(addr));
|
||||
p->des1 = cpu_to_le32(upper_32_bits(addr));
|
||||
}
|
||||
|
||||
static void dwmac4_clear(struct dma_desc *p)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static void dwmac4_set_sarc(struct dma_desc *p, u32 sarc_type)
|
||||
{
|
||||
sarc_type <<= TDES3_SA_INSERT_CTRL_SHIFT;
|
||||
|
||||
p->des3 |= cpu_to_le32(sarc_type & TDES3_SA_INSERT_CTRL_MASK);
|
||||
}
|
||||
|
||||
static int set_16kib_bfsize(int mtu)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(mtu >= BUF_SIZE_8KiB))
|
||||
ret = BUF_SIZE_16KiB;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwmac4_set_vlan_tag(struct dma_desc *p, u16 tag, u16 inner_tag,
|
||||
u32 inner_type)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
|
||||
/* Inner VLAN */
|
||||
if (inner_type) {
|
||||
u32 des = inner_tag << TDES2_IVT_SHIFT;
|
||||
|
||||
des &= TDES2_IVT_MASK;
|
||||
p->des2 = cpu_to_le32(des);
|
||||
|
||||
des = inner_type << TDES3_IVTIR_SHIFT;
|
||||
des &= TDES3_IVTIR_MASK;
|
||||
p->des3 = cpu_to_le32(des | TDES3_IVLTV);
|
||||
}
|
||||
|
||||
/* Outer VLAN */
|
||||
p->des3 |= cpu_to_le32(tag & TDES3_VLAN_TAG);
|
||||
p->des3 |= cpu_to_le32(TDES3_VLTV);
|
||||
|
||||
p->des3 |= cpu_to_le32(TDES3_CONTEXT_TYPE);
|
||||
}
|
||||
|
||||
static void dwmac4_set_vlan(struct dma_desc *p, u32 type)
|
||||
{
|
||||
type <<= TDES2_VLAN_TAG_SHIFT;
|
||||
p->des2 |= cpu_to_le32(type & TDES2_VLAN_TAG_MASK);
|
||||
}
|
||||
|
||||
static void dwmac4_get_rx_header_len(struct dma_desc *p, unsigned int *len)
|
||||
{
|
||||
*len = le32_to_cpu(p->des2) & RDES2_HL;
|
||||
}
|
||||
|
||||
static void dwmac4_set_sec_addr(struct dma_desc *p, dma_addr_t addr, bool buf2_valid)
|
||||
{
|
||||
p->des2 = cpu_to_le32(lower_32_bits(addr));
|
||||
p->des3 = cpu_to_le32(upper_32_bits(addr));
|
||||
|
||||
if (buf2_valid)
|
||||
p->des3 |= cpu_to_le32(RDES3_BUFFER2_VALID_ADDR);
|
||||
else
|
||||
p->des3 &= cpu_to_le32(~RDES3_BUFFER2_VALID_ADDR);
|
||||
}
|
||||
|
||||
static void dwmac4_set_tbs(struct dma_edesc *p, u32 sec, u32 nsec)
|
||||
{
|
||||
p->des4 = cpu_to_le32((sec & TDES4_LT) | TDES4_LTV);
|
||||
p->des5 = cpu_to_le32(nsec & TDES5_LT);
|
||||
p->des6 = 0;
|
||||
p->des7 = 0;
|
||||
}
|
||||
|
||||
const struct stmmac_desc_ops dwmac4_desc_ops = {
|
||||
.tx_status = dwmac4_wrback_get_tx_status,
|
||||
.rx_status = dwmac4_wrback_get_rx_status,
|
||||
.get_tx_len = dwmac4_rd_get_tx_len,
|
||||
.get_tx_owner = dwmac4_get_tx_owner,
|
||||
.set_tx_owner = dwmac4_set_tx_owner,
|
||||
.set_rx_owner = dwmac4_set_rx_owner,
|
||||
.get_tx_ls = dwmac4_get_tx_ls,
|
||||
.get_rx_vlan_tci = dwmac4_wrback_get_rx_vlan_tci,
|
||||
.get_rx_vlan_valid = dwmac4_wrback_get_rx_vlan_valid,
|
||||
.get_rx_frame_len = dwmac4_wrback_get_rx_frame_len,
|
||||
.enable_tx_timestamp = dwmac4_rd_enable_tx_timestamp,
|
||||
.get_tx_timestamp_status = dwmac4_wrback_get_tx_timestamp_status,
|
||||
.get_rx_timestamp_status = dwmac4_wrback_get_rx_timestamp_status,
|
||||
.get_timestamp = dwmac4_get_timestamp,
|
||||
.set_tx_ic = dwmac4_rd_set_tx_ic,
|
||||
.prepare_tx_desc = dwmac4_rd_prepare_tx_desc,
|
||||
.prepare_tso_tx_desc = dwmac4_rd_prepare_tso_tx_desc,
|
||||
.release_tx_desc = dwmac4_release_tx_desc,
|
||||
.init_rx_desc = dwmac4_rd_init_rx_desc,
|
||||
.init_tx_desc = dwmac4_rd_init_tx_desc,
|
||||
.display_ring = dwmac4_display_ring,
|
||||
.set_mss = dwmac4_set_mss_ctxt,
|
||||
.set_addr = dwmac4_set_addr,
|
||||
.clear = dwmac4_clear,
|
||||
.set_sarc = dwmac4_set_sarc,
|
||||
.set_vlan_tag = dwmac4_set_vlan_tag,
|
||||
.set_vlan = dwmac4_set_vlan,
|
||||
.get_rx_header_len = dwmac4_get_rx_header_len,
|
||||
.set_sec_addr = dwmac4_set_sec_addr,
|
||||
.set_tbs = dwmac4_set_tbs,
|
||||
};
|
||||
|
||||
const struct stmmac_mode_ops dwmac4_ring_mode_ops = {
|
||||
.set_16kib_bfsize = set_16kib_bfsize,
|
||||
};
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Header File to describe the DMA descriptors and related definitions specific
|
||||
* for DesignWare databook 4.xx.
|
||||
*
|
||||
* Copyright (C) 2015 STMicroelectronics Ltd
|
||||
*
|
||||
* Author: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
*/
|
||||
|
||||
#ifndef __DWMAC4_DESCS_H__
|
||||
#define __DWMAC4_DESCS_H__
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/* Normal transmit descriptor defines (without split feature) */
|
||||
|
||||
/* TDES2 (read format) */
|
||||
#define TDES2_BUFFER1_SIZE_MASK GENMASK(13, 0)
|
||||
#define TDES2_VLAN_TAG_MASK GENMASK(15, 14)
|
||||
#define TDES2_VLAN_TAG_SHIFT 14
|
||||
#define TDES2_BUFFER2_SIZE_MASK GENMASK(29, 16)
|
||||
#define TDES2_BUFFER2_SIZE_MASK_SHIFT 16
|
||||
#define TDES3_IVTIR_MASK GENMASK(19, 18)
|
||||
#define TDES3_IVTIR_SHIFT 18
|
||||
#define TDES3_IVLTV BIT(17)
|
||||
#define TDES2_TIMESTAMP_ENABLE BIT(30)
|
||||
#define TDES2_IVT_MASK GENMASK(31, 16)
|
||||
#define TDES2_IVT_SHIFT 16
|
||||
#define TDES2_INTERRUPT_ON_COMPLETION BIT(31)
|
||||
|
||||
/* TDES3 (read format) */
|
||||
#define TDES3_PACKET_SIZE_MASK GENMASK(14, 0)
|
||||
#define TDES3_VLAN_TAG GENMASK(15, 0)
|
||||
#define TDES3_VLTV BIT(16)
|
||||
#define TDES3_CHECKSUM_INSERTION_MASK GENMASK(17, 16)
|
||||
#define TDES3_CHECKSUM_INSERTION_SHIFT 16
|
||||
#define TDES3_TCP_PKT_PAYLOAD_MASK GENMASK(17, 0)
|
||||
#define TDES3_TCP_SEGMENTATION_ENABLE BIT(18)
|
||||
#define TDES3_HDR_LEN_SHIFT 19
|
||||
#define TDES3_SLOT_NUMBER_MASK GENMASK(22, 19)
|
||||
#define TDES3_SA_INSERT_CTRL_MASK GENMASK(25, 23)
|
||||
#define TDES3_SA_INSERT_CTRL_SHIFT 23
|
||||
#define TDES3_CRC_PAD_CTRL_MASK GENMASK(27, 26)
|
||||
|
||||
/* TDES3 (write back format) */
|
||||
#define TDES3_IP_HDR_ERROR BIT(0)
|
||||
#define TDES3_DEFERRED BIT(1)
|
||||
#define TDES3_UNDERFLOW_ERROR BIT(2)
|
||||
#define TDES3_EXCESSIVE_DEFERRAL BIT(3)
|
||||
#define TDES3_COLLISION_COUNT_MASK GENMASK(7, 4)
|
||||
#define TDES3_COLLISION_COUNT_SHIFT 4
|
||||
#define TDES3_EXCESSIVE_COLLISION BIT(8)
|
||||
#define TDES3_LATE_COLLISION BIT(9)
|
||||
#define TDES3_NO_CARRIER BIT(10)
|
||||
#define TDES3_LOSS_CARRIER BIT(11)
|
||||
#define TDES3_PAYLOAD_ERROR BIT(12)
|
||||
#define TDES3_PACKET_FLUSHED BIT(13)
|
||||
#define TDES3_JABBER_TIMEOUT BIT(14)
|
||||
#define TDES3_ERROR_SUMMARY BIT(15)
|
||||
#define TDES3_TIMESTAMP_STATUS BIT(17)
|
||||
#define TDES3_TIMESTAMP_STATUS_SHIFT 17
|
||||
|
||||
/* TDES3 context */
|
||||
#define TDES3_CTXT_TCMSSV BIT(26)
|
||||
|
||||
/* TDES3 Common */
|
||||
#define TDES3_RS1V BIT(26)
|
||||
#define TDES3_RS1V_SHIFT 26
|
||||
#define TDES3_LAST_DESCRIPTOR BIT(28)
|
||||
#define TDES3_LAST_DESCRIPTOR_SHIFT 28
|
||||
#define TDES3_FIRST_DESCRIPTOR BIT(29)
|
||||
#define TDES3_CONTEXT_TYPE BIT(30)
|
||||
#define TDES3_CONTEXT_TYPE_SHIFT 30
|
||||
|
||||
/* TDES4 */
|
||||
#define TDES4_LTV BIT(31)
|
||||
#define TDES4_LT GENMASK(7, 0)
|
||||
|
||||
/* TDES5 */
|
||||
#define TDES5_LT GENMASK(31, 8)
|
||||
|
||||
/* TDS3 use for both format (read and write back) */
|
||||
#define TDES3_OWN BIT(31)
|
||||
#define TDES3_OWN_SHIFT 31
|
||||
|
||||
/* Normal receive descriptor defines (without split feature) */
|
||||
|
||||
/* RDES0 (write back format) */
|
||||
#define RDES0_VLAN_TAG_MASK GENMASK(15, 0)
|
||||
|
||||
/* RDES1 (write back format) */
|
||||
#define RDES1_IP_PAYLOAD_TYPE_MASK GENMASK(2, 0)
|
||||
#define RDES1_IP_HDR_ERROR BIT(3)
|
||||
#define RDES1_IPV4_HEADER BIT(4)
|
||||
#define RDES1_IPV6_HEADER BIT(5)
|
||||
#define RDES1_IP_CSUM_BYPASSED BIT(6)
|
||||
#define RDES1_IP_CSUM_ERROR BIT(7)
|
||||
#define RDES1_PTP_MSG_TYPE_MASK GENMASK(11, 8)
|
||||
#define RDES1_PTP_PACKET_TYPE BIT(12)
|
||||
#define RDES1_PTP_VER BIT(13)
|
||||
#define RDES1_TIMESTAMP_AVAILABLE BIT(14)
|
||||
#define RDES1_TIMESTAMP_AVAILABLE_SHIFT 14
|
||||
#define RDES1_TIMESTAMP_DROPPED BIT(15)
|
||||
#define RDES1_IP_TYPE1_CSUM_MASK GENMASK(31, 16)
|
||||
|
||||
/* RDES2 (write back format) */
|
||||
#define RDES2_L3_L4_HEADER_SIZE_MASK GENMASK(9, 0)
|
||||
#define RDES2_VLAN_FILTER_STATUS BIT(15)
|
||||
#define RDES2_SA_FILTER_FAIL BIT(16)
|
||||
#define RDES2_DA_FILTER_FAIL BIT(17)
|
||||
#define RDES2_HASH_FILTER_STATUS BIT(18)
|
||||
#define RDES2_MAC_ADDR_MATCH_MASK GENMASK(26, 19)
|
||||
#define RDES2_HASH_VALUE_MATCH_MASK GENMASK(26, 19)
|
||||
#define RDES2_L3_FILTER_MATCH BIT(27)
|
||||
#define RDES2_L4_FILTER_MATCH BIT(28)
|
||||
#define RDES2_L3_L4_FILT_NB_MATCH_MASK GENMASK(27, 26)
|
||||
#define RDES2_L3_L4_FILT_NB_MATCH_SHIFT 26
|
||||
#define RDES2_HL GENMASK(9, 0)
|
||||
|
||||
/* RDES3 (write back format) */
|
||||
#define RDES3_PACKET_SIZE_MASK GENMASK(14, 0)
|
||||
#define RDES3_ERROR_SUMMARY BIT(15)
|
||||
#define RDES3_PACKET_LEN_TYPE_MASK GENMASK(18, 16)
|
||||
#define RDES3_DRIBBLE_ERROR BIT(19)
|
||||
#define RDES3_RECEIVE_ERROR BIT(20)
|
||||
#define RDES3_OVERFLOW_ERROR BIT(21)
|
||||
#define RDES3_RECEIVE_WATCHDOG BIT(22)
|
||||
#define RDES3_GIANT_PACKET BIT(23)
|
||||
#define RDES3_CRC_ERROR BIT(24)
|
||||
#define RDES3_RDES0_VALID BIT(25)
|
||||
#define RDES3_RDES1_VALID BIT(26)
|
||||
#define RDES3_RDES2_VALID BIT(27)
|
||||
#define RDES3_LAST_DESCRIPTOR BIT(28)
|
||||
#define RDES3_FIRST_DESCRIPTOR BIT(29)
|
||||
#define RDES3_CONTEXT_DESCRIPTOR BIT(30)
|
||||
#define RDES3_CONTEXT_DESCRIPTOR_SHIFT 30
|
||||
|
||||
/* RDES3 (read format) */
|
||||
#define RDES3_BUFFER1_VALID_ADDR BIT(24)
|
||||
#define RDES3_BUFFER2_VALID_ADDR BIT(25)
|
||||
#define RDES3_INT_ON_COMPLETION_EN BIT(30)
|
||||
|
||||
/* TDS3 use for both format (read and write back) */
|
||||
#define RDES3_OWN BIT(31)
|
||||
|
||||
#endif /* __DWMAC4_DESCS_H__ */
|
||||
|
|
@ -0,0 +1,629 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
|
||||
* DWC Ether MAC version 4.xx has been used for developing this code.
|
||||
*
|
||||
* This contains the functions to handle the dma.
|
||||
*
|
||||
* Copyright (C) 2015 STMicroelectronics Ltd
|
||||
*
|
||||
* Author: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include "dwmac4-6.12-ethercat.h"
|
||||
#include "dwmac4_dma-6.12-ethercat.h"
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
|
||||
static void dwmac4_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_SYS_BUS_MODE);
|
||||
int i;
|
||||
|
||||
pr_info("dwmac4: Master AXI performs %s burst length\n",
|
||||
(value & DMA_SYS_BUS_FB) ? "fixed" : "any");
|
||||
|
||||
if (axi->axi_lpi_en)
|
||||
value |= DMA_AXI_EN_LPI;
|
||||
if (axi->axi_xit_frm)
|
||||
value |= DMA_AXI_LPI_XIT_FRM;
|
||||
|
||||
value &= ~DMA_AXI_WR_OSR_LMT;
|
||||
value |= (axi->axi_wr_osr_lmt & DMA_AXI_OSR_MAX) <<
|
||||
DMA_AXI_WR_OSR_LMT_SHIFT;
|
||||
|
||||
value &= ~DMA_AXI_RD_OSR_LMT;
|
||||
value |= (axi->axi_rd_osr_lmt & DMA_AXI_OSR_MAX) <<
|
||||
DMA_AXI_RD_OSR_LMT_SHIFT;
|
||||
|
||||
/* Depending on the UNDEF bit the Master AXI will perform any burst
|
||||
* length according to the BLEN programmed (by default all BLEN are
|
||||
* set).
|
||||
*/
|
||||
for (i = 0; i < AXI_BLEN; i++) {
|
||||
switch (axi->axi_blen[i]) {
|
||||
case 256:
|
||||
value |= DMA_AXI_BLEN256;
|
||||
break;
|
||||
case 128:
|
||||
value |= DMA_AXI_BLEN128;
|
||||
break;
|
||||
case 64:
|
||||
value |= DMA_AXI_BLEN64;
|
||||
break;
|
||||
case 32:
|
||||
value |= DMA_AXI_BLEN32;
|
||||
break;
|
||||
case 16:
|
||||
value |= DMA_AXI_BLEN16;
|
||||
break;
|
||||
case 8:
|
||||
value |= DMA_AXI_BLEN8;
|
||||
break;
|
||||
case 4:
|
||||
value |= DMA_AXI_BLEN4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writel(value, ioaddr + DMA_SYS_BUS_MODE);
|
||||
}
|
||||
|
||||
static void dwmac4_dma_init_rx_chan(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t dma_rx_phy, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value;
|
||||
u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
|
||||
|
||||
value = readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
value = value | (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
|
||||
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && likely(dma_cfg->eame))
|
||||
writel(upper_32_bits(dma_rx_phy),
|
||||
ioaddr + DMA_CHAN_RX_BASE_ADDR_HI(dwmac4_addrs, chan));
|
||||
|
||||
writel(lower_32_bits(dma_rx_phy),
|
||||
ioaddr + DMA_CHAN_RX_BASE_ADDR(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
static void dwmac4_dma_init_tx_chan(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t dma_tx_phy, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value;
|
||||
u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
|
||||
|
||||
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
value = value | (txpbl << DMA_BUS_MODE_PBL_SHIFT);
|
||||
|
||||
/* Enable OSP to get best performance */
|
||||
value |= DMA_CONTROL_OSP;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && likely(dma_cfg->eame))
|
||||
writel(upper_32_bits(dma_tx_phy),
|
||||
ioaddr + DMA_CHAN_TX_BASE_ADDR_HI(dwmac4_addrs, chan));
|
||||
|
||||
writel(lower_32_bits(dma_tx_phy),
|
||||
ioaddr + DMA_CHAN_TX_BASE_ADDR(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
static void dwmac4_dma_init_channel(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value;
|
||||
|
||||
/* common channel control register config */
|
||||
value = readl(ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan));
|
||||
if (dma_cfg->pblx8)
|
||||
value = value | DMA_BUS_MODE_PBL;
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
/* Mask interrupts by writing to CSR7 */
|
||||
writel(DMA_CHAN_INTR_DEFAULT_MASK,
|
||||
ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
static void dwmac410_dma_init_channel(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value;
|
||||
|
||||
/* common channel control register config */
|
||||
value = readl(ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan));
|
||||
if (dma_cfg->pblx8)
|
||||
value = value | DMA_BUS_MODE_PBL;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
/* Mask interrupts by writing to CSR7 */
|
||||
writel(DMA_CHAN_INTR_DEFAULT_MASK_4_10,
|
||||
ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
static void dwmac4_dma_init(void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_SYS_BUS_MODE);
|
||||
|
||||
/* Set the Fixed burst mode */
|
||||
if (dma_cfg->fixed_burst)
|
||||
value |= DMA_SYS_BUS_FB;
|
||||
|
||||
/* Mixed Burst has no effect when fb is set */
|
||||
if (dma_cfg->mixed_burst)
|
||||
value |= DMA_SYS_BUS_MB;
|
||||
|
||||
if (dma_cfg->aal)
|
||||
value |= DMA_SYS_BUS_AAL;
|
||||
|
||||
if (dma_cfg->eame)
|
||||
value |= DMA_SYS_BUS_EAME;
|
||||
|
||||
writel(value, ioaddr + DMA_SYS_BUS_MODE);
|
||||
|
||||
value = readl(ioaddr + DMA_BUS_MODE);
|
||||
|
||||
if (dma_cfg->multi_msi_en) {
|
||||
value &= ~DMA_BUS_MODE_INTM_MASK;
|
||||
value |= (DMA_BUS_MODE_INTM_MODE1 << DMA_BUS_MODE_INTM_SHIFT);
|
||||
}
|
||||
|
||||
if (dma_cfg->dche)
|
||||
value |= DMA_BUS_MODE_DCHE;
|
||||
|
||||
writel(value, ioaddr + DMA_BUS_MODE);
|
||||
|
||||
}
|
||||
|
||||
static void _dwmac4_dump_dma_regs(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 channel,
|
||||
u32 *reg_space)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
const struct dwmac4_addrs *default_addrs = NULL;
|
||||
|
||||
/* Purposely save the registers in the "normal" layout, regardless of
|
||||
* platform modifications, to keep reg_space size constant
|
||||
*/
|
||||
reg_space[DMA_CHAN_CONTROL(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_TX_CONTROL(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_RX_CONTROL(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_TX_BASE_ADDR_HI(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_TX_BASE_ADDR_HI(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_TX_BASE_ADDR(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_TX_BASE_ADDR(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_RX_BASE_ADDR_HI(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_RX_BASE_ADDR_HI(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_RX_BASE_ADDR(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_RX_BASE_ADDR(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_TX_END_ADDR(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_TX_END_ADDR(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_RX_END_ADDR(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_RX_END_ADDR(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_TX_RING_LEN(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_TX_RING_LEN(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_RX_RING_LEN(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_RX_RING_LEN(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_INTR_ENA(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_RX_WATCHDOG(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_RX_WATCHDOG(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_SLOT_CTRL_STATUS(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_SLOT_CTRL_STATUS(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_CUR_TX_DESC(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CUR_TX_DESC(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_CUR_RX_DESC(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CUR_RX_DESC(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_CUR_TX_BUF_ADDR_HI(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CUR_TX_BUF_ADDR_HI(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_CUR_TX_BUF_ADDR(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CUR_TX_BUF_ADDR(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_CUR_RX_BUF_ADDR_HI(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CUR_RX_BUF_ADDR_HI(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_CUR_RX_BUF_ADDR(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CUR_RX_BUF_ADDR(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_STATUS(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, channel));
|
||||
}
|
||||
|
||||
static void dwmac4_dump_dma_regs(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 *reg_space)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DMA_CHANNEL_NB_MAX; i++)
|
||||
_dwmac4_dump_dma_regs(priv, ioaddr, i, reg_space);
|
||||
}
|
||||
|
||||
static void dwmac4_rx_watchdog(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 riwt, u32 queue)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(dwmac4_addrs, queue));
|
||||
}
|
||||
|
||||
static void dwmac4_dma_rx_chan_op_mode(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, int mode,
|
||||
u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
unsigned int rqs = fifosz / 256 - 1;
|
||||
u32 mtl_rx_op;
|
||||
|
||||
mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(dwmac4_addrs, channel));
|
||||
|
||||
if (mode == SF_DMA_MODE) {
|
||||
pr_debug("GMAC: enable RX store and forward mode\n");
|
||||
mtl_rx_op |= MTL_OP_MODE_RSF;
|
||||
} else {
|
||||
pr_debug("GMAC: disable RX SF mode (threshold %d)\n", mode);
|
||||
mtl_rx_op &= ~MTL_OP_MODE_RSF;
|
||||
mtl_rx_op &= MTL_OP_MODE_RTC_MASK;
|
||||
if (mode <= 32)
|
||||
mtl_rx_op |= MTL_OP_MODE_RTC_32;
|
||||
else if (mode <= 64)
|
||||
mtl_rx_op |= MTL_OP_MODE_RTC_64;
|
||||
else if (mode <= 96)
|
||||
mtl_rx_op |= MTL_OP_MODE_RTC_96;
|
||||
else
|
||||
mtl_rx_op |= MTL_OP_MODE_RTC_128;
|
||||
}
|
||||
|
||||
mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
|
||||
mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
|
||||
|
||||
/* Enable flow control only if each channel gets 4 KiB or more FIFO and
|
||||
* only if channel is not an AVB channel.
|
||||
*/
|
||||
if ((fifosz >= 4096) && (qmode != MTL_QUEUE_AVB)) {
|
||||
unsigned int rfd, rfa;
|
||||
|
||||
mtl_rx_op |= MTL_OP_MODE_EHFC;
|
||||
|
||||
/* Set Threshold for Activating Flow Control to min 2 frames,
|
||||
* i.e. 1500 * 2 = 3000 bytes.
|
||||
*
|
||||
* Set Threshold for Deactivating Flow Control to min 1 frame,
|
||||
* i.e. 1500 bytes.
|
||||
*/
|
||||
switch (fifosz) {
|
||||
case 4096:
|
||||
/* This violates the above formula because of FIFO size
|
||||
* limit therefore overflow may occur in spite of this.
|
||||
*/
|
||||
rfd = 0x03; /* Full-2.5K */
|
||||
rfa = 0x01; /* Full-1.5K */
|
||||
break;
|
||||
|
||||
default:
|
||||
rfd = 0x07; /* Full-4.5K */
|
||||
rfa = 0x04; /* Full-3K */
|
||||
break;
|
||||
}
|
||||
|
||||
mtl_rx_op &= ~MTL_OP_MODE_RFD_MASK;
|
||||
mtl_rx_op |= rfd << MTL_OP_MODE_RFD_SHIFT;
|
||||
|
||||
mtl_rx_op &= ~MTL_OP_MODE_RFA_MASK;
|
||||
mtl_rx_op |= rfa << MTL_OP_MODE_RFA_SHIFT;
|
||||
}
|
||||
|
||||
writel(mtl_rx_op, ioaddr + MTL_CHAN_RX_OP_MODE(dwmac4_addrs, channel));
|
||||
}
|
||||
|
||||
static void dwmac4_dma_tx_chan_op_mode(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, int mode,
|
||||
u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(dwmac4_addrs,
|
||||
channel));
|
||||
unsigned int tqs = fifosz / 256 - 1;
|
||||
|
||||
if (mode == SF_DMA_MODE) {
|
||||
pr_debug("GMAC: enable TX store and forward mode\n");
|
||||
/* Transmit COE type 2 cannot be done in cut-through mode. */
|
||||
mtl_tx_op |= MTL_OP_MODE_TSF;
|
||||
} else {
|
||||
pr_debug("GMAC: disabling TX SF (threshold %d)\n", mode);
|
||||
mtl_tx_op &= ~MTL_OP_MODE_TSF;
|
||||
mtl_tx_op &= MTL_OP_MODE_TTC_MASK;
|
||||
/* Set the transmit threshold */
|
||||
if (mode <= 32)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_32;
|
||||
else if (mode <= 64)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_64;
|
||||
else if (mode <= 96)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_96;
|
||||
else if (mode <= 128)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_128;
|
||||
else if (mode <= 192)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_192;
|
||||
else if (mode <= 256)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_256;
|
||||
else if (mode <= 384)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_384;
|
||||
else
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_512;
|
||||
}
|
||||
/* For an IP with DWC_EQOS_NUM_TXQ == 1, the fields TXQEN and TQS are RO
|
||||
* with reset values: TXQEN on, TQS == DWC_EQOS_TXFIFO_SIZE.
|
||||
* For an IP with DWC_EQOS_NUM_TXQ > 1, the fields TXQEN and TQS are R/W
|
||||
* with reset values: TXQEN off, TQS 256 bytes.
|
||||
*
|
||||
* TXQEN must be written for multi-channel operation and TQS must
|
||||
* reflect the available fifo size per queue (total fifo size / number
|
||||
* of enabled queues).
|
||||
*/
|
||||
mtl_tx_op &= ~MTL_OP_MODE_TXQEN_MASK;
|
||||
if (qmode != MTL_QUEUE_AVB)
|
||||
mtl_tx_op |= MTL_OP_MODE_TXQEN;
|
||||
else
|
||||
mtl_tx_op |= MTL_OP_MODE_TXQEN_AV;
|
||||
mtl_tx_op &= ~MTL_OP_MODE_TQS_MASK;
|
||||
mtl_tx_op |= tqs << MTL_OP_MODE_TQS_SHIFT;
|
||||
|
||||
writel(mtl_tx_op, ioaddr + MTL_CHAN_TX_OP_MODE(dwmac4_addrs, channel));
|
||||
}
|
||||
|
||||
static int dwmac4_get_hw_feature(void __iomem *ioaddr,
|
||||
struct dma_features *dma_cap)
|
||||
{
|
||||
u32 hw_cap = readl(ioaddr + GMAC_HW_FEATURE0);
|
||||
|
||||
/* MAC HW feature0 */
|
||||
dma_cap->mbps_10_100 = (hw_cap & GMAC_HW_FEAT_MIISEL);
|
||||
dma_cap->mbps_1000 = (hw_cap & GMAC_HW_FEAT_GMIISEL) >> 1;
|
||||
dma_cap->half_duplex = (hw_cap & GMAC_HW_FEAT_HDSEL) >> 2;
|
||||
dma_cap->vlhash = (hw_cap & GMAC_HW_FEAT_VLHASH) >> 4;
|
||||
dma_cap->multi_addr = (hw_cap & GMAC_HW_FEAT_ADDMAC) >> 18;
|
||||
dma_cap->pcs = (hw_cap & GMAC_HW_FEAT_PCSSEL) >> 3;
|
||||
dma_cap->sma_mdio = (hw_cap & GMAC_HW_FEAT_SMASEL) >> 5;
|
||||
dma_cap->pmt_remote_wake_up = (hw_cap & GMAC_HW_FEAT_RWKSEL) >> 6;
|
||||
dma_cap->pmt_magic_frame = (hw_cap & GMAC_HW_FEAT_MGKSEL) >> 7;
|
||||
/* MMC */
|
||||
dma_cap->rmon = (hw_cap & GMAC_HW_FEAT_MMCSEL) >> 8;
|
||||
/* IEEE 1588-2008 */
|
||||
dma_cap->atime_stamp = (hw_cap & GMAC_HW_FEAT_TSSEL) >> 12;
|
||||
/* 802.3az - Energy-Efficient Ethernet (EEE) */
|
||||
dma_cap->eee = (hw_cap & GMAC_HW_FEAT_EEESEL) >> 13;
|
||||
/* TX and RX csum */
|
||||
dma_cap->tx_coe = (hw_cap & GMAC_HW_FEAT_TXCOSEL) >> 14;
|
||||
dma_cap->rx_coe = (hw_cap & GMAC_HW_FEAT_RXCOESEL) >> 16;
|
||||
dma_cap->vlins = (hw_cap & GMAC_HW_FEAT_SAVLANINS) >> 27;
|
||||
dma_cap->arpoffsel = (hw_cap & GMAC_HW_FEAT_ARPOFFSEL) >> 9;
|
||||
|
||||
/* MAC HW feature1 */
|
||||
hw_cap = readl(ioaddr + GMAC_HW_FEATURE1);
|
||||
dma_cap->l3l4fnum = (hw_cap & GMAC_HW_FEAT_L3L4FNUM) >> 27;
|
||||
dma_cap->hash_tb_sz = (hw_cap & GMAC_HW_HASH_TB_SZ) >> 24;
|
||||
dma_cap->av = (hw_cap & GMAC_HW_FEAT_AVSEL) >> 20;
|
||||
dma_cap->tsoen = (hw_cap & GMAC_HW_TSOEN) >> 18;
|
||||
dma_cap->sphen = (hw_cap & GMAC_HW_FEAT_SPHEN) >> 17;
|
||||
|
||||
dma_cap->addr64 = (hw_cap & GMAC_HW_ADDR64) >> 14;
|
||||
switch (dma_cap->addr64) {
|
||||
case 0:
|
||||
dma_cap->addr64 = 32;
|
||||
break;
|
||||
case 1:
|
||||
dma_cap->addr64 = 40;
|
||||
break;
|
||||
case 2:
|
||||
dma_cap->addr64 = 48;
|
||||
break;
|
||||
default:
|
||||
dma_cap->addr64 = 32;
|
||||
break;
|
||||
}
|
||||
|
||||
/* RX and TX FIFO sizes are encoded as log2(n / 128). Undo that by
|
||||
* shifting and store the sizes in bytes.
|
||||
*/
|
||||
dma_cap->tx_fifo_size = 128 << ((hw_cap & GMAC_HW_TXFIFOSIZE) >> 6);
|
||||
dma_cap->rx_fifo_size = 128 << ((hw_cap & GMAC_HW_RXFIFOSIZE) >> 0);
|
||||
/* MAC HW feature2 */
|
||||
hw_cap = readl(ioaddr + GMAC_HW_FEATURE2);
|
||||
/* TX and RX number of channels */
|
||||
dma_cap->number_rx_channel =
|
||||
((hw_cap & GMAC_HW_FEAT_RXCHCNT) >> 12) + 1;
|
||||
dma_cap->number_tx_channel =
|
||||
((hw_cap & GMAC_HW_FEAT_TXCHCNT) >> 18) + 1;
|
||||
/* TX and RX number of queues */
|
||||
dma_cap->number_rx_queues =
|
||||
((hw_cap & GMAC_HW_FEAT_RXQCNT) >> 0) + 1;
|
||||
dma_cap->number_tx_queues =
|
||||
((hw_cap & GMAC_HW_FEAT_TXQCNT) >> 6) + 1;
|
||||
/* PPS output */
|
||||
dma_cap->pps_out_num = (hw_cap & GMAC_HW_FEAT_PPSOUTNUM) >> 24;
|
||||
|
||||
/* IEEE 1588-2002 */
|
||||
dma_cap->time_stamp = 0;
|
||||
/* Number of Auxiliary Snapshot Inputs */
|
||||
dma_cap->aux_snapshot_n = (hw_cap & GMAC_HW_FEAT_AUXSNAPNUM) >> 28;
|
||||
|
||||
/* MAC HW feature3 */
|
||||
hw_cap = readl(ioaddr + GMAC_HW_FEATURE3);
|
||||
|
||||
/* 5.10 Features */
|
||||
dma_cap->asp = (hw_cap & GMAC_HW_FEAT_ASP) >> 28;
|
||||
dma_cap->tbssel = (hw_cap & GMAC_HW_FEAT_TBSSEL) >> 27;
|
||||
dma_cap->fpesel = (hw_cap & GMAC_HW_FEAT_FPESEL) >> 26;
|
||||
dma_cap->estwid = (hw_cap & GMAC_HW_FEAT_ESTWID) >> 20;
|
||||
dma_cap->estdep = (hw_cap & GMAC_HW_FEAT_ESTDEP) >> 17;
|
||||
dma_cap->estsel = (hw_cap & GMAC_HW_FEAT_ESTSEL) >> 16;
|
||||
dma_cap->frpes = (hw_cap & GMAC_HW_FEAT_FRPES) >> 13;
|
||||
dma_cap->frpbs = (hw_cap & GMAC_HW_FEAT_FRPBS) >> 11;
|
||||
dma_cap->frpsel = (hw_cap & GMAC_HW_FEAT_FRPSEL) >> 10;
|
||||
dma_cap->dvlan = (hw_cap & GMAC_HW_FEAT_DVLAN) >> 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Enable/disable TSO feature and set MSS */
|
||||
static void dwmac4_enable_tso(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value;
|
||||
|
||||
if (en) {
|
||||
/* enable TSO */
|
||||
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
writel(value | DMA_CONTROL_TSE,
|
||||
ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
} else {
|
||||
/* enable TSO */
|
||||
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
writel(value & ~DMA_CONTROL_TSE,
|
||||
ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
}
|
||||
}
|
||||
|
||||
static void dwmac4_qmode(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 channel, u8 qmode)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(dwmac4_addrs,
|
||||
channel));
|
||||
|
||||
mtl_tx_op &= ~MTL_OP_MODE_TXQEN_MASK;
|
||||
if (qmode != MTL_QUEUE_AVB)
|
||||
mtl_tx_op |= MTL_OP_MODE_TXQEN;
|
||||
else
|
||||
mtl_tx_op |= MTL_OP_MODE_TXQEN_AV;
|
||||
|
||||
writel(mtl_tx_op, ioaddr + MTL_CHAN_TX_OP_MODE(dwmac4_addrs, channel));
|
||||
}
|
||||
|
||||
static void dwmac4_set_bfsize(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int bfsize, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value &= ~DMA_RBSZ_MASK;
|
||||
value |= (bfsize << DMA_RBSZ_SHIFT) & DMA_RBSZ_MASK;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
static void dwmac4_enable_sph(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + GMAC_EXT_CONFIG);
|
||||
|
||||
value &= ~GMAC_CONFIG_HDSMS;
|
||||
value |= GMAC_CONFIG_HDSMS_256; /* Segment max 256 bytes */
|
||||
writel(value, ioaddr + GMAC_EXT_CONFIG);
|
||||
|
||||
value = readl(ioaddr + GMAC_EXT_CFG1);
|
||||
value |= GMAC_CONFIG1_SPLM(1); /* Split mode set to L2OFST */
|
||||
value |= GMAC_CONFIG1_SAVE_EN; /* Enable Split AV mode */
|
||||
writel(value, ioaddr + GMAC_EXT_CFG1);
|
||||
|
||||
value = readl(ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan));
|
||||
if (en)
|
||||
value |= DMA_CONTROL_SPH;
|
||||
else
|
||||
value &= ~DMA_CONTROL_SPH;
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
static int dwmac4_enable_tbs(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
if (en)
|
||||
value |= DMA_CONTROL_EDSE;
|
||||
else
|
||||
value &= ~DMA_CONTROL_EDSE;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs,
|
||||
chan)) & DMA_CONTROL_EDSE;
|
||||
if (en && !value)
|
||||
return -EIO;
|
||||
|
||||
writel(DMA_TBS_DEF_FTOS, ioaddr + DMA_TBS_CTRL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct stmmac_dma_ops dwmac4_dma_ops = {
|
||||
.reset = dwmac4_dma_reset,
|
||||
.init = dwmac4_dma_init,
|
||||
.init_chan = dwmac4_dma_init_channel,
|
||||
.init_rx_chan = dwmac4_dma_init_rx_chan,
|
||||
.init_tx_chan = dwmac4_dma_init_tx_chan,
|
||||
.axi = dwmac4_dma_axi,
|
||||
.dump_regs = dwmac4_dump_dma_regs,
|
||||
.dma_rx_mode = dwmac4_dma_rx_chan_op_mode,
|
||||
.dma_tx_mode = dwmac4_dma_tx_chan_op_mode,
|
||||
.enable_dma_irq = dwmac4_enable_dma_irq,
|
||||
.disable_dma_irq = dwmac4_disable_dma_irq,
|
||||
.start_tx = dwmac4_dma_start_tx,
|
||||
.stop_tx = dwmac4_dma_stop_tx,
|
||||
.start_rx = dwmac4_dma_start_rx,
|
||||
.stop_rx = dwmac4_dma_stop_rx,
|
||||
.dma_interrupt = dwmac4_dma_interrupt,
|
||||
.get_hw_feature = dwmac4_get_hw_feature,
|
||||
.rx_watchdog = dwmac4_rx_watchdog,
|
||||
.set_rx_ring_len = dwmac4_set_rx_ring_len,
|
||||
.set_tx_ring_len = dwmac4_set_tx_ring_len,
|
||||
.set_rx_tail_ptr = dwmac4_set_rx_tail_ptr,
|
||||
.set_tx_tail_ptr = dwmac4_set_tx_tail_ptr,
|
||||
.enable_tso = dwmac4_enable_tso,
|
||||
.qmode = dwmac4_qmode,
|
||||
.set_bfsize = dwmac4_set_bfsize,
|
||||
.enable_sph = dwmac4_enable_sph,
|
||||
};
|
||||
|
||||
const struct stmmac_dma_ops dwmac410_dma_ops = {
|
||||
.reset = dwmac4_dma_reset,
|
||||
.init = dwmac4_dma_init,
|
||||
.init_chan = dwmac410_dma_init_channel,
|
||||
.init_rx_chan = dwmac4_dma_init_rx_chan,
|
||||
.init_tx_chan = dwmac4_dma_init_tx_chan,
|
||||
.axi = dwmac4_dma_axi,
|
||||
.dump_regs = dwmac4_dump_dma_regs,
|
||||
.dma_rx_mode = dwmac4_dma_rx_chan_op_mode,
|
||||
.dma_tx_mode = dwmac4_dma_tx_chan_op_mode,
|
||||
.enable_dma_irq = dwmac410_enable_dma_irq,
|
||||
.disable_dma_irq = dwmac4_disable_dma_irq,
|
||||
.start_tx = dwmac4_dma_start_tx,
|
||||
.stop_tx = dwmac4_dma_stop_tx,
|
||||
.start_rx = dwmac4_dma_start_rx,
|
||||
.stop_rx = dwmac4_dma_stop_rx,
|
||||
.dma_interrupt = dwmac4_dma_interrupt,
|
||||
.get_hw_feature = dwmac4_get_hw_feature,
|
||||
.rx_watchdog = dwmac4_rx_watchdog,
|
||||
.set_rx_ring_len = dwmac4_set_rx_ring_len,
|
||||
.set_tx_ring_len = dwmac4_set_tx_ring_len,
|
||||
.set_rx_tail_ptr = dwmac4_set_rx_tail_ptr,
|
||||
.set_tx_tail_ptr = dwmac4_set_tx_tail_ptr,
|
||||
.enable_tso = dwmac4_enable_tso,
|
||||
.qmode = dwmac4_qmode,
|
||||
.set_bfsize = dwmac4_set_bfsize,
|
||||
.enable_sph = dwmac4_enable_sph,
|
||||
.enable_tbs = dwmac4_enable_tbs,
|
||||
};
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* DWMAC4 DMA Header file.
|
||||
*
|
||||
* Copyright (C) 2007-2015 STMicroelectronics Ltd
|
||||
*
|
||||
* Author: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
*/
|
||||
|
||||
#ifndef __DWMAC4_DMA_H__
|
||||
#define __DWMAC4_DMA_H__
|
||||
|
||||
/* Define the max channel number used for tx (also rx).
|
||||
* dwmac4 accepts up to 8 channels for TX (and also 8 channels for RX
|
||||
*/
|
||||
#define DMA_CHANNEL_NB_MAX 1
|
||||
|
||||
#define DMA_BUS_MODE 0x00001000
|
||||
#define DMA_SYS_BUS_MODE 0x00001004
|
||||
#define DMA_STATUS 0x00001008
|
||||
#define DMA_DEBUG_STATUS_0 0x0000100c
|
||||
#define DMA_DEBUG_STATUS_1 0x00001010
|
||||
#define DMA_DEBUG_STATUS_2 0x00001014
|
||||
#define DMA_AXI_BUS_MODE 0x00001028
|
||||
#define DMA_TBS_CTRL 0x00001050
|
||||
|
||||
/* DMA Bus Mode bitmap */
|
||||
#define DMA_BUS_MODE_DCHE BIT(19)
|
||||
#define DMA_BUS_MODE_INTM_MASK GENMASK(17, 16)
|
||||
#define DMA_BUS_MODE_INTM_SHIFT 16
|
||||
#define DMA_BUS_MODE_INTM_MODE1 0x1
|
||||
#define DMA_BUS_MODE_SFT_RESET BIT(0)
|
||||
|
||||
/* DMA SYS Bus Mode bitmap */
|
||||
#define DMA_BUS_MODE_SPH BIT(24)
|
||||
#define DMA_BUS_MODE_PBL BIT(16)
|
||||
#define DMA_BUS_MODE_PBL_SHIFT 16
|
||||
#define DMA_BUS_MODE_RPBL_SHIFT 16
|
||||
#define DMA_BUS_MODE_MB BIT(14)
|
||||
#define DMA_BUS_MODE_FB BIT(0)
|
||||
|
||||
/* DMA Interrupt top status */
|
||||
#define DMA_STATUS_MAC BIT(17)
|
||||
#define DMA_STATUS_MTL BIT(16)
|
||||
#define DMA_STATUS_CHAN7 BIT(7)
|
||||
#define DMA_STATUS_CHAN6 BIT(6)
|
||||
#define DMA_STATUS_CHAN5 BIT(5)
|
||||
#define DMA_STATUS_CHAN4 BIT(4)
|
||||
#define DMA_STATUS_CHAN3 BIT(3)
|
||||
#define DMA_STATUS_CHAN2 BIT(2)
|
||||
#define DMA_STATUS_CHAN1 BIT(1)
|
||||
#define DMA_STATUS_CHAN0 BIT(0)
|
||||
|
||||
/* DMA debug status bitmap */
|
||||
#define DMA_DEBUG_STATUS_TS_MASK 0xf
|
||||
#define DMA_DEBUG_STATUS_RS_MASK 0xf
|
||||
|
||||
/* DMA AXI bitmap */
|
||||
#define DMA_AXI_EN_LPI BIT(31)
|
||||
#define DMA_AXI_LPI_XIT_FRM BIT(30)
|
||||
#define DMA_AXI_WR_OSR_LMT GENMASK(27, 24)
|
||||
#define DMA_AXI_WR_OSR_LMT_SHIFT 24
|
||||
#define DMA_AXI_RD_OSR_LMT GENMASK(19, 16)
|
||||
#define DMA_AXI_RD_OSR_LMT_SHIFT 16
|
||||
|
||||
#define DMA_AXI_OSR_MAX 0xf
|
||||
#define DMA_AXI_MAX_OSR_LIMIT ((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \
|
||||
(DMA_AXI_OSR_MAX << DMA_AXI_RD_OSR_LMT_SHIFT))
|
||||
|
||||
#define DMA_SYS_BUS_MB BIT(14)
|
||||
#define DMA_AXI_1KBBE BIT(13)
|
||||
#define DMA_SYS_BUS_AAL BIT(12)
|
||||
#define DMA_SYS_BUS_EAME BIT(11)
|
||||
#define DMA_AXI_BLEN256 BIT(7)
|
||||
#define DMA_AXI_BLEN128 BIT(6)
|
||||
#define DMA_AXI_BLEN64 BIT(5)
|
||||
#define DMA_AXI_BLEN32 BIT(4)
|
||||
#define DMA_AXI_BLEN16 BIT(3)
|
||||
#define DMA_AXI_BLEN8 BIT(2)
|
||||
#define DMA_AXI_BLEN4 BIT(1)
|
||||
#define DMA_SYS_BUS_FB BIT(0)
|
||||
|
||||
#define DMA_BURST_LEN_DEFAULT (DMA_AXI_BLEN256 | DMA_AXI_BLEN128 | \
|
||||
DMA_AXI_BLEN64 | DMA_AXI_BLEN32 | \
|
||||
DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | \
|
||||
DMA_AXI_BLEN4)
|
||||
|
||||
#define DMA_AXI_BURST_LEN_MASK 0x000000FE
|
||||
|
||||
/* DMA TBS Control */
|
||||
#define DMA_TBS_FTOS GENMASK(31, 8)
|
||||
#define DMA_TBS_FTOV BIT(0)
|
||||
#define DMA_TBS_DEF_FTOS (DMA_TBS_FTOS | DMA_TBS_FTOV)
|
||||
|
||||
/* Following DMA defines are channel-oriented */
|
||||
#define DMA_CHAN_BASE_ADDR 0x00001100
|
||||
#define DMA_CHAN_BASE_OFFSET 0x80
|
||||
|
||||
static inline u32 dma_chanx_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->dma_chan + (x * addrs->dma_chan_offset);
|
||||
else
|
||||
addr = DMA_CHAN_BASE_ADDR + (x * DMA_CHAN_BASE_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define DMA_CHAN_REG_NUMBER 17
|
||||
|
||||
#define DMA_CHAN_CONTROL(addrs, x) dma_chanx_base_addr(addrs, x)
|
||||
#define DMA_CHAN_TX_CONTROL(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x4)
|
||||
#define DMA_CHAN_RX_CONTROL(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x8)
|
||||
#define DMA_CHAN_TX_BASE_ADDR_HI(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x10)
|
||||
#define DMA_CHAN_TX_BASE_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x14)
|
||||
#define DMA_CHAN_RX_BASE_ADDR_HI(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x18)
|
||||
#define DMA_CHAN_RX_BASE_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x1c)
|
||||
#define DMA_CHAN_TX_END_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x20)
|
||||
#define DMA_CHAN_RX_END_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x28)
|
||||
#define DMA_CHAN_TX_RING_LEN(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x2c)
|
||||
#define DMA_CHAN_RX_RING_LEN(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x30)
|
||||
#define DMA_CHAN_INTR_ENA(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x34)
|
||||
#define DMA_CHAN_RX_WATCHDOG(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x38)
|
||||
#define DMA_CHAN_SLOT_CTRL_STATUS(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x3c)
|
||||
#define DMA_CHAN_CUR_TX_DESC(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x44)
|
||||
#define DMA_CHAN_CUR_RX_DESC(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x4c)
|
||||
#define DMA_CHAN_CUR_TX_BUF_ADDR_HI(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x50)
|
||||
#define DMA_CHAN_CUR_TX_BUF_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x54)
|
||||
#define DMA_CHAN_CUR_RX_BUF_ADDR_HI(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x58)
|
||||
#define DMA_CHAN_CUR_RX_BUF_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x5c)
|
||||
#define DMA_CHAN_STATUS(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x60)
|
||||
|
||||
/* DMA Control X */
|
||||
#define DMA_CONTROL_SPH BIT(24)
|
||||
#define DMA_CONTROL_MSS_MASK GENMASK(13, 0)
|
||||
|
||||
/* DMA Tx Channel X Control register defines */
|
||||
#define DMA_CONTROL_EDSE BIT(28)
|
||||
#define DMA_CONTROL_TSE BIT(12)
|
||||
#define DMA_CONTROL_OSP BIT(4)
|
||||
#define DMA_CONTROL_ST BIT(0)
|
||||
|
||||
/* DMA Rx Channel X Control register defines */
|
||||
#define DMA_CONTROL_SR BIT(0)
|
||||
#define DMA_RBSZ_MASK GENMASK(14, 1)
|
||||
#define DMA_RBSZ_SHIFT 1
|
||||
|
||||
/* Interrupt status per channel */
|
||||
#define DMA_CHAN_STATUS_REB GENMASK(21, 19)
|
||||
#define DMA_CHAN_STATUS_REB_SHIFT 19
|
||||
#define DMA_CHAN_STATUS_TEB GENMASK(18, 16)
|
||||
#define DMA_CHAN_STATUS_TEB_SHIFT 16
|
||||
#define DMA_CHAN_STATUS_NIS BIT(15)
|
||||
#define DMA_CHAN_STATUS_AIS BIT(14)
|
||||
#define DMA_CHAN_STATUS_CDE BIT(13)
|
||||
#define DMA_CHAN_STATUS_FBE BIT(12)
|
||||
#define DMA_CHAN_STATUS_ERI BIT(11)
|
||||
#define DMA_CHAN_STATUS_ETI BIT(10)
|
||||
#define DMA_CHAN_STATUS_RWT BIT(9)
|
||||
#define DMA_CHAN_STATUS_RPS BIT(8)
|
||||
#define DMA_CHAN_STATUS_RBU BIT(7)
|
||||
#define DMA_CHAN_STATUS_RI BIT(6)
|
||||
#define DMA_CHAN_STATUS_TBU BIT(2)
|
||||
#define DMA_CHAN_STATUS_TPS BIT(1)
|
||||
#define DMA_CHAN_STATUS_TI BIT(0)
|
||||
|
||||
#define DMA_CHAN_STATUS_MSK_COMMON (DMA_CHAN_STATUS_NIS | \
|
||||
DMA_CHAN_STATUS_AIS | \
|
||||
DMA_CHAN_STATUS_CDE | \
|
||||
DMA_CHAN_STATUS_FBE)
|
||||
|
||||
#define DMA_CHAN_STATUS_MSK_RX (DMA_CHAN_STATUS_REB | \
|
||||
DMA_CHAN_STATUS_ERI | \
|
||||
DMA_CHAN_STATUS_RWT | \
|
||||
DMA_CHAN_STATUS_RPS | \
|
||||
DMA_CHAN_STATUS_RBU | \
|
||||
DMA_CHAN_STATUS_RI | \
|
||||
DMA_CHAN_STATUS_MSK_COMMON)
|
||||
|
||||
#define DMA_CHAN_STATUS_MSK_TX (DMA_CHAN_STATUS_ETI | \
|
||||
DMA_CHAN_STATUS_TBU | \
|
||||
DMA_CHAN_STATUS_TPS | \
|
||||
DMA_CHAN_STATUS_TI | \
|
||||
DMA_CHAN_STATUS_MSK_COMMON)
|
||||
|
||||
/* Interrupt enable bits per channel */
|
||||
#define DMA_CHAN_INTR_ENA_NIE BIT(16)
|
||||
#define DMA_CHAN_INTR_ENA_AIE BIT(15)
|
||||
#define DMA_CHAN_INTR_ENA_NIE_4_10 BIT(15)
|
||||
#define DMA_CHAN_INTR_ENA_AIE_4_10 BIT(14)
|
||||
#define DMA_CHAN_INTR_ENA_CDE BIT(13)
|
||||
#define DMA_CHAN_INTR_ENA_FBE BIT(12)
|
||||
#define DMA_CHAN_INTR_ENA_ERE BIT(11)
|
||||
#define DMA_CHAN_INTR_ENA_ETE BIT(10)
|
||||
#define DMA_CHAN_INTR_ENA_RWE BIT(9)
|
||||
#define DMA_CHAN_INTR_ENA_RSE BIT(8)
|
||||
#define DMA_CHAN_INTR_ENA_RBUE BIT(7)
|
||||
#define DMA_CHAN_INTR_ENA_RIE BIT(6)
|
||||
#define DMA_CHAN_INTR_ENA_TBUE BIT(2)
|
||||
#define DMA_CHAN_INTR_ENA_TSE BIT(1)
|
||||
#define DMA_CHAN_INTR_ENA_TIE BIT(0)
|
||||
|
||||
#define DMA_CHAN_INTR_NORMAL (DMA_CHAN_INTR_ENA_NIE | \
|
||||
DMA_CHAN_INTR_ENA_RIE | \
|
||||
DMA_CHAN_INTR_ENA_TIE)
|
||||
|
||||
#define DMA_CHAN_INTR_ABNORMAL (DMA_CHAN_INTR_ENA_AIE | \
|
||||
DMA_CHAN_INTR_ENA_FBE)
|
||||
/* DMA default interrupt mask for 4.00 */
|
||||
#define DMA_CHAN_INTR_DEFAULT_MASK (DMA_CHAN_INTR_NORMAL | \
|
||||
DMA_CHAN_INTR_ABNORMAL)
|
||||
#define DMA_CHAN_INTR_DEFAULT_RX (DMA_CHAN_INTR_ENA_RIE)
|
||||
#define DMA_CHAN_INTR_DEFAULT_TX (DMA_CHAN_INTR_ENA_TIE)
|
||||
|
||||
#define DMA_CHAN_INTR_NORMAL_4_10 (DMA_CHAN_INTR_ENA_NIE_4_10 | \
|
||||
DMA_CHAN_INTR_ENA_RIE | \
|
||||
DMA_CHAN_INTR_ENA_TIE)
|
||||
|
||||
#define DMA_CHAN_INTR_ABNORMAL_4_10 (DMA_CHAN_INTR_ENA_AIE_4_10 | \
|
||||
DMA_CHAN_INTR_ENA_FBE)
|
||||
/* DMA default interrupt mask for 4.10a */
|
||||
#define DMA_CHAN_INTR_DEFAULT_MASK_4_10 (DMA_CHAN_INTR_NORMAL_4_10 | \
|
||||
DMA_CHAN_INTR_ABNORMAL_4_10)
|
||||
#define DMA_CHAN_INTR_DEFAULT_RX_4_10 (DMA_CHAN_INTR_ENA_RIE)
|
||||
#define DMA_CHAN_INTR_DEFAULT_TX_4_10 (DMA_CHAN_INTR_ENA_TIE)
|
||||
|
||||
/* channel 0 specific fields */
|
||||
#define DMA_CHAN0_DBG_STAT_TPS GENMASK(15, 12)
|
||||
#define DMA_CHAN0_DBG_STAT_TPS_SHIFT 12
|
||||
#define DMA_CHAN0_DBG_STAT_RPS GENMASK(11, 8)
|
||||
#define DMA_CHAN0_DBG_STAT_RPS_SHIFT 8
|
||||
|
||||
int dwmac4_dma_reset(void __iomem *ioaddr);
|
||||
void dwmac4_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void dwmac410_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void dwmac4_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void dwmac410_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void dwmac4_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void dwmac4_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void dwmac4_dma_start_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void dwmac4_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 chan, u32 dir);
|
||||
void dwmac4_set_rx_ring_len(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 len, u32 chan);
|
||||
void dwmac4_set_tx_ring_len(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 len, u32 chan);
|
||||
void dwmac4_set_rx_tail_ptr(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 tail_ptr, u32 chan);
|
||||
void dwmac4_set_tx_tail_ptr(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 tail_ptr, u32 chan);
|
||||
|
||||
#endif /* __DWMAC4_DMA_H__ */
|
||||
|
|
@ -0,0 +1,629 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
|
||||
* DWC Ether MAC version 4.xx has been used for developing this code.
|
||||
*
|
||||
* This contains the functions to handle the dma.
|
||||
*
|
||||
* Copyright (C) 2015 STMicroelectronics Ltd
|
||||
*
|
||||
* Author: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include "dwmac4.h"
|
||||
#include "dwmac4_dma.h"
|
||||
#include "stmmac.h"
|
||||
|
||||
static void dwmac4_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_SYS_BUS_MODE);
|
||||
int i;
|
||||
|
||||
pr_info("dwmac4: Master AXI performs %s burst length\n",
|
||||
(value & DMA_SYS_BUS_FB) ? "fixed" : "any");
|
||||
|
||||
if (axi->axi_lpi_en)
|
||||
value |= DMA_AXI_EN_LPI;
|
||||
if (axi->axi_xit_frm)
|
||||
value |= DMA_AXI_LPI_XIT_FRM;
|
||||
|
||||
value &= ~DMA_AXI_WR_OSR_LMT;
|
||||
value |= (axi->axi_wr_osr_lmt & DMA_AXI_OSR_MAX) <<
|
||||
DMA_AXI_WR_OSR_LMT_SHIFT;
|
||||
|
||||
value &= ~DMA_AXI_RD_OSR_LMT;
|
||||
value |= (axi->axi_rd_osr_lmt & DMA_AXI_OSR_MAX) <<
|
||||
DMA_AXI_RD_OSR_LMT_SHIFT;
|
||||
|
||||
/* Depending on the UNDEF bit the Master AXI will perform any burst
|
||||
* length according to the BLEN programmed (by default all BLEN are
|
||||
* set).
|
||||
*/
|
||||
for (i = 0; i < AXI_BLEN; i++) {
|
||||
switch (axi->axi_blen[i]) {
|
||||
case 256:
|
||||
value |= DMA_AXI_BLEN256;
|
||||
break;
|
||||
case 128:
|
||||
value |= DMA_AXI_BLEN128;
|
||||
break;
|
||||
case 64:
|
||||
value |= DMA_AXI_BLEN64;
|
||||
break;
|
||||
case 32:
|
||||
value |= DMA_AXI_BLEN32;
|
||||
break;
|
||||
case 16:
|
||||
value |= DMA_AXI_BLEN16;
|
||||
break;
|
||||
case 8:
|
||||
value |= DMA_AXI_BLEN8;
|
||||
break;
|
||||
case 4:
|
||||
value |= DMA_AXI_BLEN4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writel(value, ioaddr + DMA_SYS_BUS_MODE);
|
||||
}
|
||||
|
||||
static void dwmac4_dma_init_rx_chan(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t dma_rx_phy, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value;
|
||||
u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
|
||||
|
||||
value = readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
value = value | (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
|
||||
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && likely(dma_cfg->eame))
|
||||
writel(upper_32_bits(dma_rx_phy),
|
||||
ioaddr + DMA_CHAN_RX_BASE_ADDR_HI(dwmac4_addrs, chan));
|
||||
|
||||
writel(lower_32_bits(dma_rx_phy),
|
||||
ioaddr + DMA_CHAN_RX_BASE_ADDR(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
static void dwmac4_dma_init_tx_chan(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t dma_tx_phy, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value;
|
||||
u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
|
||||
|
||||
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
value = value | (txpbl << DMA_BUS_MODE_PBL_SHIFT);
|
||||
|
||||
/* Enable OSP to get best performance */
|
||||
value |= DMA_CONTROL_OSP;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && likely(dma_cfg->eame))
|
||||
writel(upper_32_bits(dma_tx_phy),
|
||||
ioaddr + DMA_CHAN_TX_BASE_ADDR_HI(dwmac4_addrs, chan));
|
||||
|
||||
writel(lower_32_bits(dma_tx_phy),
|
||||
ioaddr + DMA_CHAN_TX_BASE_ADDR(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
static void dwmac4_dma_init_channel(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value;
|
||||
|
||||
/* common channel control register config */
|
||||
value = readl(ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan));
|
||||
if (dma_cfg->pblx8)
|
||||
value = value | DMA_BUS_MODE_PBL;
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
/* Mask interrupts by writing to CSR7 */
|
||||
writel(DMA_CHAN_INTR_DEFAULT_MASK,
|
||||
ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
static void dwmac410_dma_init_channel(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value;
|
||||
|
||||
/* common channel control register config */
|
||||
value = readl(ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan));
|
||||
if (dma_cfg->pblx8)
|
||||
value = value | DMA_BUS_MODE_PBL;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
/* Mask interrupts by writing to CSR7 */
|
||||
writel(DMA_CHAN_INTR_DEFAULT_MASK_4_10,
|
||||
ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
static void dwmac4_dma_init(void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_SYS_BUS_MODE);
|
||||
|
||||
/* Set the Fixed burst mode */
|
||||
if (dma_cfg->fixed_burst)
|
||||
value |= DMA_SYS_BUS_FB;
|
||||
|
||||
/* Mixed Burst has no effect when fb is set */
|
||||
if (dma_cfg->mixed_burst)
|
||||
value |= DMA_SYS_BUS_MB;
|
||||
|
||||
if (dma_cfg->aal)
|
||||
value |= DMA_SYS_BUS_AAL;
|
||||
|
||||
if (dma_cfg->eame)
|
||||
value |= DMA_SYS_BUS_EAME;
|
||||
|
||||
writel(value, ioaddr + DMA_SYS_BUS_MODE);
|
||||
|
||||
value = readl(ioaddr + DMA_BUS_MODE);
|
||||
|
||||
if (dma_cfg->multi_msi_en) {
|
||||
value &= ~DMA_BUS_MODE_INTM_MASK;
|
||||
value |= (DMA_BUS_MODE_INTM_MODE1 << DMA_BUS_MODE_INTM_SHIFT);
|
||||
}
|
||||
|
||||
if (dma_cfg->dche)
|
||||
value |= DMA_BUS_MODE_DCHE;
|
||||
|
||||
writel(value, ioaddr + DMA_BUS_MODE);
|
||||
|
||||
}
|
||||
|
||||
static void _dwmac4_dump_dma_regs(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 channel,
|
||||
u32 *reg_space)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
const struct dwmac4_addrs *default_addrs = NULL;
|
||||
|
||||
/* Purposely save the registers in the "normal" layout, regardless of
|
||||
* platform modifications, to keep reg_space size constant
|
||||
*/
|
||||
reg_space[DMA_CHAN_CONTROL(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_TX_CONTROL(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_RX_CONTROL(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_TX_BASE_ADDR_HI(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_TX_BASE_ADDR_HI(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_TX_BASE_ADDR(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_TX_BASE_ADDR(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_RX_BASE_ADDR_HI(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_RX_BASE_ADDR_HI(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_RX_BASE_ADDR(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_RX_BASE_ADDR(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_TX_END_ADDR(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_TX_END_ADDR(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_RX_END_ADDR(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_RX_END_ADDR(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_TX_RING_LEN(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_TX_RING_LEN(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_RX_RING_LEN(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_RX_RING_LEN(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_INTR_ENA(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_RX_WATCHDOG(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_RX_WATCHDOG(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_SLOT_CTRL_STATUS(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_SLOT_CTRL_STATUS(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_CUR_TX_DESC(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CUR_TX_DESC(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_CUR_RX_DESC(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CUR_RX_DESC(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_CUR_TX_BUF_ADDR_HI(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CUR_TX_BUF_ADDR_HI(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_CUR_TX_BUF_ADDR(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CUR_TX_BUF_ADDR(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_CUR_RX_BUF_ADDR_HI(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CUR_RX_BUF_ADDR_HI(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_CUR_RX_BUF_ADDR(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_CUR_RX_BUF_ADDR(dwmac4_addrs, channel));
|
||||
reg_space[DMA_CHAN_STATUS(default_addrs, channel) / 4] =
|
||||
readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, channel));
|
||||
}
|
||||
|
||||
static void dwmac4_dump_dma_regs(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 *reg_space)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DMA_CHANNEL_NB_MAX; i++)
|
||||
_dwmac4_dump_dma_regs(priv, ioaddr, i, reg_space);
|
||||
}
|
||||
|
||||
static void dwmac4_rx_watchdog(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 riwt, u32 queue)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(dwmac4_addrs, queue));
|
||||
}
|
||||
|
||||
static void dwmac4_dma_rx_chan_op_mode(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, int mode,
|
||||
u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
unsigned int rqs = fifosz / 256 - 1;
|
||||
u32 mtl_rx_op;
|
||||
|
||||
mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(dwmac4_addrs, channel));
|
||||
|
||||
if (mode == SF_DMA_MODE) {
|
||||
pr_debug("GMAC: enable RX store and forward mode\n");
|
||||
mtl_rx_op |= MTL_OP_MODE_RSF;
|
||||
} else {
|
||||
pr_debug("GMAC: disable RX SF mode (threshold %d)\n", mode);
|
||||
mtl_rx_op &= ~MTL_OP_MODE_RSF;
|
||||
mtl_rx_op &= MTL_OP_MODE_RTC_MASK;
|
||||
if (mode <= 32)
|
||||
mtl_rx_op |= MTL_OP_MODE_RTC_32;
|
||||
else if (mode <= 64)
|
||||
mtl_rx_op |= MTL_OP_MODE_RTC_64;
|
||||
else if (mode <= 96)
|
||||
mtl_rx_op |= MTL_OP_MODE_RTC_96;
|
||||
else
|
||||
mtl_rx_op |= MTL_OP_MODE_RTC_128;
|
||||
}
|
||||
|
||||
mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
|
||||
mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
|
||||
|
||||
/* Enable flow control only if each channel gets 4 KiB or more FIFO and
|
||||
* only if channel is not an AVB channel.
|
||||
*/
|
||||
if ((fifosz >= 4096) && (qmode != MTL_QUEUE_AVB)) {
|
||||
unsigned int rfd, rfa;
|
||||
|
||||
mtl_rx_op |= MTL_OP_MODE_EHFC;
|
||||
|
||||
/* Set Threshold for Activating Flow Control to min 2 frames,
|
||||
* i.e. 1500 * 2 = 3000 bytes.
|
||||
*
|
||||
* Set Threshold for Deactivating Flow Control to min 1 frame,
|
||||
* i.e. 1500 bytes.
|
||||
*/
|
||||
switch (fifosz) {
|
||||
case 4096:
|
||||
/* This violates the above formula because of FIFO size
|
||||
* limit therefore overflow may occur in spite of this.
|
||||
*/
|
||||
rfd = 0x03; /* Full-2.5K */
|
||||
rfa = 0x01; /* Full-1.5K */
|
||||
break;
|
||||
|
||||
default:
|
||||
rfd = 0x07; /* Full-4.5K */
|
||||
rfa = 0x04; /* Full-3K */
|
||||
break;
|
||||
}
|
||||
|
||||
mtl_rx_op &= ~MTL_OP_MODE_RFD_MASK;
|
||||
mtl_rx_op |= rfd << MTL_OP_MODE_RFD_SHIFT;
|
||||
|
||||
mtl_rx_op &= ~MTL_OP_MODE_RFA_MASK;
|
||||
mtl_rx_op |= rfa << MTL_OP_MODE_RFA_SHIFT;
|
||||
}
|
||||
|
||||
writel(mtl_rx_op, ioaddr + MTL_CHAN_RX_OP_MODE(dwmac4_addrs, channel));
|
||||
}
|
||||
|
||||
static void dwmac4_dma_tx_chan_op_mode(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, int mode,
|
||||
u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(dwmac4_addrs,
|
||||
channel));
|
||||
unsigned int tqs = fifosz / 256 - 1;
|
||||
|
||||
if (mode == SF_DMA_MODE) {
|
||||
pr_debug("GMAC: enable TX store and forward mode\n");
|
||||
/* Transmit COE type 2 cannot be done in cut-through mode. */
|
||||
mtl_tx_op |= MTL_OP_MODE_TSF;
|
||||
} else {
|
||||
pr_debug("GMAC: disabling TX SF (threshold %d)\n", mode);
|
||||
mtl_tx_op &= ~MTL_OP_MODE_TSF;
|
||||
mtl_tx_op &= MTL_OP_MODE_TTC_MASK;
|
||||
/* Set the transmit threshold */
|
||||
if (mode <= 32)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_32;
|
||||
else if (mode <= 64)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_64;
|
||||
else if (mode <= 96)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_96;
|
||||
else if (mode <= 128)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_128;
|
||||
else if (mode <= 192)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_192;
|
||||
else if (mode <= 256)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_256;
|
||||
else if (mode <= 384)
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_384;
|
||||
else
|
||||
mtl_tx_op |= MTL_OP_MODE_TTC_512;
|
||||
}
|
||||
/* For an IP with DWC_EQOS_NUM_TXQ == 1, the fields TXQEN and TQS are RO
|
||||
* with reset values: TXQEN on, TQS == DWC_EQOS_TXFIFO_SIZE.
|
||||
* For an IP with DWC_EQOS_NUM_TXQ > 1, the fields TXQEN and TQS are R/W
|
||||
* with reset values: TXQEN off, TQS 256 bytes.
|
||||
*
|
||||
* TXQEN must be written for multi-channel operation and TQS must
|
||||
* reflect the available fifo size per queue (total fifo size / number
|
||||
* of enabled queues).
|
||||
*/
|
||||
mtl_tx_op &= ~MTL_OP_MODE_TXQEN_MASK;
|
||||
if (qmode != MTL_QUEUE_AVB)
|
||||
mtl_tx_op |= MTL_OP_MODE_TXQEN;
|
||||
else
|
||||
mtl_tx_op |= MTL_OP_MODE_TXQEN_AV;
|
||||
mtl_tx_op &= ~MTL_OP_MODE_TQS_MASK;
|
||||
mtl_tx_op |= tqs << MTL_OP_MODE_TQS_SHIFT;
|
||||
|
||||
writel(mtl_tx_op, ioaddr + MTL_CHAN_TX_OP_MODE(dwmac4_addrs, channel));
|
||||
}
|
||||
|
||||
static int dwmac4_get_hw_feature(void __iomem *ioaddr,
|
||||
struct dma_features *dma_cap)
|
||||
{
|
||||
u32 hw_cap = readl(ioaddr + GMAC_HW_FEATURE0);
|
||||
|
||||
/* MAC HW feature0 */
|
||||
dma_cap->mbps_10_100 = (hw_cap & GMAC_HW_FEAT_MIISEL);
|
||||
dma_cap->mbps_1000 = (hw_cap & GMAC_HW_FEAT_GMIISEL) >> 1;
|
||||
dma_cap->half_duplex = (hw_cap & GMAC_HW_FEAT_HDSEL) >> 2;
|
||||
dma_cap->vlhash = (hw_cap & GMAC_HW_FEAT_VLHASH) >> 4;
|
||||
dma_cap->multi_addr = (hw_cap & GMAC_HW_FEAT_ADDMAC) >> 18;
|
||||
dma_cap->pcs = (hw_cap & GMAC_HW_FEAT_PCSSEL) >> 3;
|
||||
dma_cap->sma_mdio = (hw_cap & GMAC_HW_FEAT_SMASEL) >> 5;
|
||||
dma_cap->pmt_remote_wake_up = (hw_cap & GMAC_HW_FEAT_RWKSEL) >> 6;
|
||||
dma_cap->pmt_magic_frame = (hw_cap & GMAC_HW_FEAT_MGKSEL) >> 7;
|
||||
/* MMC */
|
||||
dma_cap->rmon = (hw_cap & GMAC_HW_FEAT_MMCSEL) >> 8;
|
||||
/* IEEE 1588-2008 */
|
||||
dma_cap->atime_stamp = (hw_cap & GMAC_HW_FEAT_TSSEL) >> 12;
|
||||
/* 802.3az - Energy-Efficient Ethernet (EEE) */
|
||||
dma_cap->eee = (hw_cap & GMAC_HW_FEAT_EEESEL) >> 13;
|
||||
/* TX and RX csum */
|
||||
dma_cap->tx_coe = (hw_cap & GMAC_HW_FEAT_TXCOSEL) >> 14;
|
||||
dma_cap->rx_coe = (hw_cap & GMAC_HW_FEAT_RXCOESEL) >> 16;
|
||||
dma_cap->vlins = (hw_cap & GMAC_HW_FEAT_SAVLANINS) >> 27;
|
||||
dma_cap->arpoffsel = (hw_cap & GMAC_HW_FEAT_ARPOFFSEL) >> 9;
|
||||
|
||||
/* MAC HW feature1 */
|
||||
hw_cap = readl(ioaddr + GMAC_HW_FEATURE1);
|
||||
dma_cap->l3l4fnum = (hw_cap & GMAC_HW_FEAT_L3L4FNUM) >> 27;
|
||||
dma_cap->hash_tb_sz = (hw_cap & GMAC_HW_HASH_TB_SZ) >> 24;
|
||||
dma_cap->av = (hw_cap & GMAC_HW_FEAT_AVSEL) >> 20;
|
||||
dma_cap->tsoen = (hw_cap & GMAC_HW_TSOEN) >> 18;
|
||||
dma_cap->sphen = (hw_cap & GMAC_HW_FEAT_SPHEN) >> 17;
|
||||
|
||||
dma_cap->addr64 = (hw_cap & GMAC_HW_ADDR64) >> 14;
|
||||
switch (dma_cap->addr64) {
|
||||
case 0:
|
||||
dma_cap->addr64 = 32;
|
||||
break;
|
||||
case 1:
|
||||
dma_cap->addr64 = 40;
|
||||
break;
|
||||
case 2:
|
||||
dma_cap->addr64 = 48;
|
||||
break;
|
||||
default:
|
||||
dma_cap->addr64 = 32;
|
||||
break;
|
||||
}
|
||||
|
||||
/* RX and TX FIFO sizes are encoded as log2(n / 128). Undo that by
|
||||
* shifting and store the sizes in bytes.
|
||||
*/
|
||||
dma_cap->tx_fifo_size = 128 << ((hw_cap & GMAC_HW_TXFIFOSIZE) >> 6);
|
||||
dma_cap->rx_fifo_size = 128 << ((hw_cap & GMAC_HW_RXFIFOSIZE) >> 0);
|
||||
/* MAC HW feature2 */
|
||||
hw_cap = readl(ioaddr + GMAC_HW_FEATURE2);
|
||||
/* TX and RX number of channels */
|
||||
dma_cap->number_rx_channel =
|
||||
((hw_cap & GMAC_HW_FEAT_RXCHCNT) >> 12) + 1;
|
||||
dma_cap->number_tx_channel =
|
||||
((hw_cap & GMAC_HW_FEAT_TXCHCNT) >> 18) + 1;
|
||||
/* TX and RX number of queues */
|
||||
dma_cap->number_rx_queues =
|
||||
((hw_cap & GMAC_HW_FEAT_RXQCNT) >> 0) + 1;
|
||||
dma_cap->number_tx_queues =
|
||||
((hw_cap & GMAC_HW_FEAT_TXQCNT) >> 6) + 1;
|
||||
/* PPS output */
|
||||
dma_cap->pps_out_num = (hw_cap & GMAC_HW_FEAT_PPSOUTNUM) >> 24;
|
||||
|
||||
/* IEEE 1588-2002 */
|
||||
dma_cap->time_stamp = 0;
|
||||
/* Number of Auxiliary Snapshot Inputs */
|
||||
dma_cap->aux_snapshot_n = (hw_cap & GMAC_HW_FEAT_AUXSNAPNUM) >> 28;
|
||||
|
||||
/* MAC HW feature3 */
|
||||
hw_cap = readl(ioaddr + GMAC_HW_FEATURE3);
|
||||
|
||||
/* 5.10 Features */
|
||||
dma_cap->asp = (hw_cap & GMAC_HW_FEAT_ASP) >> 28;
|
||||
dma_cap->tbssel = (hw_cap & GMAC_HW_FEAT_TBSSEL) >> 27;
|
||||
dma_cap->fpesel = (hw_cap & GMAC_HW_FEAT_FPESEL) >> 26;
|
||||
dma_cap->estwid = (hw_cap & GMAC_HW_FEAT_ESTWID) >> 20;
|
||||
dma_cap->estdep = (hw_cap & GMAC_HW_FEAT_ESTDEP) >> 17;
|
||||
dma_cap->estsel = (hw_cap & GMAC_HW_FEAT_ESTSEL) >> 16;
|
||||
dma_cap->frpes = (hw_cap & GMAC_HW_FEAT_FRPES) >> 13;
|
||||
dma_cap->frpbs = (hw_cap & GMAC_HW_FEAT_FRPBS) >> 11;
|
||||
dma_cap->frpsel = (hw_cap & GMAC_HW_FEAT_FRPSEL) >> 10;
|
||||
dma_cap->dvlan = (hw_cap & GMAC_HW_FEAT_DVLAN) >> 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Enable/disable TSO feature and set MSS */
|
||||
static void dwmac4_enable_tso(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value;
|
||||
|
||||
if (en) {
|
||||
/* enable TSO */
|
||||
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
writel(value | DMA_CONTROL_TSE,
|
||||
ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
} else {
|
||||
/* enable TSO */
|
||||
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
writel(value & ~DMA_CONTROL_TSE,
|
||||
ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
}
|
||||
}
|
||||
|
||||
static void dwmac4_qmode(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 channel, u8 qmode)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(dwmac4_addrs,
|
||||
channel));
|
||||
|
||||
mtl_tx_op &= ~MTL_OP_MODE_TXQEN_MASK;
|
||||
if (qmode != MTL_QUEUE_AVB)
|
||||
mtl_tx_op |= MTL_OP_MODE_TXQEN;
|
||||
else
|
||||
mtl_tx_op |= MTL_OP_MODE_TXQEN_AV;
|
||||
|
||||
writel(mtl_tx_op, ioaddr + MTL_CHAN_TX_OP_MODE(dwmac4_addrs, channel));
|
||||
}
|
||||
|
||||
static void dwmac4_set_bfsize(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int bfsize, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value &= ~DMA_RBSZ_MASK;
|
||||
value |= (bfsize << DMA_RBSZ_SHIFT) & DMA_RBSZ_MASK;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
static void dwmac4_enable_sph(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + GMAC_EXT_CONFIG);
|
||||
|
||||
value &= ~GMAC_CONFIG_HDSMS;
|
||||
value |= GMAC_CONFIG_HDSMS_256; /* Segment max 256 bytes */
|
||||
writel(value, ioaddr + GMAC_EXT_CONFIG);
|
||||
|
||||
value = readl(ioaddr + GMAC_EXT_CFG1);
|
||||
value |= GMAC_CONFIG1_SPLM(1); /* Split mode set to L2OFST */
|
||||
value |= GMAC_CONFIG1_SAVE_EN; /* Enable Split AV mode */
|
||||
writel(value, ioaddr + GMAC_EXT_CFG1);
|
||||
|
||||
value = readl(ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan));
|
||||
if (en)
|
||||
value |= DMA_CONTROL_SPH;
|
||||
else
|
||||
value &= ~DMA_CONTROL_SPH;
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
static int dwmac4_enable_tbs(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
if (en)
|
||||
value |= DMA_CONTROL_EDSE;
|
||||
else
|
||||
value &= ~DMA_CONTROL_EDSE;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs,
|
||||
chan)) & DMA_CONTROL_EDSE;
|
||||
if (en && !value)
|
||||
return -EIO;
|
||||
|
||||
writel(DMA_TBS_DEF_FTOS, ioaddr + DMA_TBS_CTRL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct stmmac_dma_ops dwmac4_dma_ops = {
|
||||
.reset = dwmac4_dma_reset,
|
||||
.init = dwmac4_dma_init,
|
||||
.init_chan = dwmac4_dma_init_channel,
|
||||
.init_rx_chan = dwmac4_dma_init_rx_chan,
|
||||
.init_tx_chan = dwmac4_dma_init_tx_chan,
|
||||
.axi = dwmac4_dma_axi,
|
||||
.dump_regs = dwmac4_dump_dma_regs,
|
||||
.dma_rx_mode = dwmac4_dma_rx_chan_op_mode,
|
||||
.dma_tx_mode = dwmac4_dma_tx_chan_op_mode,
|
||||
.enable_dma_irq = dwmac4_enable_dma_irq,
|
||||
.disable_dma_irq = dwmac4_disable_dma_irq,
|
||||
.start_tx = dwmac4_dma_start_tx,
|
||||
.stop_tx = dwmac4_dma_stop_tx,
|
||||
.start_rx = dwmac4_dma_start_rx,
|
||||
.stop_rx = dwmac4_dma_stop_rx,
|
||||
.dma_interrupt = dwmac4_dma_interrupt,
|
||||
.get_hw_feature = dwmac4_get_hw_feature,
|
||||
.rx_watchdog = dwmac4_rx_watchdog,
|
||||
.set_rx_ring_len = dwmac4_set_rx_ring_len,
|
||||
.set_tx_ring_len = dwmac4_set_tx_ring_len,
|
||||
.set_rx_tail_ptr = dwmac4_set_rx_tail_ptr,
|
||||
.set_tx_tail_ptr = dwmac4_set_tx_tail_ptr,
|
||||
.enable_tso = dwmac4_enable_tso,
|
||||
.qmode = dwmac4_qmode,
|
||||
.set_bfsize = dwmac4_set_bfsize,
|
||||
.enable_sph = dwmac4_enable_sph,
|
||||
};
|
||||
|
||||
const struct stmmac_dma_ops dwmac410_dma_ops = {
|
||||
.reset = dwmac4_dma_reset,
|
||||
.init = dwmac4_dma_init,
|
||||
.init_chan = dwmac410_dma_init_channel,
|
||||
.init_rx_chan = dwmac4_dma_init_rx_chan,
|
||||
.init_tx_chan = dwmac4_dma_init_tx_chan,
|
||||
.axi = dwmac4_dma_axi,
|
||||
.dump_regs = dwmac4_dump_dma_regs,
|
||||
.dma_rx_mode = dwmac4_dma_rx_chan_op_mode,
|
||||
.dma_tx_mode = dwmac4_dma_tx_chan_op_mode,
|
||||
.enable_dma_irq = dwmac410_enable_dma_irq,
|
||||
.disable_dma_irq = dwmac4_disable_dma_irq,
|
||||
.start_tx = dwmac4_dma_start_tx,
|
||||
.stop_tx = dwmac4_dma_stop_tx,
|
||||
.start_rx = dwmac4_dma_start_rx,
|
||||
.stop_rx = dwmac4_dma_stop_rx,
|
||||
.dma_interrupt = dwmac4_dma_interrupt,
|
||||
.get_hw_feature = dwmac4_get_hw_feature,
|
||||
.rx_watchdog = dwmac4_rx_watchdog,
|
||||
.set_rx_ring_len = dwmac4_set_rx_ring_len,
|
||||
.set_tx_ring_len = dwmac4_set_tx_ring_len,
|
||||
.set_rx_tail_ptr = dwmac4_set_rx_tail_ptr,
|
||||
.set_tx_tail_ptr = dwmac4_set_tx_tail_ptr,
|
||||
.enable_tso = dwmac4_enable_tso,
|
||||
.qmode = dwmac4_qmode,
|
||||
.set_bfsize = dwmac4_set_bfsize,
|
||||
.enable_sph = dwmac4_enable_sph,
|
||||
.enable_tbs = dwmac4_enable_tbs,
|
||||
};
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* DWMAC4 DMA Header file.
|
||||
*
|
||||
* Copyright (C) 2007-2015 STMicroelectronics Ltd
|
||||
*
|
||||
* Author: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
*/
|
||||
|
||||
#ifndef __DWMAC4_DMA_H__
|
||||
#define __DWMAC4_DMA_H__
|
||||
|
||||
/* Define the max channel number used for tx (also rx).
|
||||
* dwmac4 accepts up to 8 channels for TX (and also 8 channels for RX
|
||||
*/
|
||||
#define DMA_CHANNEL_NB_MAX 1
|
||||
|
||||
#define DMA_BUS_MODE 0x00001000
|
||||
#define DMA_SYS_BUS_MODE 0x00001004
|
||||
#define DMA_STATUS 0x00001008
|
||||
#define DMA_DEBUG_STATUS_0 0x0000100c
|
||||
#define DMA_DEBUG_STATUS_1 0x00001010
|
||||
#define DMA_DEBUG_STATUS_2 0x00001014
|
||||
#define DMA_AXI_BUS_MODE 0x00001028
|
||||
#define DMA_TBS_CTRL 0x00001050
|
||||
|
||||
/* DMA Bus Mode bitmap */
|
||||
#define DMA_BUS_MODE_DCHE BIT(19)
|
||||
#define DMA_BUS_MODE_INTM_MASK GENMASK(17, 16)
|
||||
#define DMA_BUS_MODE_INTM_SHIFT 16
|
||||
#define DMA_BUS_MODE_INTM_MODE1 0x1
|
||||
#define DMA_BUS_MODE_SFT_RESET BIT(0)
|
||||
|
||||
/* DMA SYS Bus Mode bitmap */
|
||||
#define DMA_BUS_MODE_SPH BIT(24)
|
||||
#define DMA_BUS_MODE_PBL BIT(16)
|
||||
#define DMA_BUS_MODE_PBL_SHIFT 16
|
||||
#define DMA_BUS_MODE_RPBL_SHIFT 16
|
||||
#define DMA_BUS_MODE_MB BIT(14)
|
||||
#define DMA_BUS_MODE_FB BIT(0)
|
||||
|
||||
/* DMA Interrupt top status */
|
||||
#define DMA_STATUS_MAC BIT(17)
|
||||
#define DMA_STATUS_MTL BIT(16)
|
||||
#define DMA_STATUS_CHAN7 BIT(7)
|
||||
#define DMA_STATUS_CHAN6 BIT(6)
|
||||
#define DMA_STATUS_CHAN5 BIT(5)
|
||||
#define DMA_STATUS_CHAN4 BIT(4)
|
||||
#define DMA_STATUS_CHAN3 BIT(3)
|
||||
#define DMA_STATUS_CHAN2 BIT(2)
|
||||
#define DMA_STATUS_CHAN1 BIT(1)
|
||||
#define DMA_STATUS_CHAN0 BIT(0)
|
||||
|
||||
/* DMA debug status bitmap */
|
||||
#define DMA_DEBUG_STATUS_TS_MASK 0xf
|
||||
#define DMA_DEBUG_STATUS_RS_MASK 0xf
|
||||
|
||||
/* DMA AXI bitmap */
|
||||
#define DMA_AXI_EN_LPI BIT(31)
|
||||
#define DMA_AXI_LPI_XIT_FRM BIT(30)
|
||||
#define DMA_AXI_WR_OSR_LMT GENMASK(27, 24)
|
||||
#define DMA_AXI_WR_OSR_LMT_SHIFT 24
|
||||
#define DMA_AXI_RD_OSR_LMT GENMASK(19, 16)
|
||||
#define DMA_AXI_RD_OSR_LMT_SHIFT 16
|
||||
|
||||
#define DMA_AXI_OSR_MAX 0xf
|
||||
#define DMA_AXI_MAX_OSR_LIMIT ((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \
|
||||
(DMA_AXI_OSR_MAX << DMA_AXI_RD_OSR_LMT_SHIFT))
|
||||
|
||||
#define DMA_SYS_BUS_MB BIT(14)
|
||||
#define DMA_AXI_1KBBE BIT(13)
|
||||
#define DMA_SYS_BUS_AAL BIT(12)
|
||||
#define DMA_SYS_BUS_EAME BIT(11)
|
||||
#define DMA_AXI_BLEN256 BIT(7)
|
||||
#define DMA_AXI_BLEN128 BIT(6)
|
||||
#define DMA_AXI_BLEN64 BIT(5)
|
||||
#define DMA_AXI_BLEN32 BIT(4)
|
||||
#define DMA_AXI_BLEN16 BIT(3)
|
||||
#define DMA_AXI_BLEN8 BIT(2)
|
||||
#define DMA_AXI_BLEN4 BIT(1)
|
||||
#define DMA_SYS_BUS_FB BIT(0)
|
||||
|
||||
#define DMA_BURST_LEN_DEFAULT (DMA_AXI_BLEN256 | DMA_AXI_BLEN128 | \
|
||||
DMA_AXI_BLEN64 | DMA_AXI_BLEN32 | \
|
||||
DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | \
|
||||
DMA_AXI_BLEN4)
|
||||
|
||||
#define DMA_AXI_BURST_LEN_MASK 0x000000FE
|
||||
|
||||
/* DMA TBS Control */
|
||||
#define DMA_TBS_FTOS GENMASK(31, 8)
|
||||
#define DMA_TBS_FTOV BIT(0)
|
||||
#define DMA_TBS_DEF_FTOS (DMA_TBS_FTOS | DMA_TBS_FTOV)
|
||||
|
||||
/* Following DMA defines are channel-oriented */
|
||||
#define DMA_CHAN_BASE_ADDR 0x00001100
|
||||
#define DMA_CHAN_BASE_OFFSET 0x80
|
||||
|
||||
static inline u32 dma_chanx_base_addr(const struct dwmac4_addrs *addrs,
|
||||
const u32 x)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
if (addrs)
|
||||
addr = addrs->dma_chan + (x * addrs->dma_chan_offset);
|
||||
else
|
||||
addr = DMA_CHAN_BASE_ADDR + (x * DMA_CHAN_BASE_OFFSET);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
#define DMA_CHAN_REG_NUMBER 17
|
||||
|
||||
#define DMA_CHAN_CONTROL(addrs, x) dma_chanx_base_addr(addrs, x)
|
||||
#define DMA_CHAN_TX_CONTROL(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x4)
|
||||
#define DMA_CHAN_RX_CONTROL(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x8)
|
||||
#define DMA_CHAN_TX_BASE_ADDR_HI(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x10)
|
||||
#define DMA_CHAN_TX_BASE_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x14)
|
||||
#define DMA_CHAN_RX_BASE_ADDR_HI(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x18)
|
||||
#define DMA_CHAN_RX_BASE_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x1c)
|
||||
#define DMA_CHAN_TX_END_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x20)
|
||||
#define DMA_CHAN_RX_END_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x28)
|
||||
#define DMA_CHAN_TX_RING_LEN(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x2c)
|
||||
#define DMA_CHAN_RX_RING_LEN(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x30)
|
||||
#define DMA_CHAN_INTR_ENA(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x34)
|
||||
#define DMA_CHAN_RX_WATCHDOG(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x38)
|
||||
#define DMA_CHAN_SLOT_CTRL_STATUS(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x3c)
|
||||
#define DMA_CHAN_CUR_TX_DESC(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x44)
|
||||
#define DMA_CHAN_CUR_RX_DESC(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x4c)
|
||||
#define DMA_CHAN_CUR_TX_BUF_ADDR_HI(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x50)
|
||||
#define DMA_CHAN_CUR_TX_BUF_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x54)
|
||||
#define DMA_CHAN_CUR_RX_BUF_ADDR_HI(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x58)
|
||||
#define DMA_CHAN_CUR_RX_BUF_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x5c)
|
||||
#define DMA_CHAN_STATUS(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x60)
|
||||
|
||||
/* DMA Control X */
|
||||
#define DMA_CONTROL_SPH BIT(24)
|
||||
#define DMA_CONTROL_MSS_MASK GENMASK(13, 0)
|
||||
|
||||
/* DMA Tx Channel X Control register defines */
|
||||
#define DMA_CONTROL_EDSE BIT(28)
|
||||
#define DMA_CONTROL_TSE BIT(12)
|
||||
#define DMA_CONTROL_OSP BIT(4)
|
||||
#define DMA_CONTROL_ST BIT(0)
|
||||
|
||||
/* DMA Rx Channel X Control register defines */
|
||||
#define DMA_CONTROL_SR BIT(0)
|
||||
#define DMA_RBSZ_MASK GENMASK(14, 1)
|
||||
#define DMA_RBSZ_SHIFT 1
|
||||
|
||||
/* Interrupt status per channel */
|
||||
#define DMA_CHAN_STATUS_REB GENMASK(21, 19)
|
||||
#define DMA_CHAN_STATUS_REB_SHIFT 19
|
||||
#define DMA_CHAN_STATUS_TEB GENMASK(18, 16)
|
||||
#define DMA_CHAN_STATUS_TEB_SHIFT 16
|
||||
#define DMA_CHAN_STATUS_NIS BIT(15)
|
||||
#define DMA_CHAN_STATUS_AIS BIT(14)
|
||||
#define DMA_CHAN_STATUS_CDE BIT(13)
|
||||
#define DMA_CHAN_STATUS_FBE BIT(12)
|
||||
#define DMA_CHAN_STATUS_ERI BIT(11)
|
||||
#define DMA_CHAN_STATUS_ETI BIT(10)
|
||||
#define DMA_CHAN_STATUS_RWT BIT(9)
|
||||
#define DMA_CHAN_STATUS_RPS BIT(8)
|
||||
#define DMA_CHAN_STATUS_RBU BIT(7)
|
||||
#define DMA_CHAN_STATUS_RI BIT(6)
|
||||
#define DMA_CHAN_STATUS_TBU BIT(2)
|
||||
#define DMA_CHAN_STATUS_TPS BIT(1)
|
||||
#define DMA_CHAN_STATUS_TI BIT(0)
|
||||
|
||||
#define DMA_CHAN_STATUS_MSK_COMMON (DMA_CHAN_STATUS_NIS | \
|
||||
DMA_CHAN_STATUS_AIS | \
|
||||
DMA_CHAN_STATUS_CDE | \
|
||||
DMA_CHAN_STATUS_FBE)
|
||||
|
||||
#define DMA_CHAN_STATUS_MSK_RX (DMA_CHAN_STATUS_REB | \
|
||||
DMA_CHAN_STATUS_ERI | \
|
||||
DMA_CHAN_STATUS_RWT | \
|
||||
DMA_CHAN_STATUS_RPS | \
|
||||
DMA_CHAN_STATUS_RBU | \
|
||||
DMA_CHAN_STATUS_RI | \
|
||||
DMA_CHAN_STATUS_MSK_COMMON)
|
||||
|
||||
#define DMA_CHAN_STATUS_MSK_TX (DMA_CHAN_STATUS_ETI | \
|
||||
DMA_CHAN_STATUS_TBU | \
|
||||
DMA_CHAN_STATUS_TPS | \
|
||||
DMA_CHAN_STATUS_TI | \
|
||||
DMA_CHAN_STATUS_MSK_COMMON)
|
||||
|
||||
/* Interrupt enable bits per channel */
|
||||
#define DMA_CHAN_INTR_ENA_NIE BIT(16)
|
||||
#define DMA_CHAN_INTR_ENA_AIE BIT(15)
|
||||
#define DMA_CHAN_INTR_ENA_NIE_4_10 BIT(15)
|
||||
#define DMA_CHAN_INTR_ENA_AIE_4_10 BIT(14)
|
||||
#define DMA_CHAN_INTR_ENA_CDE BIT(13)
|
||||
#define DMA_CHAN_INTR_ENA_FBE BIT(12)
|
||||
#define DMA_CHAN_INTR_ENA_ERE BIT(11)
|
||||
#define DMA_CHAN_INTR_ENA_ETE BIT(10)
|
||||
#define DMA_CHAN_INTR_ENA_RWE BIT(9)
|
||||
#define DMA_CHAN_INTR_ENA_RSE BIT(8)
|
||||
#define DMA_CHAN_INTR_ENA_RBUE BIT(7)
|
||||
#define DMA_CHAN_INTR_ENA_RIE BIT(6)
|
||||
#define DMA_CHAN_INTR_ENA_TBUE BIT(2)
|
||||
#define DMA_CHAN_INTR_ENA_TSE BIT(1)
|
||||
#define DMA_CHAN_INTR_ENA_TIE BIT(0)
|
||||
|
||||
#define DMA_CHAN_INTR_NORMAL (DMA_CHAN_INTR_ENA_NIE | \
|
||||
DMA_CHAN_INTR_ENA_RIE | \
|
||||
DMA_CHAN_INTR_ENA_TIE)
|
||||
|
||||
#define DMA_CHAN_INTR_ABNORMAL (DMA_CHAN_INTR_ENA_AIE | \
|
||||
DMA_CHAN_INTR_ENA_FBE)
|
||||
/* DMA default interrupt mask for 4.00 */
|
||||
#define DMA_CHAN_INTR_DEFAULT_MASK (DMA_CHAN_INTR_NORMAL | \
|
||||
DMA_CHAN_INTR_ABNORMAL)
|
||||
#define DMA_CHAN_INTR_DEFAULT_RX (DMA_CHAN_INTR_ENA_RIE)
|
||||
#define DMA_CHAN_INTR_DEFAULT_TX (DMA_CHAN_INTR_ENA_TIE)
|
||||
|
||||
#define DMA_CHAN_INTR_NORMAL_4_10 (DMA_CHAN_INTR_ENA_NIE_4_10 | \
|
||||
DMA_CHAN_INTR_ENA_RIE | \
|
||||
DMA_CHAN_INTR_ENA_TIE)
|
||||
|
||||
#define DMA_CHAN_INTR_ABNORMAL_4_10 (DMA_CHAN_INTR_ENA_AIE_4_10 | \
|
||||
DMA_CHAN_INTR_ENA_FBE)
|
||||
/* DMA default interrupt mask for 4.10a */
|
||||
#define DMA_CHAN_INTR_DEFAULT_MASK_4_10 (DMA_CHAN_INTR_NORMAL_4_10 | \
|
||||
DMA_CHAN_INTR_ABNORMAL_4_10)
|
||||
#define DMA_CHAN_INTR_DEFAULT_RX_4_10 (DMA_CHAN_INTR_ENA_RIE)
|
||||
#define DMA_CHAN_INTR_DEFAULT_TX_4_10 (DMA_CHAN_INTR_ENA_TIE)
|
||||
|
||||
/* channel 0 specific fields */
|
||||
#define DMA_CHAN0_DBG_STAT_TPS GENMASK(15, 12)
|
||||
#define DMA_CHAN0_DBG_STAT_TPS_SHIFT 12
|
||||
#define DMA_CHAN0_DBG_STAT_RPS GENMASK(11, 8)
|
||||
#define DMA_CHAN0_DBG_STAT_RPS_SHIFT 8
|
||||
|
||||
int dwmac4_dma_reset(void __iomem *ioaddr);
|
||||
void dwmac4_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void dwmac410_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void dwmac4_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void dwmac410_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void dwmac4_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void dwmac4_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void dwmac4_dma_start_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void dwmac4_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 chan, u32 dir);
|
||||
void dwmac4_set_rx_ring_len(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 len, u32 chan);
|
||||
void dwmac4_set_tx_ring_len(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 len, u32 chan);
|
||||
void dwmac4_set_rx_tail_ptr(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 tail_ptr, u32 chan);
|
||||
void dwmac4_set_tx_tail_ptr(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 tail_ptr, u32 chan);
|
||||
|
||||
#endif /* __DWMAC4_DMA_H__ */
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2007-2015 STMicroelectronics Ltd
|
||||
*
|
||||
* Author: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/delay.h>
|
||||
#include "common-6.12-ethercat.h"
|
||||
#include "dwmac4_dma-6.12-ethercat.h"
|
||||
#include "dwmac4-6.12-ethercat.h"
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
|
||||
int dwmac4_dma_reset(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_BUS_MODE);
|
||||
|
||||
/* DMA SW reset */
|
||||
value |= DMA_BUS_MODE_SFT_RESET;
|
||||
writel(value, ioaddr + DMA_BUS_MODE);
|
||||
|
||||
return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
|
||||
!(value & DMA_BUS_MODE_SFT_RESET),
|
||||
10000, 1000000);
|
||||
}
|
||||
|
||||
void dwmac4_set_rx_tail_ptr(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 tail_ptr, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
writel(tail_ptr, ioaddr + DMA_CHAN_RX_END_ADDR(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_set_tx_tail_ptr(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 tail_ptr, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
writel(tail_ptr, ioaddr + DMA_CHAN_TX_END_ADDR(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value |= DMA_CONTROL_ST;
|
||||
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value = readl(ioaddr + GMAC_CONFIG);
|
||||
value |= GMAC_CONFIG_TE;
|
||||
writel(value, ioaddr + GMAC_CONFIG);
|
||||
}
|
||||
|
||||
void dwmac4_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value &= ~DMA_CONTROL_ST;
|
||||
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_dma_start_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value |= DMA_CONTROL_SR;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value = readl(ioaddr + GMAC_CONFIG);
|
||||
value |= GMAC_CONFIG_RE;
|
||||
writel(value, ioaddr + GMAC_CONFIG);
|
||||
}
|
||||
|
||||
void dwmac4_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value &= ~DMA_CONTROL_SR;
|
||||
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_set_tx_ring_len(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 len, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
writel(len, ioaddr + DMA_CHAN_TX_RING_LEN(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_set_rx_ring_len(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 len, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
|
||||
if (rx)
|
||||
value |= DMA_CHAN_INTR_DEFAULT_RX;
|
||||
if (tx)
|
||||
value |= DMA_CHAN_INTR_DEFAULT_TX;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac410_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
|
||||
if (rx)
|
||||
value |= DMA_CHAN_INTR_DEFAULT_RX_4_10;
|
||||
if (tx)
|
||||
value |= DMA_CHAN_INTR_DEFAULT_TX_4_10;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
|
||||
if (rx)
|
||||
value &= ~DMA_CHAN_INTR_DEFAULT_RX;
|
||||
if (tx)
|
||||
value &= ~DMA_CHAN_INTR_DEFAULT_TX;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac410_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
|
||||
if (rx)
|
||||
value &= ~DMA_CHAN_INTR_DEFAULT_RX_4_10;
|
||||
if (tx)
|
||||
value &= ~DMA_CHAN_INTR_DEFAULT_TX_4_10;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 chan, u32 dir)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan));
|
||||
u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);
|
||||
int ret = 0;
|
||||
|
||||
if (dir == DMA_DIR_RX)
|
||||
intr_status &= DMA_CHAN_STATUS_MSK_RX;
|
||||
else if (dir == DMA_DIR_TX)
|
||||
intr_status &= DMA_CHAN_STATUS_MSK_TX;
|
||||
|
||||
/* ABNORMAL interrupts */
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_AIS)) {
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_RBU))
|
||||
x->rx_buf_unav_irq++;
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_RPS))
|
||||
x->rx_process_stopped_irq++;
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_RWT))
|
||||
x->rx_watchdog_irq++;
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_ETI))
|
||||
x->tx_early_irq++;
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_TPS)) {
|
||||
x->tx_process_stopped_irq++;
|
||||
ret = tx_hard_error;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_FBE)) {
|
||||
x->fatal_bus_error_irq++;
|
||||
ret = tx_hard_error;
|
||||
}
|
||||
}
|
||||
/* TX/RX NORMAL interrupts */
|
||||
if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
|
||||
u64_stats_update_begin(&stats->syncp);
|
||||
u64_stats_inc(&stats->rx_normal_irq_n[chan]);
|
||||
u64_stats_update_end(&stats->syncp);
|
||||
ret |= handle_rx;
|
||||
}
|
||||
if (likely(intr_status & DMA_CHAN_STATUS_TI)) {
|
||||
u64_stats_update_begin(&stats->syncp);
|
||||
u64_stats_inc(&stats->tx_normal_irq_n[chan]);
|
||||
u64_stats_update_end(&stats->syncp);
|
||||
ret |= handle_tx;
|
||||
}
|
||||
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_TBU))
|
||||
ret |= handle_tx;
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
|
||||
x->rx_early_irq++;
|
||||
|
||||
writel(intr_status & intr_en,
|
||||
ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void stmmac_dwmac4_set_mac_addr(void __iomem *ioaddr, const u8 addr[6],
|
||||
unsigned int high, unsigned int low)
|
||||
{
|
||||
unsigned long data;
|
||||
|
||||
data = (addr[5] << 8) | addr[4];
|
||||
/* For MAC Addr registers se have to set the Address Enable (AE)
|
||||
* bit that has no effect on the High Reg 0 where the bit 31 (MO)
|
||||
* is RO.
|
||||
*/
|
||||
data |= (STMMAC_CHAN0 << GMAC_HI_DCS_SHIFT);
|
||||
writel(data | GMAC_HI_REG_AE, ioaddr + high);
|
||||
data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
|
||||
writel(data, ioaddr + low);
|
||||
}
|
||||
|
||||
/* Enable disable MAC RX/TX */
|
||||
void stmmac_dwmac4_set_mac(void __iomem *ioaddr, bool enable)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_CONFIG);
|
||||
u32 old_val = value;
|
||||
|
||||
if (enable)
|
||||
value |= GMAC_CONFIG_RE | GMAC_CONFIG_TE;
|
||||
else
|
||||
value &= ~(GMAC_CONFIG_TE | GMAC_CONFIG_RE);
|
||||
|
||||
if (value != old_val)
|
||||
writel(value, ioaddr + GMAC_CONFIG);
|
||||
}
|
||||
|
||||
void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int high, unsigned int low)
|
||||
{
|
||||
unsigned int hi_addr, lo_addr;
|
||||
|
||||
/* Read the MAC address from the hardware */
|
||||
hi_addr = readl(ioaddr + high);
|
||||
lo_addr = readl(ioaddr + low);
|
||||
|
||||
/* Extract the MAC address from the high and low words */
|
||||
addr[0] = lo_addr & 0xff;
|
||||
addr[1] = (lo_addr >> 8) & 0xff;
|
||||
addr[2] = (lo_addr >> 16) & 0xff;
|
||||
addr[3] = (lo_addr >> 24) & 0xff;
|
||||
addr[4] = hi_addr & 0xff;
|
||||
addr[5] = (hi_addr >> 8) & 0xff;
|
||||
}
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2007-2015 STMicroelectronics Ltd
|
||||
*
|
||||
* Author: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/delay.h>
|
||||
#include "common.h"
|
||||
#include "dwmac4_dma.h"
|
||||
#include "dwmac4.h"
|
||||
#include "stmmac.h"
|
||||
|
||||
int dwmac4_dma_reset(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_BUS_MODE);
|
||||
|
||||
/* DMA SW reset */
|
||||
value |= DMA_BUS_MODE_SFT_RESET;
|
||||
writel(value, ioaddr + DMA_BUS_MODE);
|
||||
|
||||
return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
|
||||
!(value & DMA_BUS_MODE_SFT_RESET),
|
||||
10000, 1000000);
|
||||
}
|
||||
|
||||
void dwmac4_set_rx_tail_ptr(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 tail_ptr, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
writel(tail_ptr, ioaddr + DMA_CHAN_RX_END_ADDR(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_set_tx_tail_ptr(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 tail_ptr, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
writel(tail_ptr, ioaddr + DMA_CHAN_TX_END_ADDR(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value |= DMA_CONTROL_ST;
|
||||
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value = readl(ioaddr + GMAC_CONFIG);
|
||||
value |= GMAC_CONFIG_TE;
|
||||
writel(value, ioaddr + GMAC_CONFIG);
|
||||
}
|
||||
|
||||
void dwmac4_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value &= ~DMA_CONTROL_ST;
|
||||
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_dma_start_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value |= DMA_CONTROL_SR;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value = readl(ioaddr + GMAC_CONFIG);
|
||||
value |= GMAC_CONFIG_RE;
|
||||
writel(value, ioaddr + GMAC_CONFIG);
|
||||
}
|
||||
|
||||
void dwmac4_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
|
||||
value &= ~DMA_CONTROL_SR;
|
||||
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_set_tx_ring_len(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 len, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
writel(len, ioaddr + DMA_CHAN_TX_RING_LEN(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_set_rx_ring_len(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 len, u32 chan)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
|
||||
writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
|
||||
if (rx)
|
||||
value |= DMA_CHAN_INTR_DEFAULT_RX;
|
||||
if (tx)
|
||||
value |= DMA_CHAN_INTR_DEFAULT_TX;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac410_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
|
||||
if (rx)
|
||||
value |= DMA_CHAN_INTR_DEFAULT_RX_4_10;
|
||||
if (tx)
|
||||
value |= DMA_CHAN_INTR_DEFAULT_TX_4_10;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac4_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
|
||||
if (rx)
|
||||
value &= ~DMA_CHAN_INTR_DEFAULT_RX;
|
||||
if (tx)
|
||||
value &= ~DMA_CHAN_INTR_DEFAULT_TX;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
void dwmac410_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
|
||||
if (rx)
|
||||
value &= ~DMA_CHAN_INTR_DEFAULT_RX_4_10;
|
||||
if (tx)
|
||||
value &= ~DMA_CHAN_INTR_DEFAULT_TX_4_10;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
}
|
||||
|
||||
int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 chan, u32 dir)
|
||||
{
|
||||
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
|
||||
u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan));
|
||||
u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
|
||||
struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);
|
||||
int ret = 0;
|
||||
|
||||
if (dir == DMA_DIR_RX)
|
||||
intr_status &= DMA_CHAN_STATUS_MSK_RX;
|
||||
else if (dir == DMA_DIR_TX)
|
||||
intr_status &= DMA_CHAN_STATUS_MSK_TX;
|
||||
|
||||
/* ABNORMAL interrupts */
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_AIS)) {
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_RBU))
|
||||
x->rx_buf_unav_irq++;
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_RPS))
|
||||
x->rx_process_stopped_irq++;
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_RWT))
|
||||
x->rx_watchdog_irq++;
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_ETI))
|
||||
x->tx_early_irq++;
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_TPS)) {
|
||||
x->tx_process_stopped_irq++;
|
||||
ret = tx_hard_error;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_FBE)) {
|
||||
x->fatal_bus_error_irq++;
|
||||
ret = tx_hard_error;
|
||||
}
|
||||
}
|
||||
/* TX/RX NORMAL interrupts */
|
||||
if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
|
||||
u64_stats_update_begin(&stats->syncp);
|
||||
u64_stats_inc(&stats->rx_normal_irq_n[chan]);
|
||||
u64_stats_update_end(&stats->syncp);
|
||||
ret |= handle_rx;
|
||||
}
|
||||
if (likely(intr_status & DMA_CHAN_STATUS_TI)) {
|
||||
u64_stats_update_begin(&stats->syncp);
|
||||
u64_stats_inc(&stats->tx_normal_irq_n[chan]);
|
||||
u64_stats_update_end(&stats->syncp);
|
||||
ret |= handle_tx;
|
||||
}
|
||||
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_TBU))
|
||||
ret |= handle_tx;
|
||||
if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
|
||||
x->rx_early_irq++;
|
||||
|
||||
writel(intr_status & intr_en,
|
||||
ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void stmmac_dwmac4_set_mac_addr(void __iomem *ioaddr, const u8 addr[6],
|
||||
unsigned int high, unsigned int low)
|
||||
{
|
||||
unsigned long data;
|
||||
|
||||
data = (addr[5] << 8) | addr[4];
|
||||
/* For MAC Addr registers se have to set the Address Enable (AE)
|
||||
* bit that has no effect on the High Reg 0 where the bit 31 (MO)
|
||||
* is RO.
|
||||
*/
|
||||
data |= (STMMAC_CHAN0 << GMAC_HI_DCS_SHIFT);
|
||||
writel(data | GMAC_HI_REG_AE, ioaddr + high);
|
||||
data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
|
||||
writel(data, ioaddr + low);
|
||||
}
|
||||
|
||||
/* Enable disable MAC RX/TX */
|
||||
void stmmac_dwmac4_set_mac(void __iomem *ioaddr, bool enable)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_CONFIG);
|
||||
u32 old_val = value;
|
||||
|
||||
if (enable)
|
||||
value |= GMAC_CONFIG_RE | GMAC_CONFIG_TE;
|
||||
else
|
||||
value &= ~(GMAC_CONFIG_TE | GMAC_CONFIG_RE);
|
||||
|
||||
if (value != old_val)
|
||||
writel(value, ioaddr + GMAC_CONFIG);
|
||||
}
|
||||
|
||||
void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int high, unsigned int low)
|
||||
{
|
||||
unsigned int hi_addr, lo_addr;
|
||||
|
||||
/* Read the MAC address from the hardware */
|
||||
hi_addr = readl(ioaddr + high);
|
||||
lo_addr = readl(ioaddr + low);
|
||||
|
||||
/* Extract the MAC address from the high and low words */
|
||||
addr[0] = lo_addr & 0xff;
|
||||
addr[1] = (lo_addr >> 8) & 0xff;
|
||||
addr[2] = (lo_addr >> 16) & 0xff;
|
||||
addr[3] = (lo_addr >> 24) & 0xff;
|
||||
addr[4] = hi_addr & 0xff;
|
||||
addr[5] = (hi_addr >> 8) & 0xff;
|
||||
}
|
||||
|
|
@ -0,0 +1,724 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
// Copyright (c) 2017 Synopsys, Inc. and/or its affiliates.
|
||||
// stmmac Support for 5.xx Ethernet QoS cores
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include "common-6.12-ethercat.h"
|
||||
#include "dwmac4-6.12-ethercat.h"
|
||||
#include "dwmac5-6.12-ethercat.h"
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
#include "stmmac_ptp-6.12-ethercat.h"
|
||||
|
||||
struct dwmac5_error_desc {
|
||||
bool valid;
|
||||
const char *desc;
|
||||
const char *detailed_desc;
|
||||
};
|
||||
|
||||
#define STAT_OFF(field) offsetof(struct stmmac_safety_stats, field)
|
||||
|
||||
static void dwmac5_log_error(struct net_device *ndev, u32 value, bool corr,
|
||||
const char *module_name, const struct dwmac5_error_desc *desc,
|
||||
unsigned long field_offset, struct stmmac_safety_stats *stats)
|
||||
{
|
||||
unsigned long loc, mask;
|
||||
u8 *bptr = (u8 *)stats;
|
||||
unsigned long *ptr;
|
||||
|
||||
ptr = (unsigned long *)(bptr + field_offset);
|
||||
|
||||
mask = value;
|
||||
for_each_set_bit(loc, &mask, 32) {
|
||||
netdev_err(ndev, "Found %s error in %s: '%s: %s'\n", corr ?
|
||||
"correctable" : "uncorrectable", module_name,
|
||||
desc[loc].desc, desc[loc].detailed_desc);
|
||||
|
||||
/* Update counters */
|
||||
ptr[loc]++;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct dwmac5_error_desc dwmac5_mac_errors[32]= {
|
||||
{ true, "ATPES", "Application Transmit Interface Parity Check Error" },
|
||||
{ true, "TPES", "TSO Data Path Parity Check Error" },
|
||||
{ true, "RDPES", "Read Descriptor Parity Check Error" },
|
||||
{ true, "MPES", "MTL Data Path Parity Check Error" },
|
||||
{ true, "MTSPES", "MTL TX Status Data Path Parity Check Error" },
|
||||
{ true, "ARPES", "Application Receive Interface Data Path Parity Check Error" },
|
||||
{ true, "CWPES", "CSR Write Data Path Parity Check Error" },
|
||||
{ true, "ASRPES", "AXI Slave Read Data Path Parity Check Error" },
|
||||
{ true, "TTES", "TX FSM Timeout Error" },
|
||||
{ true, "RTES", "RX FSM Timeout Error" },
|
||||
{ true, "CTES", "CSR FSM Timeout Error" },
|
||||
{ true, "ATES", "APP FSM Timeout Error" },
|
||||
{ true, "PTES", "PTP FSM Timeout Error" },
|
||||
{ true, "T125ES", "TX125 FSM Timeout Error" },
|
||||
{ true, "R125ES", "RX125 FSM Timeout Error" },
|
||||
{ true, "RVCTES", "REV MDC FSM Timeout Error" },
|
||||
{ true, "MSTTES", "Master Read/Write Timeout Error" },
|
||||
{ true, "SLVTES", "Slave Read/Write Timeout Error" },
|
||||
{ true, "ATITES", "Application Timeout on ATI Interface Error" },
|
||||
{ true, "ARITES", "Application Timeout on ARI Interface Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 20 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 21 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 22 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 23 */
|
||||
{ true, "FSMPES", "FSM State Parity Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 25 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 26 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 27 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 28 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 29 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 30 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 31 */
|
||||
};
|
||||
|
||||
static void dwmac5_handle_mac_err(struct net_device *ndev,
|
||||
void __iomem *ioaddr, bool correctable,
|
||||
struct stmmac_safety_stats *stats)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + MAC_DPP_FSM_INT_STATUS);
|
||||
writel(value, ioaddr + MAC_DPP_FSM_INT_STATUS);
|
||||
|
||||
dwmac5_log_error(ndev, value, correctable, "MAC", dwmac5_mac_errors,
|
||||
STAT_OFF(mac_errors), stats);
|
||||
}
|
||||
|
||||
static const struct dwmac5_error_desc dwmac5_mtl_errors[32]= {
|
||||
{ true, "TXCES", "MTL TX Memory Error" },
|
||||
{ true, "TXAMS", "MTL TX Memory Address Mismatch Error" },
|
||||
{ true, "TXUES", "MTL TX Memory Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 3 */
|
||||
{ true, "RXCES", "MTL RX Memory Error" },
|
||||
{ true, "RXAMS", "MTL RX Memory Address Mismatch Error" },
|
||||
{ true, "RXUES", "MTL RX Memory Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 7 */
|
||||
{ true, "ECES", "MTL EST Memory Error" },
|
||||
{ true, "EAMS", "MTL EST Memory Address Mismatch Error" },
|
||||
{ true, "EUES", "MTL EST Memory Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 11 */
|
||||
{ true, "RPCES", "MTL RX Parser Memory Error" },
|
||||
{ true, "RPAMS", "MTL RX Parser Memory Address Mismatch Error" },
|
||||
{ true, "RPUES", "MTL RX Parser Memory Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 15 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 16 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 17 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 18 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 19 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 20 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 21 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 22 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 23 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 24 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 25 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 26 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 27 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 28 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 29 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 30 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 31 */
|
||||
};
|
||||
|
||||
static void dwmac5_handle_mtl_err(struct net_device *ndev,
|
||||
void __iomem *ioaddr, bool correctable,
|
||||
struct stmmac_safety_stats *stats)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + MTL_ECC_INT_STATUS);
|
||||
writel(value, ioaddr + MTL_ECC_INT_STATUS);
|
||||
|
||||
dwmac5_log_error(ndev, value, correctable, "MTL", dwmac5_mtl_errors,
|
||||
STAT_OFF(mtl_errors), stats);
|
||||
}
|
||||
|
||||
static const struct dwmac5_error_desc dwmac5_dma_errors[32]= {
|
||||
{ true, "TCES", "DMA TSO Memory Error" },
|
||||
{ true, "TAMS", "DMA TSO Memory Address Mismatch Error" },
|
||||
{ true, "TUES", "DMA TSO Memory Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 3 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 4 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 5 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 6 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 7 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 8 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 9 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 10 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 11 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 12 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 13 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 14 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 15 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 16 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 17 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 18 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 19 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 20 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 21 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 22 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 23 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 24 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 25 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 26 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 27 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 28 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 29 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 30 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 31 */
|
||||
};
|
||||
|
||||
static void dwmac5_handle_dma_err(struct net_device *ndev,
|
||||
void __iomem *ioaddr, bool correctable,
|
||||
struct stmmac_safety_stats *stats)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + DMA_ECC_INT_STATUS);
|
||||
writel(value, ioaddr + DMA_ECC_INT_STATUS);
|
||||
|
||||
dwmac5_log_error(ndev, value, correctable, "DMA", dwmac5_dma_errors,
|
||||
STAT_OFF(dma_errors), stats);
|
||||
}
|
||||
|
||||
int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
|
||||
struct stmmac_safety_feature_cfg *safety_feat_cfg)
|
||||
{
|
||||
struct stmmac_safety_feature_cfg all_safety_feats = {
|
||||
.tsoee = 1,
|
||||
.mrxpee = 1,
|
||||
.mestee = 1,
|
||||
.mrxee = 1,
|
||||
.mtxee = 1,
|
||||
.epsi = 1,
|
||||
.edpp = 1,
|
||||
.prtyen = 1,
|
||||
.tmouten = 1,
|
||||
};
|
||||
u32 value;
|
||||
|
||||
if (!asp)
|
||||
return -EINVAL;
|
||||
|
||||
if (!safety_feat_cfg)
|
||||
safety_feat_cfg = &all_safety_feats;
|
||||
|
||||
/* 1. Enable Safety Features */
|
||||
value = readl(ioaddr + MTL_ECC_CONTROL);
|
||||
value |= MEEAO; /* MTL ECC Error Addr Status Override */
|
||||
if (safety_feat_cfg->tsoee)
|
||||
value |= TSOEE; /* TSO ECC */
|
||||
if (safety_feat_cfg->mrxpee)
|
||||
value |= MRXPEE; /* MTL RX Parser ECC */
|
||||
if (safety_feat_cfg->mestee)
|
||||
value |= MESTEE; /* MTL EST ECC */
|
||||
if (safety_feat_cfg->mrxee)
|
||||
value |= MRXEE; /* MTL RX FIFO ECC */
|
||||
if (safety_feat_cfg->mtxee)
|
||||
value |= MTXEE; /* MTL TX FIFO ECC */
|
||||
writel(value, ioaddr + MTL_ECC_CONTROL);
|
||||
|
||||
/* 2. Enable MTL Safety Interrupts */
|
||||
value = readl(ioaddr + MTL_ECC_INT_ENABLE);
|
||||
value |= RPCEIE; /* RX Parser Memory Correctable Error */
|
||||
value |= ECEIE; /* EST Memory Correctable Error */
|
||||
value |= RXCEIE; /* RX Memory Correctable Error */
|
||||
value |= TXCEIE; /* TX Memory Correctable Error */
|
||||
writel(value, ioaddr + MTL_ECC_INT_ENABLE);
|
||||
|
||||
/* 3. Enable DMA Safety Interrupts */
|
||||
value = readl(ioaddr + DMA_ECC_INT_ENABLE);
|
||||
value |= TCEIE; /* TSO Memory Correctable Error */
|
||||
writel(value, ioaddr + DMA_ECC_INT_ENABLE);
|
||||
|
||||
/* Only ECC Protection for External Memory feature is selected */
|
||||
if (asp <= 0x1)
|
||||
return 0;
|
||||
|
||||
/* 5. Enable Parity and Timeout for FSM */
|
||||
value = readl(ioaddr + MAC_FSM_CONTROL);
|
||||
if (safety_feat_cfg->prtyen)
|
||||
value |= PRTYEN; /* FSM Parity Feature */
|
||||
if (safety_feat_cfg->tmouten)
|
||||
value |= TMOUTEN; /* FSM Timeout Feature */
|
||||
writel(value, ioaddr + MAC_FSM_CONTROL);
|
||||
|
||||
/* 4. Enable Data Parity Protection */
|
||||
value = readl(ioaddr + MTL_DPP_CONTROL);
|
||||
if (safety_feat_cfg->edpp)
|
||||
value |= EDPP;
|
||||
writel(value, ioaddr + MTL_DPP_CONTROL);
|
||||
|
||||
/*
|
||||
* All the Automotive Safety features are selected without the "Parity
|
||||
* Port Enable for external interface" feature.
|
||||
*/
|
||||
if (asp <= 0x2)
|
||||
return 0;
|
||||
|
||||
if (safety_feat_cfg->epsi)
|
||||
value |= EPSI;
|
||||
writel(value, ioaddr + MTL_DPP_CONTROL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dwmac5_safety_feat_irq_status(struct net_device *ndev,
|
||||
void __iomem *ioaddr, unsigned int asp,
|
||||
struct stmmac_safety_stats *stats)
|
||||
{
|
||||
bool err, corr;
|
||||
u32 mtl, dma;
|
||||
int ret = 0;
|
||||
|
||||
if (!asp)
|
||||
return -EINVAL;
|
||||
|
||||
mtl = readl(ioaddr + MTL_SAFETY_INT_STATUS);
|
||||
dma = readl(ioaddr + DMA_SAFETY_INT_STATUS);
|
||||
|
||||
err = (mtl & MCSIS) || (dma & MCSIS);
|
||||
corr = false;
|
||||
if (err) {
|
||||
dwmac5_handle_mac_err(ndev, ioaddr, corr, stats);
|
||||
ret |= !corr;
|
||||
}
|
||||
|
||||
err = (mtl & (MEUIS | MECIS)) || (dma & (MSUIS | MSCIS));
|
||||
corr = (mtl & MECIS) || (dma & MSCIS);
|
||||
if (err) {
|
||||
dwmac5_handle_mtl_err(ndev, ioaddr, corr, stats);
|
||||
ret |= !corr;
|
||||
}
|
||||
|
||||
err = dma & (DEUIS | DECIS);
|
||||
corr = dma & DECIS;
|
||||
if (err) {
|
||||
dwmac5_handle_dma_err(ndev, ioaddr, corr, stats);
|
||||
ret |= !corr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dwmac5_error {
|
||||
const struct dwmac5_error_desc *desc;
|
||||
} dwmac5_all_errors[] = {
|
||||
{ dwmac5_mac_errors },
|
||||
{ dwmac5_mtl_errors },
|
||||
{ dwmac5_dma_errors },
|
||||
};
|
||||
|
||||
int dwmac5_safety_feat_dump(struct stmmac_safety_stats *stats,
|
||||
int index, unsigned long *count, const char **desc)
|
||||
{
|
||||
int module = index / 32, offset = index % 32;
|
||||
unsigned long *ptr = (unsigned long *)stats;
|
||||
|
||||
if (module >= ARRAY_SIZE(dwmac5_all_errors))
|
||||
return -EINVAL;
|
||||
if (!dwmac5_all_errors[module].desc[offset].valid)
|
||||
return -EINVAL;
|
||||
if (count)
|
||||
*count = *(ptr + index);
|
||||
if (desc)
|
||||
*desc = dwmac5_all_errors[module].desc[offset].desc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwmac5_rxp_disable(void __iomem *ioaddr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(ioaddr + MTL_OPERATION_MODE);
|
||||
val &= ~MTL_FRPE;
|
||||
writel(val, ioaddr + MTL_OPERATION_MODE);
|
||||
|
||||
return readl_poll_timeout(ioaddr + MTL_RXP_CONTROL_STATUS, val,
|
||||
val & RXPI, 1, 10000);
|
||||
}
|
||||
|
||||
static void dwmac5_rxp_enable(void __iomem *ioaddr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(ioaddr + MTL_OPERATION_MODE);
|
||||
val |= MTL_FRPE;
|
||||
writel(val, ioaddr + MTL_OPERATION_MODE);
|
||||
}
|
||||
|
||||
static int dwmac5_rxp_update_single_entry(void __iomem *ioaddr,
|
||||
struct stmmac_tc_entry *entry,
|
||||
int pos)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < (sizeof(entry->val) / sizeof(u32)); i++) {
|
||||
int real_pos = pos * (sizeof(entry->val) / sizeof(u32)) + i;
|
||||
u32 val;
|
||||
|
||||
/* Wait for ready */
|
||||
ret = readl_poll_timeout(ioaddr + MTL_RXP_IACC_CTRL_STATUS,
|
||||
val, !(val & STARTBUSY), 1, 10000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Write data */
|
||||
val = *((u32 *)&entry->val + i);
|
||||
writel(val, ioaddr + MTL_RXP_IACC_DATA);
|
||||
|
||||
/* Write pos */
|
||||
val = real_pos & ADDR;
|
||||
writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
|
||||
|
||||
/* Write OP */
|
||||
val |= WRRDN;
|
||||
writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
|
||||
|
||||
/* Start Write */
|
||||
val |= STARTBUSY;
|
||||
writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
|
||||
|
||||
/* Wait for done */
|
||||
ret = readl_poll_timeout(ioaddr + MTL_RXP_IACC_CTRL_STATUS,
|
||||
val, !(val & STARTBUSY), 1, 10000);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct stmmac_tc_entry *
|
||||
dwmac5_rxp_get_next_entry(struct stmmac_tc_entry *entries, unsigned int count,
|
||||
u32 curr_prio)
|
||||
{
|
||||
struct stmmac_tc_entry *entry;
|
||||
u32 min_prio = ~0x0;
|
||||
int i, min_prio_idx;
|
||||
bool found = false;
|
||||
|
||||
for (i = count - 1; i >= 0; i--) {
|
||||
entry = &entries[i];
|
||||
|
||||
/* Do not update unused entries */
|
||||
if (!entry->in_use)
|
||||
continue;
|
||||
/* Do not update already updated entries (i.e. fragments) */
|
||||
if (entry->in_hw)
|
||||
continue;
|
||||
/* Let last entry be updated last */
|
||||
if (entry->is_last)
|
||||
continue;
|
||||
/* Do not return fragments */
|
||||
if (entry->is_frag)
|
||||
continue;
|
||||
/* Check if we already checked this prio */
|
||||
if (entry->prio < curr_prio)
|
||||
continue;
|
||||
/* Check if this is the minimum prio */
|
||||
if (entry->prio < min_prio) {
|
||||
min_prio = entry->prio;
|
||||
min_prio_idx = i;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
return &entries[min_prio_idx];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
|
||||
unsigned int count)
|
||||
{
|
||||
struct stmmac_tc_entry *entry, *frag;
|
||||
int i, ret, nve = 0;
|
||||
u32 curr_prio = 0;
|
||||
u32 old_val, val;
|
||||
|
||||
/* Force disable RX */
|
||||
old_val = readl(ioaddr + GMAC_CONFIG);
|
||||
val = old_val & ~GMAC_CONFIG_RE;
|
||||
writel(val, ioaddr + GMAC_CONFIG);
|
||||
|
||||
/* Disable RX Parser */
|
||||
ret = dwmac5_rxp_disable(ioaddr);
|
||||
if (ret)
|
||||
goto re_enable;
|
||||
|
||||
/* Set all entries as NOT in HW */
|
||||
for (i = 0; i < count; i++) {
|
||||
entry = &entries[i];
|
||||
entry->in_hw = false;
|
||||
}
|
||||
|
||||
/* Update entries by reverse order */
|
||||
while (1) {
|
||||
entry = dwmac5_rxp_get_next_entry(entries, count, curr_prio);
|
||||
if (!entry)
|
||||
break;
|
||||
|
||||
curr_prio = entry->prio;
|
||||
frag = entry->frag_ptr;
|
||||
|
||||
/* Set special fragment requirements */
|
||||
if (frag) {
|
||||
entry->val.af = 0;
|
||||
entry->val.rf = 0;
|
||||
entry->val.nc = 1;
|
||||
entry->val.ok_index = nve + 2;
|
||||
}
|
||||
|
||||
ret = dwmac5_rxp_update_single_entry(ioaddr, entry, nve);
|
||||
if (ret)
|
||||
goto re_enable;
|
||||
|
||||
entry->table_pos = nve++;
|
||||
entry->in_hw = true;
|
||||
|
||||
if (frag && !frag->in_hw) {
|
||||
ret = dwmac5_rxp_update_single_entry(ioaddr, frag, nve);
|
||||
if (ret)
|
||||
goto re_enable;
|
||||
frag->table_pos = nve++;
|
||||
frag->in_hw = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!nve)
|
||||
goto re_enable;
|
||||
|
||||
/* Update all pass entry */
|
||||
for (i = 0; i < count; i++) {
|
||||
entry = &entries[i];
|
||||
if (!entry->is_last)
|
||||
continue;
|
||||
|
||||
ret = dwmac5_rxp_update_single_entry(ioaddr, entry, nve);
|
||||
if (ret)
|
||||
goto re_enable;
|
||||
|
||||
entry->table_pos = nve++;
|
||||
}
|
||||
|
||||
/* Assume n. of parsable entries == n. of valid entries */
|
||||
val = (nve << 16) & NPE;
|
||||
val |= nve & NVE;
|
||||
writel(val, ioaddr + MTL_RXP_CONTROL_STATUS);
|
||||
|
||||
/* Enable RX Parser */
|
||||
dwmac5_rxp_enable(ioaddr);
|
||||
|
||||
re_enable:
|
||||
/* Re-enable RX */
|
||||
writel(old_val, ioaddr + GMAC_CONFIG);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
|
||||
struct stmmac_pps_cfg *cfg, bool enable,
|
||||
u32 sub_second_inc, u32 systime_flags)
|
||||
{
|
||||
u32 tnsec = readl(ioaddr + MAC_PPSx_TARGET_TIME_NSEC(index));
|
||||
u32 val = readl(ioaddr + MAC_PPS_CONTROL);
|
||||
u64 period;
|
||||
|
||||
if (!cfg->available)
|
||||
return -EINVAL;
|
||||
if (tnsec & TRGTBUSY0)
|
||||
return -EBUSY;
|
||||
if (!sub_second_inc || !systime_flags)
|
||||
return -EINVAL;
|
||||
|
||||
val &= ~PPSx_MASK(index);
|
||||
|
||||
if (!enable) {
|
||||
val |= PPSCMDx(index, 0x5);
|
||||
val |= PPSEN0;
|
||||
writel(val, ioaddr + MAC_PPS_CONTROL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
val |= TRGTMODSELx(index, 0x2);
|
||||
val |= PPSEN0;
|
||||
writel(val, ioaddr + MAC_PPS_CONTROL);
|
||||
|
||||
writel(cfg->start.tv_sec, ioaddr + MAC_PPSx_TARGET_TIME_SEC(index));
|
||||
|
||||
if (!(systime_flags & PTP_TCR_TSCTRLSSR))
|
||||
cfg->start.tv_nsec = (cfg->start.tv_nsec * 1000) / 465;
|
||||
writel(cfg->start.tv_nsec, ioaddr + MAC_PPSx_TARGET_TIME_NSEC(index));
|
||||
|
||||
period = cfg->period.tv_sec * 1000000000;
|
||||
period += cfg->period.tv_nsec;
|
||||
|
||||
do_div(period, sub_second_inc);
|
||||
|
||||
if (period <= 1)
|
||||
return -EINVAL;
|
||||
|
||||
writel(period - 1, ioaddr + MAC_PPSx_INTERVAL(index));
|
||||
|
||||
period >>= 1;
|
||||
if (period <= 1)
|
||||
return -EINVAL;
|
||||
|
||||
writel(period - 1, ioaddr + MAC_PPSx_WIDTH(index));
|
||||
|
||||
/* Finally, activate it */
|
||||
val |= PPSCMDx(index, 0x2);
|
||||
writel(val, ioaddr + MAC_PPS_CONTROL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
||||
u32 num_txq, u32 num_rxq,
|
||||
bool tx_enable, bool pmac_enable)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
if (tx_enable) {
|
||||
cfg->fpe_csr = EFPE;
|
||||
value = readl(ioaddr + GMAC_RXQ_CTRL1);
|
||||
value &= ~GMAC_RXQCTRL_FPRQ;
|
||||
value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
|
||||
writel(value, ioaddr + GMAC_RXQ_CTRL1);
|
||||
} else {
|
||||
cfg->fpe_csr = 0;
|
||||
}
|
||||
writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS);
|
||||
|
||||
value = readl(ioaddr + GMAC_INT_EN);
|
||||
|
||||
if (pmac_enable) {
|
||||
if (!(value & GMAC_INT_FPE_EN)) {
|
||||
/* Dummy read to clear any pending masked interrupts */
|
||||
readl(ioaddr + MAC_FPE_CTRL_STS);
|
||||
|
||||
value |= GMAC_INT_FPE_EN;
|
||||
}
|
||||
} else {
|
||||
value &= ~GMAC_INT_FPE_EN;
|
||||
}
|
||||
|
||||
writel(value, ioaddr + GMAC_INT_EN);
|
||||
}
|
||||
|
||||
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
|
||||
{
|
||||
u32 value;
|
||||
int status;
|
||||
|
||||
status = FPE_EVENT_UNKNOWN;
|
||||
|
||||
/* Reads from the MAC_FPE_CTRL_STS register should only be performed
|
||||
* here, since the status flags of MAC_FPE_CTRL_STS are "clear on read"
|
||||
*/
|
||||
value = readl(ioaddr + MAC_FPE_CTRL_STS);
|
||||
|
||||
if (value & TRSP) {
|
||||
status |= FPE_EVENT_TRSP;
|
||||
netdev_dbg(dev, "FPE: Respond mPacket is transmitted\n");
|
||||
}
|
||||
|
||||
if (value & TVER) {
|
||||
status |= FPE_EVENT_TVER;
|
||||
netdev_dbg(dev, "FPE: Verify mPacket is transmitted\n");
|
||||
}
|
||||
|
||||
if (value & RRSP) {
|
||||
status |= FPE_EVENT_RRSP;
|
||||
netdev_dbg(dev, "FPE: Respond mPacket is received\n");
|
||||
}
|
||||
|
||||
if (value & RVER) {
|
||||
status |= FPE_EVENT_RVER;
|
||||
netdev_dbg(dev, "FPE: Verify mPacket is received\n");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
||||
enum stmmac_mpacket_type type)
|
||||
{
|
||||
u32 value = cfg->fpe_csr;
|
||||
|
||||
if (type == MPACKET_VERIFY)
|
||||
value |= SVER;
|
||||
else if (type == MPACKET_RESPONSE)
|
||||
value |= SRSP;
|
||||
|
||||
writel(value, ioaddr + MAC_FPE_CTRL_STS);
|
||||
}
|
||||
|
||||
int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr)
|
||||
{
|
||||
return FIELD_GET(DWMAC5_ADD_FRAG_SZ, readl(ioaddr + MTL_FPE_CTRL_STS));
|
||||
}
|
||||
|
||||
void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + MTL_FPE_CTRL_STS);
|
||||
writel(u32_replace_bits(value, add_frag_size, DWMAC5_ADD_FRAG_SZ),
|
||||
ioaddr + MTL_FPE_CTRL_STS);
|
||||
}
|
||||
|
||||
#define ALG_ERR_MSG "TX algorithm SP is not suitable for one-to-many mapping"
|
||||
#define WEIGHT_ERR_MSG "TXQ weight %u differs across other TXQs in TC: [%u]"
|
||||
|
||||
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack, u32 pclass)
|
||||
{
|
||||
u32 val, offset, count, queue_weight, preemptible_txqs = 0;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
u32 num_tc = ndev->num_tc;
|
||||
|
||||
if (!pclass)
|
||||
goto update_mapping;
|
||||
|
||||
/* DWMAC CORE4+ can not program TC:TXQ mapping to hardware.
|
||||
*
|
||||
* Synopsys Databook:
|
||||
* "The number of Tx DMA channels is equal to the number of Tx queues,
|
||||
* and is direct one-to-one mapping."
|
||||
*/
|
||||
for (u32 tc = 0; tc < num_tc; tc++) {
|
||||
count = ndev->tc_to_txq[tc].count;
|
||||
offset = ndev->tc_to_txq[tc].offset;
|
||||
|
||||
if (pclass & BIT(tc))
|
||||
preemptible_txqs |= GENMASK(offset + count - 1, offset);
|
||||
|
||||
/* This is 1:1 mapping, go to next TC */
|
||||
if (count == 1)
|
||||
continue;
|
||||
|
||||
if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) {
|
||||
NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
queue_weight = priv->plat->tx_queues_cfg[offset].weight;
|
||||
|
||||
for (u32 i = 1; i < count; i++) {
|
||||
if (priv->plat->tx_queues_cfg[offset + i].weight !=
|
||||
queue_weight) {
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG,
|
||||
queue_weight, tc);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_mapping:
|
||||
val = readl(priv->ioaddr + MTL_FPE_CTRL_STS);
|
||||
writel(u32_replace_bits(val, preemptible_txqs, DWMAC5_PREEMPTION_CLASS),
|
||||
priv->ioaddr + MTL_FPE_CTRL_STS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
|
||||
// Copyright (c) 2017 Synopsys, Inc. and/or its affiliates.
|
||||
// stmmac Support for 5.xx Ethernet QoS cores
|
||||
|
||||
#ifndef __DWMAC5_H__
|
||||
#define __DWMAC5_H__
|
||||
|
||||
#define MAC_DPP_FSM_INT_STATUS 0x00000140
|
||||
#define MAC_AXI_SLV_DPE_ADDR_STATUS 0x00000144
|
||||
#define MAC_FSM_CONTROL 0x00000148
|
||||
#define PRTYEN BIT(1)
|
||||
#define TMOUTEN BIT(0)
|
||||
|
||||
#define MAC_FPE_CTRL_STS 0x00000234
|
||||
#define TRSP BIT(19)
|
||||
#define TVER BIT(18)
|
||||
#define RRSP BIT(17)
|
||||
#define RVER BIT(16)
|
||||
#define SRSP BIT(2)
|
||||
#define SVER BIT(1)
|
||||
#define EFPE BIT(0)
|
||||
|
||||
#define MAC_PPS_CONTROL 0x00000b70
|
||||
#define PPS_MAXIDX(x) ((((x) + 1) * 8) - 1)
|
||||
#define PPS_MINIDX(x) ((x) * 8)
|
||||
#define PPSx_MASK(x) GENMASK(PPS_MAXIDX(x), PPS_MINIDX(x))
|
||||
#define MCGRENx(x) BIT(PPS_MAXIDX(x))
|
||||
#define TRGTMODSELx(x, val) \
|
||||
GENMASK(PPS_MAXIDX(x) - 1, PPS_MAXIDX(x) - 2) & \
|
||||
((val) << (PPS_MAXIDX(x) - 2))
|
||||
#define PPSCMDx(x, val) \
|
||||
GENMASK(PPS_MINIDX(x) + 3, PPS_MINIDX(x)) & \
|
||||
((val) << PPS_MINIDX(x))
|
||||
#define PPSEN0 BIT(4)
|
||||
#define MAC_PPSx_TARGET_TIME_SEC(x) (0x00000b80 + ((x) * 0x10))
|
||||
#define MAC_PPSx_TARGET_TIME_NSEC(x) (0x00000b84 + ((x) * 0x10))
|
||||
#define TRGTBUSY0 BIT(31)
|
||||
#define TTSL0 GENMASK(30, 0)
|
||||
#define MAC_PPSx_INTERVAL(x) (0x00000b88 + ((x) * 0x10))
|
||||
#define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10))
|
||||
|
||||
#define MTL_FPE_CTRL_STS 0x00000c90
|
||||
/* Preemption Classification */
|
||||
#define DWMAC5_PREEMPTION_CLASS GENMASK(15, 8)
|
||||
/* Additional Fragment Size of preempted frames */
|
||||
#define DWMAC5_ADD_FRAG_SZ GENMASK(1, 0)
|
||||
|
||||
#define MTL_RXP_CONTROL_STATUS 0x00000ca0
|
||||
#define RXPI BIT(31)
|
||||
#define NPE GENMASK(23, 16)
|
||||
#define NVE GENMASK(7, 0)
|
||||
#define MTL_RXP_IACC_CTRL_STATUS 0x00000cb0
|
||||
#define STARTBUSY BIT(31)
|
||||
#define RXPEIEC GENMASK(22, 21)
|
||||
#define RXPEIEE BIT(20)
|
||||
#define WRRDN BIT(16)
|
||||
#define ADDR GENMASK(15, 0)
|
||||
#define MTL_RXP_IACC_DATA 0x00000cb4
|
||||
#define MTL_ECC_CONTROL 0x00000cc0
|
||||
#define MEEAO BIT(8)
|
||||
#define TSOEE BIT(4)
|
||||
#define MRXPEE BIT(3)
|
||||
#define MESTEE BIT(2)
|
||||
#define MRXEE BIT(1)
|
||||
#define MTXEE BIT(0)
|
||||
|
||||
#define MTL_SAFETY_INT_STATUS 0x00000cc4
|
||||
#define MCSIS BIT(31)
|
||||
#define MEUIS BIT(1)
|
||||
#define MECIS BIT(0)
|
||||
#define MTL_ECC_INT_ENABLE 0x00000cc8
|
||||
#define RPCEIE BIT(12)
|
||||
#define ECEIE BIT(8)
|
||||
#define RXCEIE BIT(4)
|
||||
#define TXCEIE BIT(0)
|
||||
#define MTL_ECC_INT_STATUS 0x00000ccc
|
||||
#define MTL_DPP_CONTROL 0x00000ce0
|
||||
#define EPSI BIT(2)
|
||||
#define OPE BIT(1)
|
||||
#define EDPP BIT(0)
|
||||
|
||||
#define DMA_SAFETY_INT_STATUS 0x00001080
|
||||
#define MSUIS BIT(29)
|
||||
#define MSCIS BIT(28)
|
||||
#define DEUIS BIT(1)
|
||||
#define DECIS BIT(0)
|
||||
#define DMA_ECC_INT_ENABLE 0x00001084
|
||||
#define TCEIE BIT(0)
|
||||
#define DMA_ECC_INT_STATUS 0x00001088
|
||||
|
||||
/* EQoS version 5.xx VLAN Tag Filter Fail Packets Queuing */
|
||||
#define GMAC_RXQ_CTRL4 0x00000094
|
||||
#define GMAC_RXQCTRL_VFFQ_MASK GENMASK(19, 17)
|
||||
#define GMAC_RXQCTRL_VFFQ_SHIFT 17
|
||||
#define GMAC_RXQCTRL_VFFQE BIT(16)
|
||||
|
||||
#define GMAC_INT_FPE_EN BIT(17)
|
||||
|
||||
int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
|
||||
struct stmmac_safety_feature_cfg *safety_cfg);
|
||||
int dwmac5_safety_feat_irq_status(struct net_device *ndev,
|
||||
void __iomem *ioaddr, unsigned int asp,
|
||||
struct stmmac_safety_stats *stats);
|
||||
int dwmac5_safety_feat_dump(struct stmmac_safety_stats *stats,
|
||||
int index, unsigned long *count, const char **desc);
|
||||
int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
|
||||
unsigned int count);
|
||||
int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
|
||||
struct stmmac_pps_cfg *cfg, bool enable,
|
||||
u32 sub_second_inc, u32 systime_flags);
|
||||
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
||||
u32 num_txq, u32 num_rxq,
|
||||
bool tx_enable, bool pmac_enable);
|
||||
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
|
||||
struct stmmac_fpe_cfg *cfg,
|
||||
enum stmmac_mpacket_type type);
|
||||
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev);
|
||||
int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr);
|
||||
void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size);
|
||||
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack, u32 pclass);
|
||||
|
||||
#endif /* __DWMAC5_H__ */
|
||||
|
|
@ -0,0 +1,724 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
// Copyright (c) 2017 Synopsys, Inc. and/or its affiliates.
|
||||
// stmmac Support for 5.xx Ethernet QoS cores
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include "common.h"
|
||||
#include "dwmac4.h"
|
||||
#include "dwmac5.h"
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_ptp.h"
|
||||
|
||||
struct dwmac5_error_desc {
|
||||
bool valid;
|
||||
const char *desc;
|
||||
const char *detailed_desc;
|
||||
};
|
||||
|
||||
#define STAT_OFF(field) offsetof(struct stmmac_safety_stats, field)
|
||||
|
||||
static void dwmac5_log_error(struct net_device *ndev, u32 value, bool corr,
|
||||
const char *module_name, const struct dwmac5_error_desc *desc,
|
||||
unsigned long field_offset, struct stmmac_safety_stats *stats)
|
||||
{
|
||||
unsigned long loc, mask;
|
||||
u8 *bptr = (u8 *)stats;
|
||||
unsigned long *ptr;
|
||||
|
||||
ptr = (unsigned long *)(bptr + field_offset);
|
||||
|
||||
mask = value;
|
||||
for_each_set_bit(loc, &mask, 32) {
|
||||
netdev_err(ndev, "Found %s error in %s: '%s: %s'\n", corr ?
|
||||
"correctable" : "uncorrectable", module_name,
|
||||
desc[loc].desc, desc[loc].detailed_desc);
|
||||
|
||||
/* Update counters */
|
||||
ptr[loc]++;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct dwmac5_error_desc dwmac5_mac_errors[32]= {
|
||||
{ true, "ATPES", "Application Transmit Interface Parity Check Error" },
|
||||
{ true, "TPES", "TSO Data Path Parity Check Error" },
|
||||
{ true, "RDPES", "Read Descriptor Parity Check Error" },
|
||||
{ true, "MPES", "MTL Data Path Parity Check Error" },
|
||||
{ true, "MTSPES", "MTL TX Status Data Path Parity Check Error" },
|
||||
{ true, "ARPES", "Application Receive Interface Data Path Parity Check Error" },
|
||||
{ true, "CWPES", "CSR Write Data Path Parity Check Error" },
|
||||
{ true, "ASRPES", "AXI Slave Read Data Path Parity Check Error" },
|
||||
{ true, "TTES", "TX FSM Timeout Error" },
|
||||
{ true, "RTES", "RX FSM Timeout Error" },
|
||||
{ true, "CTES", "CSR FSM Timeout Error" },
|
||||
{ true, "ATES", "APP FSM Timeout Error" },
|
||||
{ true, "PTES", "PTP FSM Timeout Error" },
|
||||
{ true, "T125ES", "TX125 FSM Timeout Error" },
|
||||
{ true, "R125ES", "RX125 FSM Timeout Error" },
|
||||
{ true, "RVCTES", "REV MDC FSM Timeout Error" },
|
||||
{ true, "MSTTES", "Master Read/Write Timeout Error" },
|
||||
{ true, "SLVTES", "Slave Read/Write Timeout Error" },
|
||||
{ true, "ATITES", "Application Timeout on ATI Interface Error" },
|
||||
{ true, "ARITES", "Application Timeout on ARI Interface Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 20 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 21 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 22 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 23 */
|
||||
{ true, "FSMPES", "FSM State Parity Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 25 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 26 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 27 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 28 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 29 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 30 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 31 */
|
||||
};
|
||||
|
||||
static void dwmac5_handle_mac_err(struct net_device *ndev,
|
||||
void __iomem *ioaddr, bool correctable,
|
||||
struct stmmac_safety_stats *stats)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + MAC_DPP_FSM_INT_STATUS);
|
||||
writel(value, ioaddr + MAC_DPP_FSM_INT_STATUS);
|
||||
|
||||
dwmac5_log_error(ndev, value, correctable, "MAC", dwmac5_mac_errors,
|
||||
STAT_OFF(mac_errors), stats);
|
||||
}
|
||||
|
||||
static const struct dwmac5_error_desc dwmac5_mtl_errors[32]= {
|
||||
{ true, "TXCES", "MTL TX Memory Error" },
|
||||
{ true, "TXAMS", "MTL TX Memory Address Mismatch Error" },
|
||||
{ true, "TXUES", "MTL TX Memory Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 3 */
|
||||
{ true, "RXCES", "MTL RX Memory Error" },
|
||||
{ true, "RXAMS", "MTL RX Memory Address Mismatch Error" },
|
||||
{ true, "RXUES", "MTL RX Memory Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 7 */
|
||||
{ true, "ECES", "MTL EST Memory Error" },
|
||||
{ true, "EAMS", "MTL EST Memory Address Mismatch Error" },
|
||||
{ true, "EUES", "MTL EST Memory Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 11 */
|
||||
{ true, "RPCES", "MTL RX Parser Memory Error" },
|
||||
{ true, "RPAMS", "MTL RX Parser Memory Address Mismatch Error" },
|
||||
{ true, "RPUES", "MTL RX Parser Memory Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 15 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 16 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 17 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 18 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 19 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 20 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 21 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 22 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 23 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 24 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 25 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 26 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 27 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 28 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 29 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 30 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 31 */
|
||||
};
|
||||
|
||||
static void dwmac5_handle_mtl_err(struct net_device *ndev,
|
||||
void __iomem *ioaddr, bool correctable,
|
||||
struct stmmac_safety_stats *stats)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + MTL_ECC_INT_STATUS);
|
||||
writel(value, ioaddr + MTL_ECC_INT_STATUS);
|
||||
|
||||
dwmac5_log_error(ndev, value, correctable, "MTL", dwmac5_mtl_errors,
|
||||
STAT_OFF(mtl_errors), stats);
|
||||
}
|
||||
|
||||
static const struct dwmac5_error_desc dwmac5_dma_errors[32]= {
|
||||
{ true, "TCES", "DMA TSO Memory Error" },
|
||||
{ true, "TAMS", "DMA TSO Memory Address Mismatch Error" },
|
||||
{ true, "TUES", "DMA TSO Memory Error" },
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 3 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 4 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 5 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 6 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 7 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 8 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 9 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 10 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 11 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 12 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 13 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 14 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 15 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 16 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 17 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 18 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 19 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 20 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 21 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 22 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 23 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 24 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 25 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 26 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 27 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 28 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 29 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 30 */
|
||||
{ false, "UNKNOWN", "Unknown Error" }, /* 31 */
|
||||
};
|
||||
|
||||
static void dwmac5_handle_dma_err(struct net_device *ndev,
|
||||
void __iomem *ioaddr, bool correctable,
|
||||
struct stmmac_safety_stats *stats)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + DMA_ECC_INT_STATUS);
|
||||
writel(value, ioaddr + DMA_ECC_INT_STATUS);
|
||||
|
||||
dwmac5_log_error(ndev, value, correctable, "DMA", dwmac5_dma_errors,
|
||||
STAT_OFF(dma_errors), stats);
|
||||
}
|
||||
|
||||
int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
|
||||
struct stmmac_safety_feature_cfg *safety_feat_cfg)
|
||||
{
|
||||
struct stmmac_safety_feature_cfg all_safety_feats = {
|
||||
.tsoee = 1,
|
||||
.mrxpee = 1,
|
||||
.mestee = 1,
|
||||
.mrxee = 1,
|
||||
.mtxee = 1,
|
||||
.epsi = 1,
|
||||
.edpp = 1,
|
||||
.prtyen = 1,
|
||||
.tmouten = 1,
|
||||
};
|
||||
u32 value;
|
||||
|
||||
if (!asp)
|
||||
return -EINVAL;
|
||||
|
||||
if (!safety_feat_cfg)
|
||||
safety_feat_cfg = &all_safety_feats;
|
||||
|
||||
/* 1. Enable Safety Features */
|
||||
value = readl(ioaddr + MTL_ECC_CONTROL);
|
||||
value |= MEEAO; /* MTL ECC Error Addr Status Override */
|
||||
if (safety_feat_cfg->tsoee)
|
||||
value |= TSOEE; /* TSO ECC */
|
||||
if (safety_feat_cfg->mrxpee)
|
||||
value |= MRXPEE; /* MTL RX Parser ECC */
|
||||
if (safety_feat_cfg->mestee)
|
||||
value |= MESTEE; /* MTL EST ECC */
|
||||
if (safety_feat_cfg->mrxee)
|
||||
value |= MRXEE; /* MTL RX FIFO ECC */
|
||||
if (safety_feat_cfg->mtxee)
|
||||
value |= MTXEE; /* MTL TX FIFO ECC */
|
||||
writel(value, ioaddr + MTL_ECC_CONTROL);
|
||||
|
||||
/* 2. Enable MTL Safety Interrupts */
|
||||
value = readl(ioaddr + MTL_ECC_INT_ENABLE);
|
||||
value |= RPCEIE; /* RX Parser Memory Correctable Error */
|
||||
value |= ECEIE; /* EST Memory Correctable Error */
|
||||
value |= RXCEIE; /* RX Memory Correctable Error */
|
||||
value |= TXCEIE; /* TX Memory Correctable Error */
|
||||
writel(value, ioaddr + MTL_ECC_INT_ENABLE);
|
||||
|
||||
/* 3. Enable DMA Safety Interrupts */
|
||||
value = readl(ioaddr + DMA_ECC_INT_ENABLE);
|
||||
value |= TCEIE; /* TSO Memory Correctable Error */
|
||||
writel(value, ioaddr + DMA_ECC_INT_ENABLE);
|
||||
|
||||
/* Only ECC Protection for External Memory feature is selected */
|
||||
if (asp <= 0x1)
|
||||
return 0;
|
||||
|
||||
/* 5. Enable Parity and Timeout for FSM */
|
||||
value = readl(ioaddr + MAC_FSM_CONTROL);
|
||||
if (safety_feat_cfg->prtyen)
|
||||
value |= PRTYEN; /* FSM Parity Feature */
|
||||
if (safety_feat_cfg->tmouten)
|
||||
value |= TMOUTEN; /* FSM Timeout Feature */
|
||||
writel(value, ioaddr + MAC_FSM_CONTROL);
|
||||
|
||||
/* 4. Enable Data Parity Protection */
|
||||
value = readl(ioaddr + MTL_DPP_CONTROL);
|
||||
if (safety_feat_cfg->edpp)
|
||||
value |= EDPP;
|
||||
writel(value, ioaddr + MTL_DPP_CONTROL);
|
||||
|
||||
/*
|
||||
* All the Automotive Safety features are selected without the "Parity
|
||||
* Port Enable for external interface" feature.
|
||||
*/
|
||||
if (asp <= 0x2)
|
||||
return 0;
|
||||
|
||||
if (safety_feat_cfg->epsi)
|
||||
value |= EPSI;
|
||||
writel(value, ioaddr + MTL_DPP_CONTROL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dwmac5_safety_feat_irq_status(struct net_device *ndev,
|
||||
void __iomem *ioaddr, unsigned int asp,
|
||||
struct stmmac_safety_stats *stats)
|
||||
{
|
||||
bool err, corr;
|
||||
u32 mtl, dma;
|
||||
int ret = 0;
|
||||
|
||||
if (!asp)
|
||||
return -EINVAL;
|
||||
|
||||
mtl = readl(ioaddr + MTL_SAFETY_INT_STATUS);
|
||||
dma = readl(ioaddr + DMA_SAFETY_INT_STATUS);
|
||||
|
||||
err = (mtl & MCSIS) || (dma & MCSIS);
|
||||
corr = false;
|
||||
if (err) {
|
||||
dwmac5_handle_mac_err(ndev, ioaddr, corr, stats);
|
||||
ret |= !corr;
|
||||
}
|
||||
|
||||
err = (mtl & (MEUIS | MECIS)) || (dma & (MSUIS | MSCIS));
|
||||
corr = (mtl & MECIS) || (dma & MSCIS);
|
||||
if (err) {
|
||||
dwmac5_handle_mtl_err(ndev, ioaddr, corr, stats);
|
||||
ret |= !corr;
|
||||
}
|
||||
|
||||
err = dma & (DEUIS | DECIS);
|
||||
corr = dma & DECIS;
|
||||
if (err) {
|
||||
dwmac5_handle_dma_err(ndev, ioaddr, corr, stats);
|
||||
ret |= !corr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dwmac5_error {
|
||||
const struct dwmac5_error_desc *desc;
|
||||
} dwmac5_all_errors[] = {
|
||||
{ dwmac5_mac_errors },
|
||||
{ dwmac5_mtl_errors },
|
||||
{ dwmac5_dma_errors },
|
||||
};
|
||||
|
||||
int dwmac5_safety_feat_dump(struct stmmac_safety_stats *stats,
|
||||
int index, unsigned long *count, const char **desc)
|
||||
{
|
||||
int module = index / 32, offset = index % 32;
|
||||
unsigned long *ptr = (unsigned long *)stats;
|
||||
|
||||
if (module >= ARRAY_SIZE(dwmac5_all_errors))
|
||||
return -EINVAL;
|
||||
if (!dwmac5_all_errors[module].desc[offset].valid)
|
||||
return -EINVAL;
|
||||
if (count)
|
||||
*count = *(ptr + index);
|
||||
if (desc)
|
||||
*desc = dwmac5_all_errors[module].desc[offset].desc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwmac5_rxp_disable(void __iomem *ioaddr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(ioaddr + MTL_OPERATION_MODE);
|
||||
val &= ~MTL_FRPE;
|
||||
writel(val, ioaddr + MTL_OPERATION_MODE);
|
||||
|
||||
return readl_poll_timeout(ioaddr + MTL_RXP_CONTROL_STATUS, val,
|
||||
val & RXPI, 1, 10000);
|
||||
}
|
||||
|
||||
static void dwmac5_rxp_enable(void __iomem *ioaddr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(ioaddr + MTL_OPERATION_MODE);
|
||||
val |= MTL_FRPE;
|
||||
writel(val, ioaddr + MTL_OPERATION_MODE);
|
||||
}
|
||||
|
||||
static int dwmac5_rxp_update_single_entry(void __iomem *ioaddr,
|
||||
struct stmmac_tc_entry *entry,
|
||||
int pos)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < (sizeof(entry->val) / sizeof(u32)); i++) {
|
||||
int real_pos = pos * (sizeof(entry->val) / sizeof(u32)) + i;
|
||||
u32 val;
|
||||
|
||||
/* Wait for ready */
|
||||
ret = readl_poll_timeout(ioaddr + MTL_RXP_IACC_CTRL_STATUS,
|
||||
val, !(val & STARTBUSY), 1, 10000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Write data */
|
||||
val = *((u32 *)&entry->val + i);
|
||||
writel(val, ioaddr + MTL_RXP_IACC_DATA);
|
||||
|
||||
/* Write pos */
|
||||
val = real_pos & ADDR;
|
||||
writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
|
||||
|
||||
/* Write OP */
|
||||
val |= WRRDN;
|
||||
writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
|
||||
|
||||
/* Start Write */
|
||||
val |= STARTBUSY;
|
||||
writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
|
||||
|
||||
/* Wait for done */
|
||||
ret = readl_poll_timeout(ioaddr + MTL_RXP_IACC_CTRL_STATUS,
|
||||
val, !(val & STARTBUSY), 1, 10000);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct stmmac_tc_entry *
|
||||
dwmac5_rxp_get_next_entry(struct stmmac_tc_entry *entries, unsigned int count,
|
||||
u32 curr_prio)
|
||||
{
|
||||
struct stmmac_tc_entry *entry;
|
||||
u32 min_prio = ~0x0;
|
||||
int i, min_prio_idx;
|
||||
bool found = false;
|
||||
|
||||
for (i = count - 1; i >= 0; i--) {
|
||||
entry = &entries[i];
|
||||
|
||||
/* Do not update unused entries */
|
||||
if (!entry->in_use)
|
||||
continue;
|
||||
/* Do not update already updated entries (i.e. fragments) */
|
||||
if (entry->in_hw)
|
||||
continue;
|
||||
/* Let last entry be updated last */
|
||||
if (entry->is_last)
|
||||
continue;
|
||||
/* Do not return fragments */
|
||||
if (entry->is_frag)
|
||||
continue;
|
||||
/* Check if we already checked this prio */
|
||||
if (entry->prio < curr_prio)
|
||||
continue;
|
||||
/* Check if this is the minimum prio */
|
||||
if (entry->prio < min_prio) {
|
||||
min_prio = entry->prio;
|
||||
min_prio_idx = i;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
return &entries[min_prio_idx];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
|
||||
unsigned int count)
|
||||
{
|
||||
struct stmmac_tc_entry *entry, *frag;
|
||||
int i, ret, nve = 0;
|
||||
u32 curr_prio = 0;
|
||||
u32 old_val, val;
|
||||
|
||||
/* Force disable RX */
|
||||
old_val = readl(ioaddr + GMAC_CONFIG);
|
||||
val = old_val & ~GMAC_CONFIG_RE;
|
||||
writel(val, ioaddr + GMAC_CONFIG);
|
||||
|
||||
/* Disable RX Parser */
|
||||
ret = dwmac5_rxp_disable(ioaddr);
|
||||
if (ret)
|
||||
goto re_enable;
|
||||
|
||||
/* Set all entries as NOT in HW */
|
||||
for (i = 0; i < count; i++) {
|
||||
entry = &entries[i];
|
||||
entry->in_hw = false;
|
||||
}
|
||||
|
||||
/* Update entries by reverse order */
|
||||
while (1) {
|
||||
entry = dwmac5_rxp_get_next_entry(entries, count, curr_prio);
|
||||
if (!entry)
|
||||
break;
|
||||
|
||||
curr_prio = entry->prio;
|
||||
frag = entry->frag_ptr;
|
||||
|
||||
/* Set special fragment requirements */
|
||||
if (frag) {
|
||||
entry->val.af = 0;
|
||||
entry->val.rf = 0;
|
||||
entry->val.nc = 1;
|
||||
entry->val.ok_index = nve + 2;
|
||||
}
|
||||
|
||||
ret = dwmac5_rxp_update_single_entry(ioaddr, entry, nve);
|
||||
if (ret)
|
||||
goto re_enable;
|
||||
|
||||
entry->table_pos = nve++;
|
||||
entry->in_hw = true;
|
||||
|
||||
if (frag && !frag->in_hw) {
|
||||
ret = dwmac5_rxp_update_single_entry(ioaddr, frag, nve);
|
||||
if (ret)
|
||||
goto re_enable;
|
||||
frag->table_pos = nve++;
|
||||
frag->in_hw = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!nve)
|
||||
goto re_enable;
|
||||
|
||||
/* Update all pass entry */
|
||||
for (i = 0; i < count; i++) {
|
||||
entry = &entries[i];
|
||||
if (!entry->is_last)
|
||||
continue;
|
||||
|
||||
ret = dwmac5_rxp_update_single_entry(ioaddr, entry, nve);
|
||||
if (ret)
|
||||
goto re_enable;
|
||||
|
||||
entry->table_pos = nve++;
|
||||
}
|
||||
|
||||
/* Assume n. of parsable entries == n. of valid entries */
|
||||
val = (nve << 16) & NPE;
|
||||
val |= nve & NVE;
|
||||
writel(val, ioaddr + MTL_RXP_CONTROL_STATUS);
|
||||
|
||||
/* Enable RX Parser */
|
||||
dwmac5_rxp_enable(ioaddr);
|
||||
|
||||
re_enable:
|
||||
/* Re-enable RX */
|
||||
writel(old_val, ioaddr + GMAC_CONFIG);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
|
||||
struct stmmac_pps_cfg *cfg, bool enable,
|
||||
u32 sub_second_inc, u32 systime_flags)
|
||||
{
|
||||
u32 tnsec = readl(ioaddr + MAC_PPSx_TARGET_TIME_NSEC(index));
|
||||
u32 val = readl(ioaddr + MAC_PPS_CONTROL);
|
||||
u64 period;
|
||||
|
||||
if (!cfg->available)
|
||||
return -EINVAL;
|
||||
if (tnsec & TRGTBUSY0)
|
||||
return -EBUSY;
|
||||
if (!sub_second_inc || !systime_flags)
|
||||
return -EINVAL;
|
||||
|
||||
val &= ~PPSx_MASK(index);
|
||||
|
||||
if (!enable) {
|
||||
val |= PPSCMDx(index, 0x5);
|
||||
val |= PPSEN0;
|
||||
writel(val, ioaddr + MAC_PPS_CONTROL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
val |= TRGTMODSELx(index, 0x2);
|
||||
val |= PPSEN0;
|
||||
writel(val, ioaddr + MAC_PPS_CONTROL);
|
||||
|
||||
writel(cfg->start.tv_sec, ioaddr + MAC_PPSx_TARGET_TIME_SEC(index));
|
||||
|
||||
if (!(systime_flags & PTP_TCR_TSCTRLSSR))
|
||||
cfg->start.tv_nsec = (cfg->start.tv_nsec * 1000) / 465;
|
||||
writel(cfg->start.tv_nsec, ioaddr + MAC_PPSx_TARGET_TIME_NSEC(index));
|
||||
|
||||
period = cfg->period.tv_sec * 1000000000;
|
||||
period += cfg->period.tv_nsec;
|
||||
|
||||
do_div(period, sub_second_inc);
|
||||
|
||||
if (period <= 1)
|
||||
return -EINVAL;
|
||||
|
||||
writel(period - 1, ioaddr + MAC_PPSx_INTERVAL(index));
|
||||
|
||||
period >>= 1;
|
||||
if (period <= 1)
|
||||
return -EINVAL;
|
||||
|
||||
writel(period - 1, ioaddr + MAC_PPSx_WIDTH(index));
|
||||
|
||||
/* Finally, activate it */
|
||||
val |= PPSCMDx(index, 0x2);
|
||||
writel(val, ioaddr + MAC_PPS_CONTROL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
||||
u32 num_txq, u32 num_rxq,
|
||||
bool tx_enable, bool pmac_enable)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
if (tx_enable) {
|
||||
cfg->fpe_csr = EFPE;
|
||||
value = readl(ioaddr + GMAC_RXQ_CTRL1);
|
||||
value &= ~GMAC_RXQCTRL_FPRQ;
|
||||
value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
|
||||
writel(value, ioaddr + GMAC_RXQ_CTRL1);
|
||||
} else {
|
||||
cfg->fpe_csr = 0;
|
||||
}
|
||||
writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS);
|
||||
|
||||
value = readl(ioaddr + GMAC_INT_EN);
|
||||
|
||||
if (pmac_enable) {
|
||||
if (!(value & GMAC_INT_FPE_EN)) {
|
||||
/* Dummy read to clear any pending masked interrupts */
|
||||
readl(ioaddr + MAC_FPE_CTRL_STS);
|
||||
|
||||
value |= GMAC_INT_FPE_EN;
|
||||
}
|
||||
} else {
|
||||
value &= ~GMAC_INT_FPE_EN;
|
||||
}
|
||||
|
||||
writel(value, ioaddr + GMAC_INT_EN);
|
||||
}
|
||||
|
||||
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
|
||||
{
|
||||
u32 value;
|
||||
int status;
|
||||
|
||||
status = FPE_EVENT_UNKNOWN;
|
||||
|
||||
/* Reads from the MAC_FPE_CTRL_STS register should only be performed
|
||||
* here, since the status flags of MAC_FPE_CTRL_STS are "clear on read"
|
||||
*/
|
||||
value = readl(ioaddr + MAC_FPE_CTRL_STS);
|
||||
|
||||
if (value & TRSP) {
|
||||
status |= FPE_EVENT_TRSP;
|
||||
netdev_dbg(dev, "FPE: Respond mPacket is transmitted\n");
|
||||
}
|
||||
|
||||
if (value & TVER) {
|
||||
status |= FPE_EVENT_TVER;
|
||||
netdev_dbg(dev, "FPE: Verify mPacket is transmitted\n");
|
||||
}
|
||||
|
||||
if (value & RRSP) {
|
||||
status |= FPE_EVENT_RRSP;
|
||||
netdev_dbg(dev, "FPE: Respond mPacket is received\n");
|
||||
}
|
||||
|
||||
if (value & RVER) {
|
||||
status |= FPE_EVENT_RVER;
|
||||
netdev_dbg(dev, "FPE: Verify mPacket is received\n");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
||||
enum stmmac_mpacket_type type)
|
||||
{
|
||||
u32 value = cfg->fpe_csr;
|
||||
|
||||
if (type == MPACKET_VERIFY)
|
||||
value |= SVER;
|
||||
else if (type == MPACKET_RESPONSE)
|
||||
value |= SRSP;
|
||||
|
||||
writel(value, ioaddr + MAC_FPE_CTRL_STS);
|
||||
}
|
||||
|
||||
int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr)
|
||||
{
|
||||
return FIELD_GET(DWMAC5_ADD_FRAG_SZ, readl(ioaddr + MTL_FPE_CTRL_STS));
|
||||
}
|
||||
|
||||
void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + MTL_FPE_CTRL_STS);
|
||||
writel(u32_replace_bits(value, add_frag_size, DWMAC5_ADD_FRAG_SZ),
|
||||
ioaddr + MTL_FPE_CTRL_STS);
|
||||
}
|
||||
|
||||
#define ALG_ERR_MSG "TX algorithm SP is not suitable for one-to-many mapping"
|
||||
#define WEIGHT_ERR_MSG "TXQ weight %u differs across other TXQs in TC: [%u]"
|
||||
|
||||
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack, u32 pclass)
|
||||
{
|
||||
u32 val, offset, count, queue_weight, preemptible_txqs = 0;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
u32 num_tc = ndev->num_tc;
|
||||
|
||||
if (!pclass)
|
||||
goto update_mapping;
|
||||
|
||||
/* DWMAC CORE4+ can not program TC:TXQ mapping to hardware.
|
||||
*
|
||||
* Synopsys Databook:
|
||||
* "The number of Tx DMA channels is equal to the number of Tx queues,
|
||||
* and is direct one-to-one mapping."
|
||||
*/
|
||||
for (u32 tc = 0; tc < num_tc; tc++) {
|
||||
count = ndev->tc_to_txq[tc].count;
|
||||
offset = ndev->tc_to_txq[tc].offset;
|
||||
|
||||
if (pclass & BIT(tc))
|
||||
preemptible_txqs |= GENMASK(offset + count - 1, offset);
|
||||
|
||||
/* This is 1:1 mapping, go to next TC */
|
||||
if (count == 1)
|
||||
continue;
|
||||
|
||||
if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) {
|
||||
NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
queue_weight = priv->plat->tx_queues_cfg[offset].weight;
|
||||
|
||||
for (u32 i = 1; i < count; i++) {
|
||||
if (priv->plat->tx_queues_cfg[offset + i].weight !=
|
||||
queue_weight) {
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG,
|
||||
queue_weight, tc);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_mapping:
|
||||
val = readl(priv->ioaddr + MTL_FPE_CTRL_STS);
|
||||
writel(u32_replace_bits(val, preemptible_txqs, DWMAC5_PREEMPTION_CLASS),
|
||||
priv->ioaddr + MTL_FPE_CTRL_STS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
|
||||
// Copyright (c) 2017 Synopsys, Inc. and/or its affiliates.
|
||||
// stmmac Support for 5.xx Ethernet QoS cores
|
||||
|
||||
#ifndef __DWMAC5_H__
|
||||
#define __DWMAC5_H__
|
||||
|
||||
#define MAC_DPP_FSM_INT_STATUS 0x00000140
|
||||
#define MAC_AXI_SLV_DPE_ADDR_STATUS 0x00000144
|
||||
#define MAC_FSM_CONTROL 0x00000148
|
||||
#define PRTYEN BIT(1)
|
||||
#define TMOUTEN BIT(0)
|
||||
|
||||
#define MAC_FPE_CTRL_STS 0x00000234
|
||||
#define TRSP BIT(19)
|
||||
#define TVER BIT(18)
|
||||
#define RRSP BIT(17)
|
||||
#define RVER BIT(16)
|
||||
#define SRSP BIT(2)
|
||||
#define SVER BIT(1)
|
||||
#define EFPE BIT(0)
|
||||
|
||||
#define MAC_PPS_CONTROL 0x00000b70
|
||||
#define PPS_MAXIDX(x) ((((x) + 1) * 8) - 1)
|
||||
#define PPS_MINIDX(x) ((x) * 8)
|
||||
#define PPSx_MASK(x) GENMASK(PPS_MAXIDX(x), PPS_MINIDX(x))
|
||||
#define MCGRENx(x) BIT(PPS_MAXIDX(x))
|
||||
#define TRGTMODSELx(x, val) \
|
||||
GENMASK(PPS_MAXIDX(x) - 1, PPS_MAXIDX(x) - 2) & \
|
||||
((val) << (PPS_MAXIDX(x) - 2))
|
||||
#define PPSCMDx(x, val) \
|
||||
GENMASK(PPS_MINIDX(x) + 3, PPS_MINIDX(x)) & \
|
||||
((val) << PPS_MINIDX(x))
|
||||
#define PPSEN0 BIT(4)
|
||||
#define MAC_PPSx_TARGET_TIME_SEC(x) (0x00000b80 + ((x) * 0x10))
|
||||
#define MAC_PPSx_TARGET_TIME_NSEC(x) (0x00000b84 + ((x) * 0x10))
|
||||
#define TRGTBUSY0 BIT(31)
|
||||
#define TTSL0 GENMASK(30, 0)
|
||||
#define MAC_PPSx_INTERVAL(x) (0x00000b88 + ((x) * 0x10))
|
||||
#define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10))
|
||||
|
||||
#define MTL_FPE_CTRL_STS 0x00000c90
|
||||
/* Preemption Classification */
|
||||
#define DWMAC5_PREEMPTION_CLASS GENMASK(15, 8)
|
||||
/* Additional Fragment Size of preempted frames */
|
||||
#define DWMAC5_ADD_FRAG_SZ GENMASK(1, 0)
|
||||
|
||||
#define MTL_RXP_CONTROL_STATUS 0x00000ca0
|
||||
#define RXPI BIT(31)
|
||||
#define NPE GENMASK(23, 16)
|
||||
#define NVE GENMASK(7, 0)
|
||||
#define MTL_RXP_IACC_CTRL_STATUS 0x00000cb0
|
||||
#define STARTBUSY BIT(31)
|
||||
#define RXPEIEC GENMASK(22, 21)
|
||||
#define RXPEIEE BIT(20)
|
||||
#define WRRDN BIT(16)
|
||||
#define ADDR GENMASK(15, 0)
|
||||
#define MTL_RXP_IACC_DATA 0x00000cb4
|
||||
#define MTL_ECC_CONTROL 0x00000cc0
|
||||
#define MEEAO BIT(8)
|
||||
#define TSOEE BIT(4)
|
||||
#define MRXPEE BIT(3)
|
||||
#define MESTEE BIT(2)
|
||||
#define MRXEE BIT(1)
|
||||
#define MTXEE BIT(0)
|
||||
|
||||
#define MTL_SAFETY_INT_STATUS 0x00000cc4
|
||||
#define MCSIS BIT(31)
|
||||
#define MEUIS BIT(1)
|
||||
#define MECIS BIT(0)
|
||||
#define MTL_ECC_INT_ENABLE 0x00000cc8
|
||||
#define RPCEIE BIT(12)
|
||||
#define ECEIE BIT(8)
|
||||
#define RXCEIE BIT(4)
|
||||
#define TXCEIE BIT(0)
|
||||
#define MTL_ECC_INT_STATUS 0x00000ccc
|
||||
#define MTL_DPP_CONTROL 0x00000ce0
|
||||
#define EPSI BIT(2)
|
||||
#define OPE BIT(1)
|
||||
#define EDPP BIT(0)
|
||||
|
||||
#define DMA_SAFETY_INT_STATUS 0x00001080
|
||||
#define MSUIS BIT(29)
|
||||
#define MSCIS BIT(28)
|
||||
#define DEUIS BIT(1)
|
||||
#define DECIS BIT(0)
|
||||
#define DMA_ECC_INT_ENABLE 0x00001084
|
||||
#define TCEIE BIT(0)
|
||||
#define DMA_ECC_INT_STATUS 0x00001088
|
||||
|
||||
/* EQoS version 5.xx VLAN Tag Filter Fail Packets Queuing */
|
||||
#define GMAC_RXQ_CTRL4 0x00000094
|
||||
#define GMAC_RXQCTRL_VFFQ_MASK GENMASK(19, 17)
|
||||
#define GMAC_RXQCTRL_VFFQ_SHIFT 17
|
||||
#define GMAC_RXQCTRL_VFFQE BIT(16)
|
||||
|
||||
#define GMAC_INT_FPE_EN BIT(17)
|
||||
|
||||
int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
|
||||
struct stmmac_safety_feature_cfg *safety_cfg);
|
||||
int dwmac5_safety_feat_irq_status(struct net_device *ndev,
|
||||
void __iomem *ioaddr, unsigned int asp,
|
||||
struct stmmac_safety_stats *stats);
|
||||
int dwmac5_safety_feat_dump(struct stmmac_safety_stats *stats,
|
||||
int index, unsigned long *count, const char **desc);
|
||||
int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
|
||||
unsigned int count);
|
||||
int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
|
||||
struct stmmac_pps_cfg *cfg, bool enable,
|
||||
u32 sub_second_inc, u32 systime_flags);
|
||||
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
||||
u32 num_txq, u32 num_rxq,
|
||||
bool tx_enable, bool pmac_enable);
|
||||
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
|
||||
struct stmmac_fpe_cfg *cfg,
|
||||
enum stmmac_mpacket_type type);
|
||||
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev);
|
||||
int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr);
|
||||
void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size);
|
||||
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack, u32 pclass);
|
||||
|
||||
#endif /* __DWMAC5_H__ */
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
DWMAC DMA Header file.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DWMAC_DMA_H__
|
||||
#define __DWMAC_DMA_H__
|
||||
|
||||
/* DMA CRS Control and Status Register Mapping */
|
||||
#define DMA_BUS_MODE 0x00001000 /* Bus Mode */
|
||||
#define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */
|
||||
#define DMA_RCV_POLL_DEMAND 0x00001008 /* Received Poll Demand */
|
||||
#define DMA_RCV_BASE_ADDR 0x0000100c /* Receive List Base */
|
||||
#define DMA_TX_BASE_ADDR 0x00001010 /* Transmit List Base */
|
||||
#define DMA_STATUS 0x00001014 /* Status Register */
|
||||
#define DMA_CONTROL 0x00001018 /* Ctrl (Operational Mode) */
|
||||
#define DMA_INTR_ENA 0x0000101c /* Interrupt Enable */
|
||||
#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */
|
||||
|
||||
/* Following DMA defines are channels oriented */
|
||||
#define DMA_CHAN_BASE_OFFSET 0x100
|
||||
|
||||
static inline u32 dma_chan_base_addr(u32 base, u32 chan)
|
||||
{
|
||||
return base + chan * DMA_CHAN_BASE_OFFSET;
|
||||
}
|
||||
|
||||
#define DMA_CHAN_BUS_MODE(chan) dma_chan_base_addr(DMA_BUS_MODE, chan)
|
||||
#define DMA_CHAN_XMT_POLL_DEMAND(chan) \
|
||||
dma_chan_base_addr(DMA_XMT_POLL_DEMAND, chan)
|
||||
#define DMA_CHAN_RCV_POLL_DEMAND(chan) \
|
||||
dma_chan_base_addr(DMA_RCV_POLL_DEMAND, chan)
|
||||
#define DMA_CHAN_RCV_BASE_ADDR(chan) \
|
||||
dma_chan_base_addr(DMA_RCV_BASE_ADDR, chan)
|
||||
#define DMA_CHAN_TX_BASE_ADDR(chan) \
|
||||
dma_chan_base_addr(DMA_TX_BASE_ADDR, chan)
|
||||
#define DMA_CHAN_STATUS(chan) dma_chan_base_addr(DMA_STATUS, chan)
|
||||
#define DMA_CHAN_CONTROL(chan) dma_chan_base_addr(DMA_CONTROL, chan)
|
||||
#define DMA_CHAN_INTR_ENA(chan) dma_chan_base_addr(DMA_INTR_ENA, chan)
|
||||
#define DMA_CHAN_MISSED_FRAME_CTR(chan) \
|
||||
dma_chan_base_addr(DMA_MISSED_FRAME_CTR, chan)
|
||||
#define DMA_CHAN_RX_WATCHDOG(chan) \
|
||||
dma_chan_base_addr(DMA_RX_WATCHDOG, chan)
|
||||
|
||||
/* SW Reset */
|
||||
#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
|
||||
|
||||
/* Rx watchdog register */
|
||||
#define DMA_RX_WATCHDOG 0x00001024
|
||||
|
||||
/* AXI Master Bus Mode */
|
||||
#define DMA_AXI_BUS_MODE 0x00001028
|
||||
|
||||
#define DMA_AXI_EN_LPI BIT(31)
|
||||
#define DMA_AXI_LPI_XIT_FRM BIT(30)
|
||||
#define DMA_AXI_WR_OSR_LMT GENMASK(23, 20)
|
||||
#define DMA_AXI_WR_OSR_LMT_SHIFT 20
|
||||
#define DMA_AXI_WR_OSR_LMT_MASK 0xf
|
||||
#define DMA_AXI_RD_OSR_LMT GENMASK(19, 16)
|
||||
#define DMA_AXI_RD_OSR_LMT_SHIFT 16
|
||||
#define DMA_AXI_RD_OSR_LMT_MASK 0xf
|
||||
|
||||
#define DMA_AXI_OSR_MAX 0xf
|
||||
#define DMA_AXI_MAX_OSR_LIMIT ((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \
|
||||
(DMA_AXI_OSR_MAX << DMA_AXI_RD_OSR_LMT_SHIFT))
|
||||
#define DMA_AXI_1KBBE BIT(13)
|
||||
#define DMA_AXI_AAL BIT(12)
|
||||
#define DMA_AXI_BLEN256 BIT(7)
|
||||
#define DMA_AXI_BLEN128 BIT(6)
|
||||
#define DMA_AXI_BLEN64 BIT(5)
|
||||
#define DMA_AXI_BLEN32 BIT(4)
|
||||
#define DMA_AXI_BLEN16 BIT(3)
|
||||
#define DMA_AXI_BLEN8 BIT(2)
|
||||
#define DMA_AXI_BLEN4 BIT(1)
|
||||
#define DMA_BURST_LEN_DEFAULT (DMA_AXI_BLEN256 | DMA_AXI_BLEN128 | \
|
||||
DMA_AXI_BLEN64 | DMA_AXI_BLEN32 | \
|
||||
DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | \
|
||||
DMA_AXI_BLEN4)
|
||||
|
||||
#define DMA_AXI_UNDEF BIT(0)
|
||||
|
||||
#define DMA_AXI_BURST_LEN_MASK 0x000000FE
|
||||
|
||||
#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */
|
||||
#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */
|
||||
#define DMA_HW_FEATURE 0x00001058 /* HW Feature Register */
|
||||
|
||||
/* DMA Control register defines */
|
||||
#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */
|
||||
#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */
|
||||
|
||||
/* DMA Normal interrupt */
|
||||
#define DMA_INTR_ENA_NIE 0x00010000 /* Normal Summary */
|
||||
#define DMA_INTR_ENA_TIE 0x00000001 /* Transmit Interrupt */
|
||||
#define DMA_INTR_ENA_TUE 0x00000004 /* Transmit Buffer Unavailable */
|
||||
#define DMA_INTR_ENA_RIE 0x00000040 /* Receive Interrupt */
|
||||
#define DMA_INTR_ENA_ERE 0x00004000 /* Early Receive */
|
||||
|
||||
#define DMA_INTR_NORMAL (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \
|
||||
DMA_INTR_ENA_TIE)
|
||||
|
||||
/* DMA Abnormal interrupt */
|
||||
#define DMA_INTR_ENA_AIE 0x00008000 /* Abnormal Summary */
|
||||
#define DMA_INTR_ENA_FBE 0x00002000 /* Fatal Bus Error */
|
||||
#define DMA_INTR_ENA_ETE 0x00000400 /* Early Transmit */
|
||||
#define DMA_INTR_ENA_RWE 0x00000200 /* Receive Watchdog */
|
||||
#define DMA_INTR_ENA_RSE 0x00000100 /* Receive Stopped */
|
||||
#define DMA_INTR_ENA_RUE 0x00000080 /* Receive Buffer Unavailable */
|
||||
#define DMA_INTR_ENA_UNE 0x00000020 /* Tx Underflow */
|
||||
#define DMA_INTR_ENA_OVE 0x00000010 /* Receive Overflow */
|
||||
#define DMA_INTR_ENA_TJE 0x00000008 /* Transmit Jabber */
|
||||
#define DMA_INTR_ENA_TSE 0x00000002 /* Transmit Stopped */
|
||||
|
||||
#define DMA_INTR_ABNORMAL (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \
|
||||
DMA_INTR_ENA_UNE)
|
||||
|
||||
/* DMA default interrupt mask */
|
||||
#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
|
||||
#define DMA_INTR_DEFAULT_RX (DMA_INTR_ENA_RIE)
|
||||
#define DMA_INTR_DEFAULT_TX (DMA_INTR_ENA_TIE)
|
||||
|
||||
/* DMA Status register defines */
|
||||
#define DMA_STATUS_GLPII 0x40000000 /* GMAC LPI interrupt */
|
||||
#define DMA_STATUS_GPI 0x10000000 /* PMT interrupt */
|
||||
#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
|
||||
#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */
|
||||
#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */
|
||||
#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */
|
||||
#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */
|
||||
#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */
|
||||
#define DMA_STATUS_TS_SHIFT 20
|
||||
#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */
|
||||
#define DMA_STATUS_RS_SHIFT 17
|
||||
#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */
|
||||
#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */
|
||||
#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */
|
||||
#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */
|
||||
#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */
|
||||
#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */
|
||||
#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */
|
||||
#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */
|
||||
#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */
|
||||
#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */
|
||||
#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */
|
||||
#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */
|
||||
#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */
|
||||
#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */
|
||||
#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
|
||||
#define DMA_CONTROL_FTF 0x00100000 /* Flush transmit FIFO */
|
||||
|
||||
#define DMA_STATUS_MSK_COMMON (DMA_STATUS_NIS | \
|
||||
DMA_STATUS_AIS | \
|
||||
DMA_STATUS_FBI)
|
||||
|
||||
#define DMA_STATUS_MSK_RX (DMA_STATUS_ERI | \
|
||||
DMA_STATUS_RWT | \
|
||||
DMA_STATUS_RPS | \
|
||||
DMA_STATUS_RU | \
|
||||
DMA_STATUS_RI | \
|
||||
DMA_STATUS_OVF | \
|
||||
DMA_STATUS_MSK_COMMON)
|
||||
|
||||
#define DMA_STATUS_MSK_TX (DMA_STATUS_ETI | \
|
||||
DMA_STATUS_UNF | \
|
||||
DMA_STATUS_TJT | \
|
||||
DMA_STATUS_TU | \
|
||||
DMA_STATUS_TPS | \
|
||||
DMA_STATUS_TI | \
|
||||
DMA_STATUS_MSK_COMMON)
|
||||
|
||||
#define NUM_DWMAC100_DMA_REGS 9
|
||||
#define NUM_DWMAC1000_DMA_REGS 23
|
||||
#define NUM_DWMAC4_DMA_REGS 27
|
||||
|
||||
void dwmac_enable_dma_transmission(void __iomem *ioaddr, u32 chan);
|
||||
void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void dwmac_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void dwmac_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void dwmac_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void dwmac_dma_start_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void dwmac_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 chan, u32 dir);
|
||||
int dwmac_dma_reset(void __iomem *ioaddr);
|
||||
|
||||
#endif /* __DWMAC_DMA_H__ */
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
DWMAC DMA Header file.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DWMAC_DMA_H__
|
||||
#define __DWMAC_DMA_H__
|
||||
|
||||
/* DMA CRS Control and Status Register Mapping */
|
||||
#define DMA_BUS_MODE 0x00001000 /* Bus Mode */
|
||||
#define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */
|
||||
#define DMA_RCV_POLL_DEMAND 0x00001008 /* Received Poll Demand */
|
||||
#define DMA_RCV_BASE_ADDR 0x0000100c /* Receive List Base */
|
||||
#define DMA_TX_BASE_ADDR 0x00001010 /* Transmit List Base */
|
||||
#define DMA_STATUS 0x00001014 /* Status Register */
|
||||
#define DMA_CONTROL 0x00001018 /* Ctrl (Operational Mode) */
|
||||
#define DMA_INTR_ENA 0x0000101c /* Interrupt Enable */
|
||||
#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */
|
||||
|
||||
/* Following DMA defines are channels oriented */
|
||||
#define DMA_CHAN_BASE_OFFSET 0x100
|
||||
|
||||
static inline u32 dma_chan_base_addr(u32 base, u32 chan)
|
||||
{
|
||||
return base + chan * DMA_CHAN_BASE_OFFSET;
|
||||
}
|
||||
|
||||
#define DMA_CHAN_BUS_MODE(chan) dma_chan_base_addr(DMA_BUS_MODE, chan)
|
||||
#define DMA_CHAN_XMT_POLL_DEMAND(chan) \
|
||||
dma_chan_base_addr(DMA_XMT_POLL_DEMAND, chan)
|
||||
#define DMA_CHAN_RCV_POLL_DEMAND(chan) \
|
||||
dma_chan_base_addr(DMA_RCV_POLL_DEMAND, chan)
|
||||
#define DMA_CHAN_RCV_BASE_ADDR(chan) \
|
||||
dma_chan_base_addr(DMA_RCV_BASE_ADDR, chan)
|
||||
#define DMA_CHAN_TX_BASE_ADDR(chan) \
|
||||
dma_chan_base_addr(DMA_TX_BASE_ADDR, chan)
|
||||
#define DMA_CHAN_STATUS(chan) dma_chan_base_addr(DMA_STATUS, chan)
|
||||
#define DMA_CHAN_CONTROL(chan) dma_chan_base_addr(DMA_CONTROL, chan)
|
||||
#define DMA_CHAN_INTR_ENA(chan) dma_chan_base_addr(DMA_INTR_ENA, chan)
|
||||
#define DMA_CHAN_MISSED_FRAME_CTR(chan) \
|
||||
dma_chan_base_addr(DMA_MISSED_FRAME_CTR, chan)
|
||||
#define DMA_CHAN_RX_WATCHDOG(chan) \
|
||||
dma_chan_base_addr(DMA_RX_WATCHDOG, chan)
|
||||
|
||||
/* SW Reset */
|
||||
#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
|
||||
|
||||
/* Rx watchdog register */
|
||||
#define DMA_RX_WATCHDOG 0x00001024
|
||||
|
||||
/* AXI Master Bus Mode */
|
||||
#define DMA_AXI_BUS_MODE 0x00001028
|
||||
|
||||
#define DMA_AXI_EN_LPI BIT(31)
|
||||
#define DMA_AXI_LPI_XIT_FRM BIT(30)
|
||||
#define DMA_AXI_WR_OSR_LMT GENMASK(23, 20)
|
||||
#define DMA_AXI_WR_OSR_LMT_SHIFT 20
|
||||
#define DMA_AXI_WR_OSR_LMT_MASK 0xf
|
||||
#define DMA_AXI_RD_OSR_LMT GENMASK(19, 16)
|
||||
#define DMA_AXI_RD_OSR_LMT_SHIFT 16
|
||||
#define DMA_AXI_RD_OSR_LMT_MASK 0xf
|
||||
|
||||
#define DMA_AXI_OSR_MAX 0xf
|
||||
#define DMA_AXI_MAX_OSR_LIMIT ((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \
|
||||
(DMA_AXI_OSR_MAX << DMA_AXI_RD_OSR_LMT_SHIFT))
|
||||
#define DMA_AXI_1KBBE BIT(13)
|
||||
#define DMA_AXI_AAL BIT(12)
|
||||
#define DMA_AXI_BLEN256 BIT(7)
|
||||
#define DMA_AXI_BLEN128 BIT(6)
|
||||
#define DMA_AXI_BLEN64 BIT(5)
|
||||
#define DMA_AXI_BLEN32 BIT(4)
|
||||
#define DMA_AXI_BLEN16 BIT(3)
|
||||
#define DMA_AXI_BLEN8 BIT(2)
|
||||
#define DMA_AXI_BLEN4 BIT(1)
|
||||
#define DMA_BURST_LEN_DEFAULT (DMA_AXI_BLEN256 | DMA_AXI_BLEN128 | \
|
||||
DMA_AXI_BLEN64 | DMA_AXI_BLEN32 | \
|
||||
DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | \
|
||||
DMA_AXI_BLEN4)
|
||||
|
||||
#define DMA_AXI_UNDEF BIT(0)
|
||||
|
||||
#define DMA_AXI_BURST_LEN_MASK 0x000000FE
|
||||
|
||||
#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */
|
||||
#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */
|
||||
#define DMA_HW_FEATURE 0x00001058 /* HW Feature Register */
|
||||
|
||||
/* DMA Control register defines */
|
||||
#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */
|
||||
#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */
|
||||
|
||||
/* DMA Normal interrupt */
|
||||
#define DMA_INTR_ENA_NIE 0x00010000 /* Normal Summary */
|
||||
#define DMA_INTR_ENA_TIE 0x00000001 /* Transmit Interrupt */
|
||||
#define DMA_INTR_ENA_TUE 0x00000004 /* Transmit Buffer Unavailable */
|
||||
#define DMA_INTR_ENA_RIE 0x00000040 /* Receive Interrupt */
|
||||
#define DMA_INTR_ENA_ERE 0x00004000 /* Early Receive */
|
||||
|
||||
#define DMA_INTR_NORMAL (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \
|
||||
DMA_INTR_ENA_TIE)
|
||||
|
||||
/* DMA Abnormal interrupt */
|
||||
#define DMA_INTR_ENA_AIE 0x00008000 /* Abnormal Summary */
|
||||
#define DMA_INTR_ENA_FBE 0x00002000 /* Fatal Bus Error */
|
||||
#define DMA_INTR_ENA_ETE 0x00000400 /* Early Transmit */
|
||||
#define DMA_INTR_ENA_RWE 0x00000200 /* Receive Watchdog */
|
||||
#define DMA_INTR_ENA_RSE 0x00000100 /* Receive Stopped */
|
||||
#define DMA_INTR_ENA_RUE 0x00000080 /* Receive Buffer Unavailable */
|
||||
#define DMA_INTR_ENA_UNE 0x00000020 /* Tx Underflow */
|
||||
#define DMA_INTR_ENA_OVE 0x00000010 /* Receive Overflow */
|
||||
#define DMA_INTR_ENA_TJE 0x00000008 /* Transmit Jabber */
|
||||
#define DMA_INTR_ENA_TSE 0x00000002 /* Transmit Stopped */
|
||||
|
||||
#define DMA_INTR_ABNORMAL (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \
|
||||
DMA_INTR_ENA_UNE)
|
||||
|
||||
/* DMA default interrupt mask */
|
||||
#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
|
||||
#define DMA_INTR_DEFAULT_RX (DMA_INTR_ENA_RIE)
|
||||
#define DMA_INTR_DEFAULT_TX (DMA_INTR_ENA_TIE)
|
||||
|
||||
/* DMA Status register defines */
|
||||
#define DMA_STATUS_GLPII 0x40000000 /* GMAC LPI interrupt */
|
||||
#define DMA_STATUS_GPI 0x10000000 /* PMT interrupt */
|
||||
#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
|
||||
#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */
|
||||
#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */
|
||||
#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */
|
||||
#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */
|
||||
#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */
|
||||
#define DMA_STATUS_TS_SHIFT 20
|
||||
#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */
|
||||
#define DMA_STATUS_RS_SHIFT 17
|
||||
#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */
|
||||
#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */
|
||||
#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */
|
||||
#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */
|
||||
#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */
|
||||
#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */
|
||||
#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */
|
||||
#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */
|
||||
#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */
|
||||
#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */
|
||||
#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */
|
||||
#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */
|
||||
#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */
|
||||
#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */
|
||||
#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
|
||||
#define DMA_CONTROL_FTF 0x00100000 /* Flush transmit FIFO */
|
||||
|
||||
#define DMA_STATUS_MSK_COMMON (DMA_STATUS_NIS | \
|
||||
DMA_STATUS_AIS | \
|
||||
DMA_STATUS_FBI)
|
||||
|
||||
#define DMA_STATUS_MSK_RX (DMA_STATUS_ERI | \
|
||||
DMA_STATUS_RWT | \
|
||||
DMA_STATUS_RPS | \
|
||||
DMA_STATUS_RU | \
|
||||
DMA_STATUS_RI | \
|
||||
DMA_STATUS_OVF | \
|
||||
DMA_STATUS_MSK_COMMON)
|
||||
|
||||
#define DMA_STATUS_MSK_TX (DMA_STATUS_ETI | \
|
||||
DMA_STATUS_UNF | \
|
||||
DMA_STATUS_TJT | \
|
||||
DMA_STATUS_TU | \
|
||||
DMA_STATUS_TPS | \
|
||||
DMA_STATUS_TI | \
|
||||
DMA_STATUS_MSK_COMMON)
|
||||
|
||||
#define NUM_DWMAC100_DMA_REGS 9
|
||||
#define NUM_DWMAC1000_DMA_REGS 23
|
||||
#define NUM_DWMAC4_DMA_REGS 27
|
||||
|
||||
void dwmac_enable_dma_transmission(void __iomem *ioaddr, u32 chan);
|
||||
void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void dwmac_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void dwmac_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void dwmac_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void dwmac_dma_start_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void dwmac_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 chan, u32 dir);
|
||||
int dwmac_dma_reset(void __iomem *ioaddr);
|
||||
|
||||
#endif /* __DWMAC_DMA_H__ */
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include "common-6.12-ethercat.h"
|
||||
#include "dwmac_dma-6.12-ethercat.h"
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
|
||||
#define GMAC_HI_REG_AE 0x80000000
|
||||
|
||||
int dwmac_dma_reset(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_BUS_MODE);
|
||||
|
||||
/* DMA SW reset */
|
||||
value |= DMA_BUS_MODE_SFT_RESET;
|
||||
writel(value, ioaddr + DMA_BUS_MODE);
|
||||
|
||||
return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
|
||||
!(value & DMA_BUS_MODE_SFT_RESET),
|
||||
10000, 200000);
|
||||
}
|
||||
|
||||
/* CSR1 enables the transmit DMA to check for new descriptor */
|
||||
void dwmac_enable_dma_transmission(void __iomem *ioaddr, u32 chan)
|
||||
{
|
||||
writel(1, ioaddr + DMA_CHAN_XMT_POLL_DEMAND(chan));
|
||||
}
|
||||
|
||||
void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
|
||||
|
||||
if (rx)
|
||||
value |= DMA_INTR_DEFAULT_RX;
|
||||
if (tx)
|
||||
value |= DMA_INTR_DEFAULT_TX;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
|
||||
}
|
||||
|
||||
void dwmac_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
|
||||
|
||||
if (rx)
|
||||
value &= ~DMA_INTR_DEFAULT_RX;
|
||||
if (tx)
|
||||
value &= ~DMA_INTR_DEFAULT_TX;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
|
||||
}
|
||||
|
||||
void dwmac_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
value |= DMA_CONTROL_ST;
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
}
|
||||
|
||||
void dwmac_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
value &= ~DMA_CONTROL_ST;
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
}
|
||||
|
||||
void dwmac_dma_start_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
value |= DMA_CONTROL_SR;
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
}
|
||||
|
||||
void dwmac_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
value &= ~DMA_CONTROL_SR;
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
}
|
||||
|
||||
#ifdef DWMAC_DMA_DEBUG
|
||||
static void show_tx_process_state(unsigned int status)
|
||||
{
|
||||
unsigned int state;
|
||||
state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT;
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
pr_debug("- TX (Stopped): Reset or Stop command\n");
|
||||
break;
|
||||
case 1:
|
||||
pr_debug("- TX (Running): Fetching the Tx desc\n");
|
||||
break;
|
||||
case 2:
|
||||
pr_debug("- TX (Running): Waiting for end of tx\n");
|
||||
break;
|
||||
case 3:
|
||||
pr_debug("- TX (Running): Reading the data "
|
||||
"and queuing the data into the Tx buf\n");
|
||||
break;
|
||||
case 6:
|
||||
pr_debug("- TX (Suspended): Tx Buff Underflow "
|
||||
"or an unavailable Transmit descriptor\n");
|
||||
break;
|
||||
case 7:
|
||||
pr_debug("- TX (Running): Closing Tx descriptor\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void show_rx_process_state(unsigned int status)
|
||||
{
|
||||
unsigned int state;
|
||||
state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT;
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
pr_debug("- RX (Stopped): Reset or Stop command\n");
|
||||
break;
|
||||
case 1:
|
||||
pr_debug("- RX (Running): Fetching the Rx desc\n");
|
||||
break;
|
||||
case 2:
|
||||
pr_debug("- RX (Running): Checking for end of pkt\n");
|
||||
break;
|
||||
case 3:
|
||||
pr_debug("- RX (Running): Waiting for Rx pkt\n");
|
||||
break;
|
||||
case 4:
|
||||
pr_debug("- RX (Suspended): Unavailable Rx buf\n");
|
||||
break;
|
||||
case 5:
|
||||
pr_debug("- RX (Running): Closing Rx descriptor\n");
|
||||
break;
|
||||
case 6:
|
||||
pr_debug("- RX(Running): Flushing the current frame"
|
||||
" from the Rx buf\n");
|
||||
break;
|
||||
case 7:
|
||||
pr_debug("- RX (Running): Queuing the Rx frame"
|
||||
" from the Rx buf into memory\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 chan, u32 dir)
|
||||
{
|
||||
struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);
|
||||
int ret = 0;
|
||||
/* read the status register (CSR5) */
|
||||
u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(chan));
|
||||
|
||||
#ifdef DWMAC_DMA_DEBUG
|
||||
/* Enable it to monitor DMA rx/tx status in case of critical problems */
|
||||
pr_debug("%s: [CSR5: 0x%08x]\n", __func__, intr_status);
|
||||
show_tx_process_state(intr_status);
|
||||
show_rx_process_state(intr_status);
|
||||
#endif
|
||||
|
||||
if (dir == DMA_DIR_RX)
|
||||
intr_status &= DMA_STATUS_MSK_RX;
|
||||
else if (dir == DMA_DIR_TX)
|
||||
intr_status &= DMA_STATUS_MSK_TX;
|
||||
|
||||
/* ABNORMAL interrupts */
|
||||
if (unlikely(intr_status & DMA_STATUS_AIS)) {
|
||||
if (unlikely(intr_status & DMA_STATUS_UNF)) {
|
||||
ret = tx_hard_error_bump_tc;
|
||||
x->tx_undeflow_irq++;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_TJT))
|
||||
x->tx_jabber_irq++;
|
||||
|
||||
if (unlikely(intr_status & DMA_STATUS_OVF))
|
||||
x->rx_overflow_irq++;
|
||||
|
||||
if (unlikely(intr_status & DMA_STATUS_RU))
|
||||
x->rx_buf_unav_irq++;
|
||||
if (unlikely(intr_status & DMA_STATUS_RPS))
|
||||
x->rx_process_stopped_irq++;
|
||||
if (unlikely(intr_status & DMA_STATUS_RWT))
|
||||
x->rx_watchdog_irq++;
|
||||
if (unlikely(intr_status & DMA_STATUS_ETI))
|
||||
x->tx_early_irq++;
|
||||
if (unlikely(intr_status & DMA_STATUS_TPS)) {
|
||||
x->tx_process_stopped_irq++;
|
||||
ret = tx_hard_error;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_FBI)) {
|
||||
x->fatal_bus_error_irq++;
|
||||
ret = tx_hard_error;
|
||||
}
|
||||
}
|
||||
/* TX/RX NORMAL interrupts */
|
||||
if (likely(intr_status & DMA_STATUS_NIS)) {
|
||||
if (likely(intr_status & DMA_STATUS_RI)) {
|
||||
u32 value = readl(ioaddr + DMA_INTR_ENA);
|
||||
/* to schedule NAPI on real RIE event. */
|
||||
if (likely(value & DMA_INTR_ENA_RIE)) {
|
||||
u64_stats_update_begin(&stats->syncp);
|
||||
u64_stats_inc(&stats->rx_normal_irq_n[chan]);
|
||||
u64_stats_update_end(&stats->syncp);
|
||||
ret |= handle_rx;
|
||||
}
|
||||
}
|
||||
if (likely(intr_status & DMA_STATUS_TI)) {
|
||||
u64_stats_update_begin(&stats->syncp);
|
||||
u64_stats_inc(&stats->tx_normal_irq_n[chan]);
|
||||
u64_stats_update_end(&stats->syncp);
|
||||
ret |= handle_tx;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_ERI))
|
||||
x->rx_early_irq++;
|
||||
}
|
||||
/* Optional hardware blocks, interrupts should be disabled */
|
||||
if (unlikely(intr_status &
|
||||
(DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
|
||||
pr_warn("%s: unexpected status %08x\n", __func__, intr_status);
|
||||
|
||||
/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
|
||||
writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CONTROL);
|
||||
writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
|
||||
|
||||
do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
|
||||
}
|
||||
|
||||
void stmmac_set_mac_addr(void __iomem *ioaddr, const u8 addr[6],
|
||||
unsigned int high, unsigned int low)
|
||||
{
|
||||
unsigned long data;
|
||||
|
||||
data = (addr[5] << 8) | addr[4];
|
||||
/* For MAC Addr registers we have to set the Address Enable (AE)
|
||||
* bit that has no effect on the High Reg 0 where the bit 31 (MO)
|
||||
* is RO.
|
||||
*/
|
||||
writel(data | GMAC_HI_REG_AE, ioaddr + high);
|
||||
data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
|
||||
writel(data, ioaddr + low);
|
||||
}
|
||||
|
||||
/* Enable disable MAC RX/TX */
|
||||
void stmmac_set_mac(void __iomem *ioaddr, bool enable)
|
||||
{
|
||||
u32 old_val, value;
|
||||
|
||||
old_val = readl(ioaddr + MAC_CTRL_REG);
|
||||
value = old_val;
|
||||
|
||||
if (enable)
|
||||
value |= MAC_ENABLE_RX | MAC_ENABLE_TX;
|
||||
else
|
||||
value &= ~(MAC_ENABLE_TX | MAC_ENABLE_RX);
|
||||
|
||||
if (value != old_val)
|
||||
writel(value, ioaddr + MAC_CTRL_REG);
|
||||
}
|
||||
|
||||
void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int high, unsigned int low)
|
||||
{
|
||||
unsigned int hi_addr, lo_addr;
|
||||
|
||||
/* Read the MAC address from the hardware */
|
||||
hi_addr = readl(ioaddr + high);
|
||||
lo_addr = readl(ioaddr + low);
|
||||
|
||||
/* Extract the MAC address from the high and low words */
|
||||
addr[0] = lo_addr & 0xff;
|
||||
addr[1] = (lo_addr >> 8) & 0xff;
|
||||
addr[2] = (lo_addr >> 16) & 0xff;
|
||||
addr[3] = (lo_addr >> 24) & 0xff;
|
||||
addr[4] = hi_addr & 0xff;
|
||||
addr[5] = (hi_addr >> 8) & 0xff;
|
||||
}
|
||||
|
|
@ -0,0 +1,301 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include "common.h"
|
||||
#include "dwmac_dma.h"
|
||||
#include "stmmac.h"
|
||||
|
||||
#define GMAC_HI_REG_AE 0x80000000
|
||||
|
||||
int dwmac_dma_reset(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_BUS_MODE);
|
||||
|
||||
/* DMA SW reset */
|
||||
value |= DMA_BUS_MODE_SFT_RESET;
|
||||
writel(value, ioaddr + DMA_BUS_MODE);
|
||||
|
||||
return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
|
||||
!(value & DMA_BUS_MODE_SFT_RESET),
|
||||
10000, 200000);
|
||||
}
|
||||
|
||||
/* CSR1 enables the transmit DMA to check for new descriptor */
|
||||
void dwmac_enable_dma_transmission(void __iomem *ioaddr, u32 chan)
|
||||
{
|
||||
writel(1, ioaddr + DMA_CHAN_XMT_POLL_DEMAND(chan));
|
||||
}
|
||||
|
||||
void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
|
||||
|
||||
if (rx)
|
||||
value |= DMA_INTR_DEFAULT_RX;
|
||||
if (tx)
|
||||
value |= DMA_INTR_DEFAULT_TX;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
|
||||
}
|
||||
|
||||
void dwmac_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
|
||||
|
||||
if (rx)
|
||||
value &= ~DMA_INTR_DEFAULT_RX;
|
||||
if (tx)
|
||||
value &= ~DMA_INTR_DEFAULT_TX;
|
||||
|
||||
writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
|
||||
}
|
||||
|
||||
void dwmac_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
value |= DMA_CONTROL_ST;
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
}
|
||||
|
||||
void dwmac_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
value &= ~DMA_CONTROL_ST;
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
}
|
||||
|
||||
void dwmac_dma_start_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
value |= DMA_CONTROL_SR;
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
}
|
||||
|
||||
void dwmac_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
value &= ~DMA_CONTROL_SR;
|
||||
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
|
||||
}
|
||||
|
||||
#ifdef DWMAC_DMA_DEBUG
|
||||
static void show_tx_process_state(unsigned int status)
|
||||
{
|
||||
unsigned int state;
|
||||
state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT;
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
pr_debug("- TX (Stopped): Reset or Stop command\n");
|
||||
break;
|
||||
case 1:
|
||||
pr_debug("- TX (Running): Fetching the Tx desc\n");
|
||||
break;
|
||||
case 2:
|
||||
pr_debug("- TX (Running): Waiting for end of tx\n");
|
||||
break;
|
||||
case 3:
|
||||
pr_debug("- TX (Running): Reading the data "
|
||||
"and queuing the data into the Tx buf\n");
|
||||
break;
|
||||
case 6:
|
||||
pr_debug("- TX (Suspended): Tx Buff Underflow "
|
||||
"or an unavailable Transmit descriptor\n");
|
||||
break;
|
||||
case 7:
|
||||
pr_debug("- TX (Running): Closing Tx descriptor\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void show_rx_process_state(unsigned int status)
|
||||
{
|
||||
unsigned int state;
|
||||
state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT;
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
pr_debug("- RX (Stopped): Reset or Stop command\n");
|
||||
break;
|
||||
case 1:
|
||||
pr_debug("- RX (Running): Fetching the Rx desc\n");
|
||||
break;
|
||||
case 2:
|
||||
pr_debug("- RX (Running): Checking for end of pkt\n");
|
||||
break;
|
||||
case 3:
|
||||
pr_debug("- RX (Running): Waiting for Rx pkt\n");
|
||||
break;
|
||||
case 4:
|
||||
pr_debug("- RX (Suspended): Unavailable Rx buf\n");
|
||||
break;
|
||||
case 5:
|
||||
pr_debug("- RX (Running): Closing Rx descriptor\n");
|
||||
break;
|
||||
case 6:
|
||||
pr_debug("- RX(Running): Flushing the current frame"
|
||||
" from the Rx buf\n");
|
||||
break;
|
||||
case 7:
|
||||
pr_debug("- RX (Running): Queuing the Rx frame"
|
||||
" from the Rx buf into memory\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 chan, u32 dir)
|
||||
{
|
||||
struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);
|
||||
int ret = 0;
|
||||
/* read the status register (CSR5) */
|
||||
u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(chan));
|
||||
|
||||
#ifdef DWMAC_DMA_DEBUG
|
||||
/* Enable it to monitor DMA rx/tx status in case of critical problems */
|
||||
pr_debug("%s: [CSR5: 0x%08x]\n", __func__, intr_status);
|
||||
show_tx_process_state(intr_status);
|
||||
show_rx_process_state(intr_status);
|
||||
#endif
|
||||
|
||||
if (dir == DMA_DIR_RX)
|
||||
intr_status &= DMA_STATUS_MSK_RX;
|
||||
else if (dir == DMA_DIR_TX)
|
||||
intr_status &= DMA_STATUS_MSK_TX;
|
||||
|
||||
/* ABNORMAL interrupts */
|
||||
if (unlikely(intr_status & DMA_STATUS_AIS)) {
|
||||
if (unlikely(intr_status & DMA_STATUS_UNF)) {
|
||||
ret = tx_hard_error_bump_tc;
|
||||
x->tx_undeflow_irq++;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_TJT))
|
||||
x->tx_jabber_irq++;
|
||||
|
||||
if (unlikely(intr_status & DMA_STATUS_OVF))
|
||||
x->rx_overflow_irq++;
|
||||
|
||||
if (unlikely(intr_status & DMA_STATUS_RU))
|
||||
x->rx_buf_unav_irq++;
|
||||
if (unlikely(intr_status & DMA_STATUS_RPS))
|
||||
x->rx_process_stopped_irq++;
|
||||
if (unlikely(intr_status & DMA_STATUS_RWT))
|
||||
x->rx_watchdog_irq++;
|
||||
if (unlikely(intr_status & DMA_STATUS_ETI))
|
||||
x->tx_early_irq++;
|
||||
if (unlikely(intr_status & DMA_STATUS_TPS)) {
|
||||
x->tx_process_stopped_irq++;
|
||||
ret = tx_hard_error;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_FBI)) {
|
||||
x->fatal_bus_error_irq++;
|
||||
ret = tx_hard_error;
|
||||
}
|
||||
}
|
||||
/* TX/RX NORMAL interrupts */
|
||||
if (likely(intr_status & DMA_STATUS_NIS)) {
|
||||
if (likely(intr_status & DMA_STATUS_RI)) {
|
||||
u32 value = readl(ioaddr + DMA_INTR_ENA);
|
||||
/* to schedule NAPI on real RIE event. */
|
||||
if (likely(value & DMA_INTR_ENA_RIE)) {
|
||||
u64_stats_update_begin(&stats->syncp);
|
||||
u64_stats_inc(&stats->rx_normal_irq_n[chan]);
|
||||
u64_stats_update_end(&stats->syncp);
|
||||
ret |= handle_rx;
|
||||
}
|
||||
}
|
||||
if (likely(intr_status & DMA_STATUS_TI)) {
|
||||
u64_stats_update_begin(&stats->syncp);
|
||||
u64_stats_inc(&stats->tx_normal_irq_n[chan]);
|
||||
u64_stats_update_end(&stats->syncp);
|
||||
ret |= handle_tx;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_ERI))
|
||||
x->rx_early_irq++;
|
||||
}
|
||||
/* Optional hardware blocks, interrupts should be disabled */
|
||||
if (unlikely(intr_status &
|
||||
(DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
|
||||
pr_warn("%s: unexpected status %08x\n", __func__, intr_status);
|
||||
|
||||
/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
|
||||
writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CONTROL);
|
||||
writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
|
||||
|
||||
do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
|
||||
}
|
||||
|
||||
void stmmac_set_mac_addr(void __iomem *ioaddr, const u8 addr[6],
|
||||
unsigned int high, unsigned int low)
|
||||
{
|
||||
unsigned long data;
|
||||
|
||||
data = (addr[5] << 8) | addr[4];
|
||||
/* For MAC Addr registers we have to set the Address Enable (AE)
|
||||
* bit that has no effect on the High Reg 0 where the bit 31 (MO)
|
||||
* is RO.
|
||||
*/
|
||||
writel(data | GMAC_HI_REG_AE, ioaddr + high);
|
||||
data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
|
||||
writel(data, ioaddr + low);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stmmac_set_mac_addr);
|
||||
|
||||
/* Enable disable MAC RX/TX */
|
||||
void stmmac_set_mac(void __iomem *ioaddr, bool enable)
|
||||
{
|
||||
u32 old_val, value;
|
||||
|
||||
old_val = readl(ioaddr + MAC_CTRL_REG);
|
||||
value = old_val;
|
||||
|
||||
if (enable)
|
||||
value |= MAC_ENABLE_RX | MAC_ENABLE_TX;
|
||||
else
|
||||
value &= ~(MAC_ENABLE_TX | MAC_ENABLE_RX);
|
||||
|
||||
if (value != old_val)
|
||||
writel(value, ioaddr + MAC_CTRL_REG);
|
||||
}
|
||||
|
||||
void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int high, unsigned int low)
|
||||
{
|
||||
unsigned int hi_addr, lo_addr;
|
||||
|
||||
/* Read the MAC address from the hardware */
|
||||
hi_addr = readl(ioaddr + high);
|
||||
lo_addr = readl(ioaddr + low);
|
||||
|
||||
/* Extract the MAC address from the high and low words */
|
||||
addr[0] = lo_addr & 0xff;
|
||||
addr[1] = (lo_addr >> 8) & 0xff;
|
||||
addr[2] = (lo_addr >> 16) & 0xff;
|
||||
addr[3] = (lo_addr >> 24) & 0xff;
|
||||
addr[4] = hi_addr & 0xff;
|
||||
addr[5] = (hi_addr >> 8) & 0xff;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stmmac_get_mac_addr);
|
||||
|
|
@ -0,0 +1,498 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
|
||||
/*
|
||||
* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
|
||||
* stmmac XGMAC definitions.
|
||||
*/
|
||||
|
||||
#ifndef __STMMAC_DWXGMAC2_H__
|
||||
#define __STMMAC_DWXGMAC2_H__
|
||||
|
||||
#include "common-6.12-ethercat.h"
|
||||
|
||||
/* Misc */
|
||||
#define XGMAC_JUMBO_LEN 16368
|
||||
|
||||
/* MAC Registers */
|
||||
#define XGMAC_TX_CONFIG 0x00000000
|
||||
#define XGMAC_CONFIG_SS_OFF 29
|
||||
#define XGMAC_CONFIG_SS_MASK GENMASK(31, 29)
|
||||
#define XGMAC_CONFIG_SS_10000 (0x0 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SS_2500_GMII (0x2 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SS_1000_GMII (0x3 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SS_100_MII (0x4 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SS_5000 (0x5 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SS_2500 (0x6 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SS_10_MII (0x7 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SARC GENMASK(22, 20)
|
||||
#define XGMAC_CONFIG_SARC_SHIFT 20
|
||||
#define XGMAC_CONFIG_JD BIT(16)
|
||||
#define XGMAC_CONFIG_TE BIT(0)
|
||||
#define XGMAC_CORE_INIT_TX (XGMAC_CONFIG_JD)
|
||||
#define XGMAC_RX_CONFIG 0x00000004
|
||||
#define XGMAC_CONFIG_ARPEN BIT(31)
|
||||
#define XGMAC_CONFIG_GPSL GENMASK(29, 16)
|
||||
#define XGMAC_CONFIG_GPSL_SHIFT 16
|
||||
#define XGMAC_CONFIG_HDSMS GENMASK(14, 12)
|
||||
#define XGMAC_CONFIG_HDSMS_SHIFT 12
|
||||
#define XGMAC_CONFIG_HDSMS_256 (0x2 << XGMAC_CONFIG_HDSMS_SHIFT)
|
||||
#define XGMAC_CONFIG_S2KP BIT(11)
|
||||
#define XGMAC_CONFIG_LM BIT(10)
|
||||
#define XGMAC_CONFIG_IPC BIT(9)
|
||||
#define XGMAC_CONFIG_JE BIT(8)
|
||||
#define XGMAC_CONFIG_WD BIT(7)
|
||||
#define XGMAC_CONFIG_GPSLCE BIT(6)
|
||||
#define XGMAC_CONFIG_CST BIT(2)
|
||||
#define XGMAC_CONFIG_ACS BIT(1)
|
||||
#define XGMAC_CONFIG_RE BIT(0)
|
||||
#define XGMAC_CORE_INIT_RX (XGMAC_CONFIG_GPSLCE | XGMAC_CONFIG_WD | \
|
||||
(XGMAC_JUMBO_LEN << XGMAC_CONFIG_GPSL_SHIFT))
|
||||
#define XGMAC_PACKET_FILTER 0x00000008
|
||||
#define XGMAC_FILTER_RA BIT(31)
|
||||
#define XGMAC_FILTER_IPFE BIT(20)
|
||||
#define XGMAC_FILTER_VTFE BIT(16)
|
||||
#define XGMAC_FILTER_HPF BIT(10)
|
||||
#define XGMAC_FILTER_PCF BIT(7)
|
||||
#define XGMAC_FILTER_PM BIT(4)
|
||||
#define XGMAC_FILTER_HMC BIT(2)
|
||||
#define XGMAC_FILTER_PR BIT(0)
|
||||
#define XGMAC_HASH_TABLE(x) (0x00000010 + (x) * 4)
|
||||
#define XGMAC_MAX_HASH_TABLE 8
|
||||
#define XGMAC_VLAN_TAG 0x00000050
|
||||
#define XGMAC_VLAN_EDVLP BIT(26)
|
||||
#define XGMAC_VLAN_VTHM BIT(25)
|
||||
#define XGMAC_VLAN_DOVLTC BIT(20)
|
||||
#define XGMAC_VLAN_ESVL BIT(18)
|
||||
#define XGMAC_VLAN_ETV BIT(16)
|
||||
#define XGMAC_VLAN_VID GENMASK(15, 0)
|
||||
#define XGMAC_VLAN_HASH_TABLE 0x00000058
|
||||
#define XGMAC_VLAN_INCL 0x00000060
|
||||
#define XGMAC_VLAN_VLTI BIT(20)
|
||||
#define XGMAC_VLAN_CSVL BIT(19)
|
||||
#define XGMAC_VLAN_VLC GENMASK(17, 16)
|
||||
#define XGMAC_VLAN_VLC_SHIFT 16
|
||||
#define XGMAC_RXQ_CTRL0 0x000000a0
|
||||
#define XGMAC_RXQEN(x) GENMASK((x) * 2 + 1, (x) * 2)
|
||||
#define XGMAC_RXQEN_SHIFT(x) ((x) * 2)
|
||||
#define XGMAC_RXQ_CTRL1 0x000000a4
|
||||
#define XGMAC_AVCPQ GENMASK(31, 28)
|
||||
#define XGMAC_AVCPQ_SHIFT 28
|
||||
#define XGMAC_PTPQ GENMASK(27, 24)
|
||||
#define XGMAC_PTPQ_SHIFT 24
|
||||
#define XGMAC_TACPQE BIT(23)
|
||||
#define XGMAC_DCBCPQ GENMASK(19, 16)
|
||||
#define XGMAC_DCBCPQ_SHIFT 16
|
||||
#define XGMAC_MCBCQEN BIT(15)
|
||||
#define XGMAC_MCBCQ GENMASK(11, 8)
|
||||
#define XGMAC_MCBCQ_SHIFT 8
|
||||
#define XGMAC_RQ GENMASK(7, 4)
|
||||
#define XGMAC_RQ_SHIFT 4
|
||||
#define XGMAC_UPQ GENMASK(3, 0)
|
||||
#define XGMAC_UPQ_SHIFT 0
|
||||
#define XGMAC_RXQ_CTRL2 0x000000a8
|
||||
#define XGMAC_RXQ_CTRL3 0x000000ac
|
||||
#define XGMAC_PSRQ(x) GENMASK((x) * 8 + 7, (x) * 8)
|
||||
#define XGMAC_PSRQ_SHIFT(x) ((x) * 8)
|
||||
#define XGMAC_INT_STATUS 0x000000b0
|
||||
#define XGMAC_LPIIS BIT(5)
|
||||
#define XGMAC_PMTIS BIT(4)
|
||||
#define XGMAC_INT_EN 0x000000b4
|
||||
#define XGMAC_TSIE BIT(12)
|
||||
#define XGMAC_LPIIE BIT(5)
|
||||
#define XGMAC_PMTIE BIT(4)
|
||||
#define XGMAC_INT_DEFAULT_EN (XGMAC_LPIIE | XGMAC_PMTIE)
|
||||
#define XGMAC_Qx_TX_FLOW_CTRL(x) (0x00000070 + (x) * 4)
|
||||
#define XGMAC_PT GENMASK(31, 16)
|
||||
#define XGMAC_PT_SHIFT 16
|
||||
#define XGMAC_TFE BIT(1)
|
||||
#define XGMAC_RX_FLOW_CTRL 0x00000090
|
||||
#define XGMAC_RFE BIT(0)
|
||||
#define XGMAC_PMT 0x000000c0
|
||||
#define XGMAC_GLBLUCAST BIT(9)
|
||||
#define XGMAC_RWKPKTEN BIT(2)
|
||||
#define XGMAC_MGKPKTEN BIT(1)
|
||||
#define XGMAC_PWRDWN BIT(0)
|
||||
#define XGMAC_LPI_CTRL 0x000000d0
|
||||
#define XGMAC_TXCGE BIT(21)
|
||||
#define XGMAC_LPITXA BIT(19)
|
||||
#define XGMAC_PLS BIT(17)
|
||||
#define XGMAC_LPITXEN BIT(16)
|
||||
#define XGMAC_RLPIEX BIT(3)
|
||||
#define XGMAC_RLPIEN BIT(2)
|
||||
#define XGMAC_TLPIEX BIT(1)
|
||||
#define XGMAC_TLPIEN BIT(0)
|
||||
#define XGMAC_LPI_TIMER_CTRL 0x000000d4
|
||||
#define XGMAC_HW_FEATURE0 0x0000011c
|
||||
#define XGMAC_HWFEAT_EDMA BIT(31)
|
||||
#define XGMAC_HWFEAT_EDIFFC BIT(30)
|
||||
#define XGMAC_HWFEAT_VXN BIT(29)
|
||||
#define XGMAC_HWFEAT_SAVLANINS BIT(27)
|
||||
#define XGMAC_HWFEAT_TSSTSSEL GENMASK(26, 25)
|
||||
#define XGMAC_HWFEAT_ADDMACADRSEL GENMASK(22, 18)
|
||||
#define XGMAC_HWFEAT_RXCOESEL BIT(16)
|
||||
#define XGMAC_HWFEAT_TXCOESEL BIT(14)
|
||||
#define XGMAC_HWFEAT_EEESEL BIT(13)
|
||||
#define XGMAC_HWFEAT_TSSEL BIT(12)
|
||||
#define XGMAC_HWFEAT_AVSEL BIT(11)
|
||||
#define XGMAC_HWFEAT_RAVSEL BIT(10)
|
||||
#define XGMAC_HWFEAT_ARPOFFSEL BIT(9)
|
||||
#define XGMAC_HWFEAT_MMCSEL BIT(8)
|
||||
#define XGMAC_HWFEAT_MGKSEL BIT(7)
|
||||
#define XGMAC_HWFEAT_RWKSEL BIT(6)
|
||||
#define XGMAC_HWFEAT_SMASEL BIT(5)
|
||||
#define XGMAC_HWFEAT_VLHASH BIT(4)
|
||||
#define XGMAC_HWFEAT_HDSEL BIT(3)
|
||||
#define XGMAC_HWFEAT_GMIISEL BIT(1)
|
||||
#define XGMAC_HW_FEATURE1 0x00000120
|
||||
#define XGMAC_HWFEAT_L3L4FNUM GENMASK(30, 27)
|
||||
#define XGMAC_HWFEAT_HASHTBLSZ GENMASK(25, 24)
|
||||
#define XGMAC_HWFEAT_NUMTC GENMASK(23, 21)
|
||||
#define XGMAC_HWFEAT_RSSEN BIT(20)
|
||||
#define XGMAC_HWFEAT_DBGMEMA BIT(19)
|
||||
#define XGMAC_HWFEAT_TSOEN BIT(18)
|
||||
#define XGMAC_HWFEAT_SPHEN BIT(17)
|
||||
#define XGMAC_HWFEAT_DCBEN BIT(16)
|
||||
#define XGMAC_HWFEAT_ADDR64 GENMASK(15, 14)
|
||||
#define XGMAC_HWFEAT_ADVTHWORD BIT(13)
|
||||
#define XGMAC_HWFEAT_PTOEN BIT(12)
|
||||
#define XGMAC_HWFEAT_OSTEN BIT(11)
|
||||
#define XGMAC_HWFEAT_TXFIFOSIZE GENMASK(10, 6)
|
||||
#define XGMAC_HWFEAT_PFCEN BIT(5)
|
||||
#define XGMAC_HWFEAT_RXFIFOSIZE GENMASK(4, 0)
|
||||
#define XGMAC_HW_FEATURE2 0x00000124
|
||||
#define XGMAC_HWFEAT_AUXSNAPNUM GENMASK(30, 28)
|
||||
#define XGMAC_HWFEAT_PPSOUTNUM GENMASK(26, 24)
|
||||
#define XGMAC_HWFEAT_TXCHCNT GENMASK(21, 18)
|
||||
#define XGMAC_HWFEAT_RXCHCNT GENMASK(15, 12)
|
||||
#define XGMAC_HWFEAT_TXQCNT GENMASK(9, 6)
|
||||
#define XGMAC_HWFEAT_RXQCNT GENMASK(3, 0)
|
||||
#define XGMAC_HW_FEATURE3 0x00000128
|
||||
#define XGMAC_HWFEAT_TBSCH GENMASK(31, 28)
|
||||
#define XGMAC_HWFEAT_TBSSEL BIT(27)
|
||||
#define XGMAC_HWFEAT_FPESEL BIT(26)
|
||||
#define XGMAC_HWFEAT_SGFSEL BIT(25)
|
||||
#define XGMAC_HWFEAT_ESTWID GENMASK(24, 23)
|
||||
#define XGMAC_HWFEAT_ESTDEP GENMASK(22, 20)
|
||||
#define XGMAC_HWFEAT_ESTSEL BIT(19)
|
||||
#define XGMAC_HWFEAT_TTSFD GENMASK(18, 16)
|
||||
#define XGMAC_HWFEAT_ASP GENMASK(15, 14)
|
||||
#define XGMAC_HWFEAT_DVLAN BIT(13)
|
||||
#define XGMAC_HWFEAT_FRPES GENMASK(12, 11)
|
||||
#define XGMAC_HWFEAT_FRPPB GENMASK(10, 9)
|
||||
#define XGMAC_HWFEAT_POUOST BIT(8)
|
||||
#define XGMAC_HWFEAT_FRPPIPE GENMASK(7, 5)
|
||||
#define XGMAC_HWFEAT_CBTISEL BIT(4)
|
||||
#define XGMAC_HWFEAT_FRPSEL BIT(3)
|
||||
#define XGMAC_HWFEAT_NRVF GENMASK(2, 0)
|
||||
#define XGMAC_HW_FEATURE4 0x0000012c
|
||||
#define XGMAC_HWFEAT_EASP BIT(4)
|
||||
#define XGMAC_HWFEAT_PCSEL GENMASK(1, 0)
|
||||
#define XGMAC_MAC_DPP_FSM_INT_STATUS 0x00000150
|
||||
#define XGMAC_MAC_FSM_CONTROL 0x00000158
|
||||
#define XGMAC_PRTYEN BIT(1)
|
||||
#define XGMAC_TMOUTEN BIT(0)
|
||||
#define XGMAC_MDIO_ADDR 0x00000200
|
||||
#define XGMAC_MDIO_DATA 0x00000204
|
||||
#define XGMAC_MDIO_C22P 0x00000220
|
||||
#define XGMAC_FPE_CTRL_STS 0x00000280
|
||||
#define XGMAC_EFPE BIT(0)
|
||||
#define XGMAC_ADDRx_HIGH(x) (0x00000300 + (x) * 0x8)
|
||||
#define XGMAC_ADDR_MAX 32
|
||||
#define XGMAC_AE BIT(31)
|
||||
#define XGMAC_DCS GENMASK(19, 16)
|
||||
#define XGMAC_DCS_SHIFT 16
|
||||
#define XGMAC_ADDRx_LOW(x) (0x00000304 + (x) * 0x8)
|
||||
#define XGMAC_L3L4_ADDR_CTRL 0x00000c00
|
||||
#define XGMAC_IDDR GENMASK(16, 8)
|
||||
#define XGMAC_IDDR_SHIFT 8
|
||||
#define XGMAC_IDDR_FNUM 4
|
||||
#define XGMAC_TT BIT(1)
|
||||
#define XGMAC_XB BIT(0)
|
||||
#define XGMAC_L3L4_DATA 0x00000c04
|
||||
#define XGMAC_L3L4_CTRL 0x0
|
||||
#define XGMAC_L4DPIM0 BIT(21)
|
||||
#define XGMAC_L4DPM0 BIT(20)
|
||||
#define XGMAC_L4SPIM0 BIT(19)
|
||||
#define XGMAC_L4SPM0 BIT(18)
|
||||
#define XGMAC_L4PEN0 BIT(16)
|
||||
#define XGMAC_L3HDBM0 GENMASK(15, 11)
|
||||
#define XGMAC_L3HSBM0 GENMASK(10, 6)
|
||||
#define XGMAC_L3DAIM0 BIT(5)
|
||||
#define XGMAC_L3DAM0 BIT(4)
|
||||
#define XGMAC_L3SAIM0 BIT(3)
|
||||
#define XGMAC_L3SAM0 BIT(2)
|
||||
#define XGMAC_L3PEN0 BIT(0)
|
||||
#define XGMAC_L4_ADDR 0x1
|
||||
#define XGMAC_L4DP0 GENMASK(31, 16)
|
||||
#define XGMAC_L4DP0_SHIFT 16
|
||||
#define XGMAC_L4SP0 GENMASK(15, 0)
|
||||
#define XGMAC_L3_ADDR0 0x4
|
||||
#define XGMAC_L3_ADDR1 0x5
|
||||
#define XGMAC_L3_ADDR2 0x6
|
||||
#define XMGAC_L3_ADDR3 0x7
|
||||
#define XGMAC_ARP_ADDR 0x00000c10
|
||||
#define XGMAC_RSS_CTRL 0x00000c80
|
||||
#define XGMAC_UDP4TE BIT(3)
|
||||
#define XGMAC_TCP4TE BIT(2)
|
||||
#define XGMAC_IP2TE BIT(1)
|
||||
#define XGMAC_RSSE BIT(0)
|
||||
#define XGMAC_RSS_ADDR 0x00000c88
|
||||
#define XGMAC_RSSIA_SHIFT 8
|
||||
#define XGMAC_ADDRT BIT(2)
|
||||
#define XGMAC_CT BIT(1)
|
||||
#define XGMAC_OB BIT(0)
|
||||
#define XGMAC_RSS_DATA 0x00000c8c
|
||||
#define XGMAC_TIMESTAMP_STATUS 0x00000d20
|
||||
#define XGMAC_TXTSC BIT(15)
|
||||
#define XGMAC_TXTIMESTAMP_NSEC 0x00000d30
|
||||
#define XGMAC_TXTSSTSLO GENMASK(30, 0)
|
||||
#define XGMAC_TXTIMESTAMP_SEC 0x00000d34
|
||||
#define XGMAC_PPS_CONTROL 0x00000d70
|
||||
#define XGMAC_PPS_MAXIDX(x) ((((x) + 1) * 8) - 1)
|
||||
#define XGMAC_PPS_MINIDX(x) ((x) * 8)
|
||||
#define XGMAC_PPSx_MASK(x) \
|
||||
GENMASK(XGMAC_PPS_MAXIDX(x), XGMAC_PPS_MINIDX(x))
|
||||
#define XGMAC_TRGTMODSELx(x, val) \
|
||||
GENMASK(XGMAC_PPS_MAXIDX(x) - 1, XGMAC_PPS_MAXIDX(x) - 2) & \
|
||||
((val) << (XGMAC_PPS_MAXIDX(x) - 2))
|
||||
#define XGMAC_PPSCMDx(x, val) \
|
||||
GENMASK(XGMAC_PPS_MINIDX(x) + 3, XGMAC_PPS_MINIDX(x)) & \
|
||||
((val) << XGMAC_PPS_MINIDX(x))
|
||||
#define XGMAC_PPSCMD_START 0x2
|
||||
#define XGMAC_PPSCMD_STOP 0x5
|
||||
#define XGMAC_PPSENx(x) BIT(4 + (x) * 8)
|
||||
#define XGMAC_PPSx_TARGET_TIME_SEC(x) (0x00000d80 + (x) * 0x10)
|
||||
#define XGMAC_PPSx_TARGET_TIME_NSEC(x) (0x00000d84 + (x) * 0x10)
|
||||
#define XGMAC_TRGTBUSY0 BIT(31)
|
||||
#define XGMAC_PPSx_INTERVAL(x) (0x00000d88 + (x) * 0x10)
|
||||
#define XGMAC_PPSx_WIDTH(x) (0x00000d8c + (x) * 0x10)
|
||||
|
||||
/* MTL Registers */
|
||||
#define XGMAC_MTL_OPMODE 0x00001000
|
||||
#define XGMAC_FRPE BIT(15)
|
||||
#define XGMAC_ETSALG GENMASK(6, 5)
|
||||
#define XGMAC_WRR (0x0 << 5)
|
||||
#define XGMAC_WFQ (0x1 << 5)
|
||||
#define XGMAC_DWRR (0x2 << 5)
|
||||
#define XGMAC_RAA BIT(2)
|
||||
#define XGMAC_MTL_INT_STATUS 0x00001020
|
||||
#define XGMAC_MTL_RXQ_DMA_MAP0 0x00001030
|
||||
#define XGMAC_MTL_RXQ_DMA_MAP1 0x00001034
|
||||
#define XGMAC_QxMDMACH(x) GENMASK((x) * 8 + 7, (x) * 8)
|
||||
#define XGMAC_QxMDMACH_SHIFT(x) ((x) * 8)
|
||||
#define XGMAC_QDDMACH BIT(7)
|
||||
#define XGMAC_TC_PRTY_MAP0 0x00001040
|
||||
#define XGMAC_TC_PRTY_MAP1 0x00001044
|
||||
#define XGMAC_PSTC(x) GENMASK((x) * 8 + 7, (x) * 8)
|
||||
#define XGMAC_PSTC_SHIFT(x) ((x) * 8)
|
||||
#define XGMAC_MTL_RXP_CONTROL_STATUS 0x000010a0
|
||||
#define XGMAC_RXPI BIT(31)
|
||||
#define XGMAC_NPE GENMASK(23, 16)
|
||||
#define XGMAC_NVE GENMASK(7, 0)
|
||||
#define XGMAC_MTL_RXP_IACC_CTRL_ST 0x000010b0
|
||||
#define XGMAC_STARTBUSY BIT(31)
|
||||
#define XGMAC_WRRDN BIT(16)
|
||||
#define XGMAC_ADDR GENMASK(9, 0)
|
||||
#define XGMAC_MTL_RXP_IACC_DATA 0x000010b4
|
||||
#define XGMAC_MTL_ECC_CONTROL 0x000010c0
|
||||
#define XGMAC_MTL_SAFETY_INT_STATUS 0x000010c4
|
||||
#define XGMAC_MEUIS BIT(1)
|
||||
#define XGMAC_MECIS BIT(0)
|
||||
#define XGMAC_MTL_ECC_INT_ENABLE 0x000010c8
|
||||
#define XGMAC_RPCEIE BIT(12)
|
||||
#define XGMAC_ECEIE BIT(8)
|
||||
#define XGMAC_RXCEIE BIT(4)
|
||||
#define XGMAC_TXCEIE BIT(0)
|
||||
#define XGMAC_MTL_ECC_INT_STATUS 0x000010cc
|
||||
#define XGMAC_MTL_DPP_CONTROL 0x000010e0
|
||||
#define XGMAC_DPP_DISABLE BIT(0)
|
||||
#define XGMAC_MTL_TXQ_OPMODE(x) (0x00001100 + (0x80 * (x)))
|
||||
#define XGMAC_TQS GENMASK(25, 16)
|
||||
#define XGMAC_TQS_SHIFT 16
|
||||
#define XGMAC_Q2TCMAP GENMASK(10, 8)
|
||||
#define XGMAC_Q2TCMAP_SHIFT 8
|
||||
#define XGMAC_TTC GENMASK(6, 4)
|
||||
#define XGMAC_TTC_SHIFT 4
|
||||
#define XGMAC_TXQEN GENMASK(3, 2)
|
||||
#define XGMAC_TXQEN_SHIFT 2
|
||||
#define XGMAC_TSF BIT(1)
|
||||
#define XGMAC_MTL_TCx_ETS_CONTROL(x) (0x00001110 + (0x80 * (x)))
|
||||
#define XGMAC_MTL_TCx_QUANTUM_WEIGHT(x) (0x00001118 + (0x80 * (x)))
|
||||
#define XGMAC_MTL_TCx_SENDSLOPE(x) (0x0000111c + (0x80 * (x)))
|
||||
#define XGMAC_MTL_TCx_HICREDIT(x) (0x00001120 + (0x80 * (x)))
|
||||
#define XGMAC_MTL_TCx_LOCREDIT(x) (0x00001124 + (0x80 * (x)))
|
||||
#define XGMAC_CC BIT(3)
|
||||
#define XGMAC_TSA GENMASK(1, 0)
|
||||
#define XGMAC_SP (0x0 << 0)
|
||||
#define XGMAC_CBS (0x1 << 0)
|
||||
#define XGMAC_ETS (0x2 << 0)
|
||||
#define XGMAC_MTL_RXQ_OPMODE(x) (0x00001140 + (0x80 * (x)))
|
||||
#define XGMAC_RQS GENMASK(25, 16)
|
||||
#define XGMAC_RQS_SHIFT 16
|
||||
#define XGMAC_EHFC BIT(7)
|
||||
#define XGMAC_RSF BIT(5)
|
||||
#define XGMAC_RTC GENMASK(1, 0)
|
||||
#define XGMAC_RTC_SHIFT 0
|
||||
#define XGMAC_MTL_RXQ_FLOW_CONTROL(x) (0x00001150 + (0x80 * (x)))
|
||||
#define XGMAC_RFD GENMASK(31, 17)
|
||||
#define XGMAC_RFD_SHIFT 17
|
||||
#define XGMAC_RFA GENMASK(15, 1)
|
||||
#define XGMAC_RFA_SHIFT 1
|
||||
#define XGMAC_MTL_QINTEN(x) (0x00001170 + (0x80 * (x)))
|
||||
#define XGMAC_RXOIE BIT(16)
|
||||
#define XGMAC_MTL_QINT_STATUS(x) (0x00001174 + (0x80 * (x)))
|
||||
#define XGMAC_RXOVFIS BIT(16)
|
||||
#define XGMAC_ABPSIS BIT(1)
|
||||
#define XGMAC_TXUNFIS BIT(0)
|
||||
#define XGMAC_MAC_REGSIZE (XGMAC_MTL_QINT_STATUS(15) / 4)
|
||||
|
||||
/* DMA Registers */
|
||||
#define XGMAC_DMA_MODE 0x00003000
|
||||
#define XGMAC_SWR BIT(0)
|
||||
#define XGMAC_DMA_SYSBUS_MODE 0x00003004
|
||||
#define XGMAC_WR_OSR_LMT GENMASK(29, 24)
|
||||
#define XGMAC_WR_OSR_LMT_SHIFT 24
|
||||
#define XGMAC_RD_OSR_LMT GENMASK(21, 16)
|
||||
#define XGMAC_RD_OSR_LMT_SHIFT 16
|
||||
#define XGMAC_EN_LPI BIT(15)
|
||||
#define XGMAC_LPI_XIT_PKT BIT(14)
|
||||
#define XGMAC_AAL BIT(12)
|
||||
#define XGMAC_EAME BIT(11)
|
||||
#define XGMAC_BLEN GENMASK(7, 1)
|
||||
#define XGMAC_BLEN256 BIT(7)
|
||||
#define XGMAC_BLEN128 BIT(6)
|
||||
#define XGMAC_BLEN64 BIT(5)
|
||||
#define XGMAC_BLEN32 BIT(4)
|
||||
#define XGMAC_BLEN16 BIT(3)
|
||||
#define XGMAC_BLEN8 BIT(2)
|
||||
#define XGMAC_BLEN4 BIT(1)
|
||||
#define XGMAC_UNDEF BIT(0)
|
||||
#define XGMAC_TX_EDMA_CTRL 0x00003040
|
||||
#define XGMAC_TDPS GENMASK(29, 0)
|
||||
#define XGMAC_RX_EDMA_CTRL 0x00003044
|
||||
#define XGMAC_RDPS GENMASK(29, 0)
|
||||
#define XGMAC_DMA_TBS_CTRL0 0x00003054
|
||||
#define XGMAC_DMA_TBS_CTRL1 0x00003058
|
||||
#define XGMAC_DMA_TBS_CTRL2 0x0000305c
|
||||
#define XGMAC_DMA_TBS_CTRL3 0x00003060
|
||||
#define XGMAC_FTOS GENMASK(31, 8)
|
||||
#define XGMAC_FTOV BIT(0)
|
||||
#define XGMAC_DEF_FTOS (XGMAC_FTOS | XGMAC_FTOV)
|
||||
#define XGMAC_DMA_SAFETY_INT_STATUS 0x00003064
|
||||
#define XGMAC_MCSIS BIT(31)
|
||||
#define XGMAC_MSUIS BIT(29)
|
||||
#define XGMAC_MSCIS BIT(28)
|
||||
#define XGMAC_DEUIS BIT(1)
|
||||
#define XGMAC_DECIS BIT(0)
|
||||
#define XGMAC_DMA_ECC_INT_ENABLE 0x00003068
|
||||
#define XGMAC_DCEIE BIT(1)
|
||||
#define XGMAC_TCEIE BIT(0)
|
||||
#define XGMAC_DMA_ECC_INT_STATUS 0x0000306c
|
||||
#define XGMAC_DMA_DPP_INT_STATUS 0x00003074
|
||||
#define XGMAC_DMA_CH_CONTROL(x) (0x00003100 + (0x80 * (x)))
|
||||
#define XGMAC_SPH BIT(24)
|
||||
#define XGMAC_PBLx8 BIT(16)
|
||||
#define XGMAC_DMA_CH_TX_CONTROL(x) (0x00003104 + (0x80 * (x)))
|
||||
#define XGMAC_EDSE BIT(28)
|
||||
#define XGMAC_TxPBL GENMASK(21, 16)
|
||||
#define XGMAC_TxPBL_SHIFT 16
|
||||
#define XGMAC_TSE BIT(12)
|
||||
#define XGMAC_OSP BIT(4)
|
||||
#define XGMAC_TXST BIT(0)
|
||||
#define XGMAC_DMA_CH_RX_CONTROL(x) (0x00003108 + (0x80 * (x)))
|
||||
#define XGMAC_RxPBL GENMASK(21, 16)
|
||||
#define XGMAC_RxPBL_SHIFT 16
|
||||
#define XGMAC_RBSZ GENMASK(14, 1)
|
||||
#define XGMAC_RBSZ_SHIFT 1
|
||||
#define XGMAC_RXST BIT(0)
|
||||
#define XGMAC_DMA_CH_TxDESC_HADDR(x) (0x00003110 + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_TxDESC_LADDR(x) (0x00003114 + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_RxDESC_HADDR(x) (0x00003118 + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_RxDESC_LADDR(x) (0x0000311c + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_TxDESC_TAIL_LPTR(x) (0x00003124 + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_RxDESC_TAIL_LPTR(x) (0x0000312c + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_TxDESC_RING_LEN(x) (0x00003130 + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_RxDESC_RING_LEN(x) (0x00003134 + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_INT_EN(x) (0x00003138 + (0x80 * (x)))
|
||||
#define XGMAC_NIE BIT(15)
|
||||
#define XGMAC_AIE BIT(14)
|
||||
#define XGMAC_RBUE BIT(7)
|
||||
#define XGMAC_RIE BIT(6)
|
||||
#define XGMAC_TBUE BIT(2)
|
||||
#define XGMAC_TIE BIT(0)
|
||||
#define XGMAC_DMA_INT_DEFAULT_EN (XGMAC_NIE | XGMAC_AIE | XGMAC_RBUE | \
|
||||
XGMAC_RIE | XGMAC_TIE)
|
||||
#define XGMAC_DMA_INT_DEFAULT_RX (XGMAC_RBUE | XGMAC_RIE)
|
||||
#define XGMAC_DMA_INT_DEFAULT_TX (XGMAC_TIE)
|
||||
#define XGMAC_DMA_CH_Rx_WATCHDOG(x) (0x0000313c + (0x80 * (x)))
|
||||
#define XGMAC_RWT GENMASK(7, 0)
|
||||
#define XGMAC_DMA_CH_STATUS(x) (0x00003160 + (0x80 * (x)))
|
||||
#define XGMAC_NIS BIT(15)
|
||||
#define XGMAC_AIS BIT(14)
|
||||
#define XGMAC_FBE BIT(12)
|
||||
#define XGMAC_RBU BIT(7)
|
||||
#define XGMAC_RI BIT(6)
|
||||
#define XGMAC_TBU BIT(2)
|
||||
#define XGMAC_TPS BIT(1)
|
||||
#define XGMAC_TI BIT(0)
|
||||
#define XGMAC_REGSIZE ((0x0000317c + (0x80 * 15)) / 4)
|
||||
|
||||
#define XGMAC_DMA_STATUS_MSK_COMMON (XGMAC_NIS | XGMAC_AIS | XGMAC_FBE)
|
||||
#define XGMAC_DMA_STATUS_MSK_RX (XGMAC_RBU | XGMAC_RI | \
|
||||
XGMAC_DMA_STATUS_MSK_COMMON)
|
||||
#define XGMAC_DMA_STATUS_MSK_TX (XGMAC_TBU | XGMAC_TPS | XGMAC_TI | \
|
||||
XGMAC_DMA_STATUS_MSK_COMMON)
|
||||
|
||||
/* Descriptors */
|
||||
#define XGMAC_TDES0_LTV BIT(31)
|
||||
#define XGMAC_TDES0_LT GENMASK(7, 0)
|
||||
#define XGMAC_TDES1_LT GENMASK(31, 8)
|
||||
#define XGMAC_TDES2_IVT GENMASK(31, 16)
|
||||
#define XGMAC_TDES2_IVT_SHIFT 16
|
||||
#define XGMAC_TDES2_IOC BIT(31)
|
||||
#define XGMAC_TDES2_TTSE BIT(30)
|
||||
#define XGMAC_TDES2_B2L GENMASK(29, 16)
|
||||
#define XGMAC_TDES2_B2L_SHIFT 16
|
||||
#define XGMAC_TDES2_VTIR GENMASK(15, 14)
|
||||
#define XGMAC_TDES2_VTIR_SHIFT 14
|
||||
#define XGMAC_TDES2_B1L GENMASK(13, 0)
|
||||
#define XGMAC_TDES3_OWN BIT(31)
|
||||
#define XGMAC_TDES3_CTXT BIT(30)
|
||||
#define XGMAC_TDES3_FD BIT(29)
|
||||
#define XGMAC_TDES3_LD BIT(28)
|
||||
#define XGMAC_TDES3_CPC GENMASK(27, 26)
|
||||
#define XGMAC_TDES3_CPC_SHIFT 26
|
||||
#define XGMAC_TDES3_TCMSSV BIT(26)
|
||||
#define XGMAC_TDES3_SAIC GENMASK(25, 23)
|
||||
#define XGMAC_TDES3_SAIC_SHIFT 23
|
||||
#define XGMAC_TDES3_TBSV BIT(24)
|
||||
#define XGMAC_TDES3_THL GENMASK(22, 19)
|
||||
#define XGMAC_TDES3_THL_SHIFT 19
|
||||
#define XGMAC_TDES3_IVTIR GENMASK(19, 18)
|
||||
#define XGMAC_TDES3_IVTIR_SHIFT 18
|
||||
#define XGMAC_TDES3_TSE BIT(18)
|
||||
#define XGMAC_TDES3_IVLTV BIT(17)
|
||||
#define XGMAC_TDES3_CIC GENMASK(17, 16)
|
||||
#define XGMAC_TDES3_CIC_SHIFT 16
|
||||
#define XGMAC_TDES3_TPL GENMASK(17, 0)
|
||||
#define XGMAC_TDES3_VLTV BIT(16)
|
||||
#define XGMAC_TDES3_VT GENMASK(15, 0)
|
||||
#define XGMAC_TDES3_FL GENMASK(14, 0)
|
||||
#define XGMAC_RDES2_HL GENMASK(9, 0)
|
||||
#define XGMAC_RDES3_OWN BIT(31)
|
||||
#define XGMAC_RDES3_CTXT BIT(30)
|
||||
#define XGMAC_RDES3_IOC BIT(30)
|
||||
#define XGMAC_RDES3_LD BIT(28)
|
||||
#define XGMAC_RDES3_CDA BIT(27)
|
||||
#define XGMAC_RDES3_RSV BIT(26)
|
||||
#define XGMAC_RDES3_L34T GENMASK(23, 20)
|
||||
#define XGMAC_RDES3_L34T_SHIFT 20
|
||||
#define XGMAC_L34T_IP4TCP 0x1
|
||||
#define XGMAC_L34T_IP4UDP 0x2
|
||||
#define XGMAC_L34T_IP6TCP 0x9
|
||||
#define XGMAC_L34T_IP6UDP 0xA
|
||||
#define XGMAC_RDES3_ES BIT(15)
|
||||
#define XGMAC_RDES3_PL GENMASK(13, 0)
|
||||
#define XGMAC_RDES3_TSD BIT(6)
|
||||
#define XGMAC_RDES3_TSA BIT(4)
|
||||
|
||||
#endif /* __STMMAC_DWXGMAC2_H__ */
|
||||
|
|
@ -0,0 +1,498 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
|
||||
/*
|
||||
* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
|
||||
* stmmac XGMAC definitions.
|
||||
*/
|
||||
|
||||
#ifndef __STMMAC_DWXGMAC2_H__
|
||||
#define __STMMAC_DWXGMAC2_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* Misc */
|
||||
#define XGMAC_JUMBO_LEN 16368
|
||||
|
||||
/* MAC Registers */
|
||||
#define XGMAC_TX_CONFIG 0x00000000
|
||||
#define XGMAC_CONFIG_SS_OFF 29
|
||||
#define XGMAC_CONFIG_SS_MASK GENMASK(31, 29)
|
||||
#define XGMAC_CONFIG_SS_10000 (0x0 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SS_2500_GMII (0x2 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SS_1000_GMII (0x3 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SS_100_MII (0x4 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SS_5000 (0x5 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SS_2500 (0x6 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SS_10_MII (0x7 << XGMAC_CONFIG_SS_OFF)
|
||||
#define XGMAC_CONFIG_SARC GENMASK(22, 20)
|
||||
#define XGMAC_CONFIG_SARC_SHIFT 20
|
||||
#define XGMAC_CONFIG_JD BIT(16)
|
||||
#define XGMAC_CONFIG_TE BIT(0)
|
||||
#define XGMAC_CORE_INIT_TX (XGMAC_CONFIG_JD)
|
||||
#define XGMAC_RX_CONFIG 0x00000004
|
||||
#define XGMAC_CONFIG_ARPEN BIT(31)
|
||||
#define XGMAC_CONFIG_GPSL GENMASK(29, 16)
|
||||
#define XGMAC_CONFIG_GPSL_SHIFT 16
|
||||
#define XGMAC_CONFIG_HDSMS GENMASK(14, 12)
|
||||
#define XGMAC_CONFIG_HDSMS_SHIFT 12
|
||||
#define XGMAC_CONFIG_HDSMS_256 (0x2 << XGMAC_CONFIG_HDSMS_SHIFT)
|
||||
#define XGMAC_CONFIG_S2KP BIT(11)
|
||||
#define XGMAC_CONFIG_LM BIT(10)
|
||||
#define XGMAC_CONFIG_IPC BIT(9)
|
||||
#define XGMAC_CONFIG_JE BIT(8)
|
||||
#define XGMAC_CONFIG_WD BIT(7)
|
||||
#define XGMAC_CONFIG_GPSLCE BIT(6)
|
||||
#define XGMAC_CONFIG_CST BIT(2)
|
||||
#define XGMAC_CONFIG_ACS BIT(1)
|
||||
#define XGMAC_CONFIG_RE BIT(0)
|
||||
#define XGMAC_CORE_INIT_RX (XGMAC_CONFIG_GPSLCE | XGMAC_CONFIG_WD | \
|
||||
(XGMAC_JUMBO_LEN << XGMAC_CONFIG_GPSL_SHIFT))
|
||||
#define XGMAC_PACKET_FILTER 0x00000008
|
||||
#define XGMAC_FILTER_RA BIT(31)
|
||||
#define XGMAC_FILTER_IPFE BIT(20)
|
||||
#define XGMAC_FILTER_VTFE BIT(16)
|
||||
#define XGMAC_FILTER_HPF BIT(10)
|
||||
#define XGMAC_FILTER_PCF BIT(7)
|
||||
#define XGMAC_FILTER_PM BIT(4)
|
||||
#define XGMAC_FILTER_HMC BIT(2)
|
||||
#define XGMAC_FILTER_PR BIT(0)
|
||||
#define XGMAC_HASH_TABLE(x) (0x00000010 + (x) * 4)
|
||||
#define XGMAC_MAX_HASH_TABLE 8
|
||||
#define XGMAC_VLAN_TAG 0x00000050
|
||||
#define XGMAC_VLAN_EDVLP BIT(26)
|
||||
#define XGMAC_VLAN_VTHM BIT(25)
|
||||
#define XGMAC_VLAN_DOVLTC BIT(20)
|
||||
#define XGMAC_VLAN_ESVL BIT(18)
|
||||
#define XGMAC_VLAN_ETV BIT(16)
|
||||
#define XGMAC_VLAN_VID GENMASK(15, 0)
|
||||
#define XGMAC_VLAN_HASH_TABLE 0x00000058
|
||||
#define XGMAC_VLAN_INCL 0x00000060
|
||||
#define XGMAC_VLAN_VLTI BIT(20)
|
||||
#define XGMAC_VLAN_CSVL BIT(19)
|
||||
#define XGMAC_VLAN_VLC GENMASK(17, 16)
|
||||
#define XGMAC_VLAN_VLC_SHIFT 16
|
||||
#define XGMAC_RXQ_CTRL0 0x000000a0
|
||||
#define XGMAC_RXQEN(x) GENMASK((x) * 2 + 1, (x) * 2)
|
||||
#define XGMAC_RXQEN_SHIFT(x) ((x) * 2)
|
||||
#define XGMAC_RXQ_CTRL1 0x000000a4
|
||||
#define XGMAC_AVCPQ GENMASK(31, 28)
|
||||
#define XGMAC_AVCPQ_SHIFT 28
|
||||
#define XGMAC_PTPQ GENMASK(27, 24)
|
||||
#define XGMAC_PTPQ_SHIFT 24
|
||||
#define XGMAC_TACPQE BIT(23)
|
||||
#define XGMAC_DCBCPQ GENMASK(19, 16)
|
||||
#define XGMAC_DCBCPQ_SHIFT 16
|
||||
#define XGMAC_MCBCQEN BIT(15)
|
||||
#define XGMAC_MCBCQ GENMASK(11, 8)
|
||||
#define XGMAC_MCBCQ_SHIFT 8
|
||||
#define XGMAC_RQ GENMASK(7, 4)
|
||||
#define XGMAC_RQ_SHIFT 4
|
||||
#define XGMAC_UPQ GENMASK(3, 0)
|
||||
#define XGMAC_UPQ_SHIFT 0
|
||||
#define XGMAC_RXQ_CTRL2 0x000000a8
|
||||
#define XGMAC_RXQ_CTRL3 0x000000ac
|
||||
#define XGMAC_PSRQ(x) GENMASK((x) * 8 + 7, (x) * 8)
|
||||
#define XGMAC_PSRQ_SHIFT(x) ((x) * 8)
|
||||
#define XGMAC_INT_STATUS 0x000000b0
|
||||
#define XGMAC_LPIIS BIT(5)
|
||||
#define XGMAC_PMTIS BIT(4)
|
||||
#define XGMAC_INT_EN 0x000000b4
|
||||
#define XGMAC_TSIE BIT(12)
|
||||
#define XGMAC_LPIIE BIT(5)
|
||||
#define XGMAC_PMTIE BIT(4)
|
||||
#define XGMAC_INT_DEFAULT_EN (XGMAC_LPIIE | XGMAC_PMTIE)
|
||||
#define XGMAC_Qx_TX_FLOW_CTRL(x) (0x00000070 + (x) * 4)
|
||||
#define XGMAC_PT GENMASK(31, 16)
|
||||
#define XGMAC_PT_SHIFT 16
|
||||
#define XGMAC_TFE BIT(1)
|
||||
#define XGMAC_RX_FLOW_CTRL 0x00000090
|
||||
#define XGMAC_RFE BIT(0)
|
||||
#define XGMAC_PMT 0x000000c0
|
||||
#define XGMAC_GLBLUCAST BIT(9)
|
||||
#define XGMAC_RWKPKTEN BIT(2)
|
||||
#define XGMAC_MGKPKTEN BIT(1)
|
||||
#define XGMAC_PWRDWN BIT(0)
|
||||
#define XGMAC_LPI_CTRL 0x000000d0
|
||||
#define XGMAC_TXCGE BIT(21)
|
||||
#define XGMAC_LPITXA BIT(19)
|
||||
#define XGMAC_PLS BIT(17)
|
||||
#define XGMAC_LPITXEN BIT(16)
|
||||
#define XGMAC_RLPIEX BIT(3)
|
||||
#define XGMAC_RLPIEN BIT(2)
|
||||
#define XGMAC_TLPIEX BIT(1)
|
||||
#define XGMAC_TLPIEN BIT(0)
|
||||
#define XGMAC_LPI_TIMER_CTRL 0x000000d4
|
||||
#define XGMAC_HW_FEATURE0 0x0000011c
|
||||
#define XGMAC_HWFEAT_EDMA BIT(31)
|
||||
#define XGMAC_HWFEAT_EDIFFC BIT(30)
|
||||
#define XGMAC_HWFEAT_VXN BIT(29)
|
||||
#define XGMAC_HWFEAT_SAVLANINS BIT(27)
|
||||
#define XGMAC_HWFEAT_TSSTSSEL GENMASK(26, 25)
|
||||
#define XGMAC_HWFEAT_ADDMACADRSEL GENMASK(22, 18)
|
||||
#define XGMAC_HWFEAT_RXCOESEL BIT(16)
|
||||
#define XGMAC_HWFEAT_TXCOESEL BIT(14)
|
||||
#define XGMAC_HWFEAT_EEESEL BIT(13)
|
||||
#define XGMAC_HWFEAT_TSSEL BIT(12)
|
||||
#define XGMAC_HWFEAT_AVSEL BIT(11)
|
||||
#define XGMAC_HWFEAT_RAVSEL BIT(10)
|
||||
#define XGMAC_HWFEAT_ARPOFFSEL BIT(9)
|
||||
#define XGMAC_HWFEAT_MMCSEL BIT(8)
|
||||
#define XGMAC_HWFEAT_MGKSEL BIT(7)
|
||||
#define XGMAC_HWFEAT_RWKSEL BIT(6)
|
||||
#define XGMAC_HWFEAT_SMASEL BIT(5)
|
||||
#define XGMAC_HWFEAT_VLHASH BIT(4)
|
||||
#define XGMAC_HWFEAT_HDSEL BIT(3)
|
||||
#define XGMAC_HWFEAT_GMIISEL BIT(1)
|
||||
#define XGMAC_HW_FEATURE1 0x00000120
|
||||
#define XGMAC_HWFEAT_L3L4FNUM GENMASK(30, 27)
|
||||
#define XGMAC_HWFEAT_HASHTBLSZ GENMASK(25, 24)
|
||||
#define XGMAC_HWFEAT_NUMTC GENMASK(23, 21)
|
||||
#define XGMAC_HWFEAT_RSSEN BIT(20)
|
||||
#define XGMAC_HWFEAT_DBGMEMA BIT(19)
|
||||
#define XGMAC_HWFEAT_TSOEN BIT(18)
|
||||
#define XGMAC_HWFEAT_SPHEN BIT(17)
|
||||
#define XGMAC_HWFEAT_DCBEN BIT(16)
|
||||
#define XGMAC_HWFEAT_ADDR64 GENMASK(15, 14)
|
||||
#define XGMAC_HWFEAT_ADVTHWORD BIT(13)
|
||||
#define XGMAC_HWFEAT_PTOEN BIT(12)
|
||||
#define XGMAC_HWFEAT_OSTEN BIT(11)
|
||||
#define XGMAC_HWFEAT_TXFIFOSIZE GENMASK(10, 6)
|
||||
#define XGMAC_HWFEAT_PFCEN BIT(5)
|
||||
#define XGMAC_HWFEAT_RXFIFOSIZE GENMASK(4, 0)
|
||||
#define XGMAC_HW_FEATURE2 0x00000124
|
||||
#define XGMAC_HWFEAT_AUXSNAPNUM GENMASK(30, 28)
|
||||
#define XGMAC_HWFEAT_PPSOUTNUM GENMASK(26, 24)
|
||||
#define XGMAC_HWFEAT_TXCHCNT GENMASK(21, 18)
|
||||
#define XGMAC_HWFEAT_RXCHCNT GENMASK(15, 12)
|
||||
#define XGMAC_HWFEAT_TXQCNT GENMASK(9, 6)
|
||||
#define XGMAC_HWFEAT_RXQCNT GENMASK(3, 0)
|
||||
#define XGMAC_HW_FEATURE3 0x00000128
|
||||
#define XGMAC_HWFEAT_TBSCH GENMASK(31, 28)
|
||||
#define XGMAC_HWFEAT_TBSSEL BIT(27)
|
||||
#define XGMAC_HWFEAT_FPESEL BIT(26)
|
||||
#define XGMAC_HWFEAT_SGFSEL BIT(25)
|
||||
#define XGMAC_HWFEAT_ESTWID GENMASK(24, 23)
|
||||
#define XGMAC_HWFEAT_ESTDEP GENMASK(22, 20)
|
||||
#define XGMAC_HWFEAT_ESTSEL BIT(19)
|
||||
#define XGMAC_HWFEAT_TTSFD GENMASK(18, 16)
|
||||
#define XGMAC_HWFEAT_ASP GENMASK(15, 14)
|
||||
#define XGMAC_HWFEAT_DVLAN BIT(13)
|
||||
#define XGMAC_HWFEAT_FRPES GENMASK(12, 11)
|
||||
#define XGMAC_HWFEAT_FRPPB GENMASK(10, 9)
|
||||
#define XGMAC_HWFEAT_POUOST BIT(8)
|
||||
#define XGMAC_HWFEAT_FRPPIPE GENMASK(7, 5)
|
||||
#define XGMAC_HWFEAT_CBTISEL BIT(4)
|
||||
#define XGMAC_HWFEAT_FRPSEL BIT(3)
|
||||
#define XGMAC_HWFEAT_NRVF GENMASK(2, 0)
|
||||
#define XGMAC_HW_FEATURE4 0x0000012c
|
||||
#define XGMAC_HWFEAT_EASP BIT(4)
|
||||
#define XGMAC_HWFEAT_PCSEL GENMASK(1, 0)
|
||||
#define XGMAC_MAC_DPP_FSM_INT_STATUS 0x00000150
|
||||
#define XGMAC_MAC_FSM_CONTROL 0x00000158
|
||||
#define XGMAC_PRTYEN BIT(1)
|
||||
#define XGMAC_TMOUTEN BIT(0)
|
||||
#define XGMAC_MDIO_ADDR 0x00000200
|
||||
#define XGMAC_MDIO_DATA 0x00000204
|
||||
#define XGMAC_MDIO_C22P 0x00000220
|
||||
#define XGMAC_FPE_CTRL_STS 0x00000280
|
||||
#define XGMAC_EFPE BIT(0)
|
||||
#define XGMAC_ADDRx_HIGH(x) (0x00000300 + (x) * 0x8)
|
||||
#define XGMAC_ADDR_MAX 32
|
||||
#define XGMAC_AE BIT(31)
|
||||
#define XGMAC_DCS GENMASK(19, 16)
|
||||
#define XGMAC_DCS_SHIFT 16
|
||||
#define XGMAC_ADDRx_LOW(x) (0x00000304 + (x) * 0x8)
|
||||
#define XGMAC_L3L4_ADDR_CTRL 0x00000c00
|
||||
#define XGMAC_IDDR GENMASK(16, 8)
|
||||
#define XGMAC_IDDR_SHIFT 8
|
||||
#define XGMAC_IDDR_FNUM 4
|
||||
#define XGMAC_TT BIT(1)
|
||||
#define XGMAC_XB BIT(0)
|
||||
#define XGMAC_L3L4_DATA 0x00000c04
|
||||
#define XGMAC_L3L4_CTRL 0x0
|
||||
#define XGMAC_L4DPIM0 BIT(21)
|
||||
#define XGMAC_L4DPM0 BIT(20)
|
||||
#define XGMAC_L4SPIM0 BIT(19)
|
||||
#define XGMAC_L4SPM0 BIT(18)
|
||||
#define XGMAC_L4PEN0 BIT(16)
|
||||
#define XGMAC_L3HDBM0 GENMASK(15, 11)
|
||||
#define XGMAC_L3HSBM0 GENMASK(10, 6)
|
||||
#define XGMAC_L3DAIM0 BIT(5)
|
||||
#define XGMAC_L3DAM0 BIT(4)
|
||||
#define XGMAC_L3SAIM0 BIT(3)
|
||||
#define XGMAC_L3SAM0 BIT(2)
|
||||
#define XGMAC_L3PEN0 BIT(0)
|
||||
#define XGMAC_L4_ADDR 0x1
|
||||
#define XGMAC_L4DP0 GENMASK(31, 16)
|
||||
#define XGMAC_L4DP0_SHIFT 16
|
||||
#define XGMAC_L4SP0 GENMASK(15, 0)
|
||||
#define XGMAC_L3_ADDR0 0x4
|
||||
#define XGMAC_L3_ADDR1 0x5
|
||||
#define XGMAC_L3_ADDR2 0x6
|
||||
#define XMGAC_L3_ADDR3 0x7
|
||||
#define XGMAC_ARP_ADDR 0x00000c10
|
||||
#define XGMAC_RSS_CTRL 0x00000c80
|
||||
#define XGMAC_UDP4TE BIT(3)
|
||||
#define XGMAC_TCP4TE BIT(2)
|
||||
#define XGMAC_IP2TE BIT(1)
|
||||
#define XGMAC_RSSE BIT(0)
|
||||
#define XGMAC_RSS_ADDR 0x00000c88
|
||||
#define XGMAC_RSSIA_SHIFT 8
|
||||
#define XGMAC_ADDRT BIT(2)
|
||||
#define XGMAC_CT BIT(1)
|
||||
#define XGMAC_OB BIT(0)
|
||||
#define XGMAC_RSS_DATA 0x00000c8c
|
||||
#define XGMAC_TIMESTAMP_STATUS 0x00000d20
|
||||
#define XGMAC_TXTSC BIT(15)
|
||||
#define XGMAC_TXTIMESTAMP_NSEC 0x00000d30
|
||||
#define XGMAC_TXTSSTSLO GENMASK(30, 0)
|
||||
#define XGMAC_TXTIMESTAMP_SEC 0x00000d34
|
||||
#define XGMAC_PPS_CONTROL 0x00000d70
|
||||
#define XGMAC_PPS_MAXIDX(x) ((((x) + 1) * 8) - 1)
|
||||
#define XGMAC_PPS_MINIDX(x) ((x) * 8)
|
||||
#define XGMAC_PPSx_MASK(x) \
|
||||
GENMASK(XGMAC_PPS_MAXIDX(x), XGMAC_PPS_MINIDX(x))
|
||||
#define XGMAC_TRGTMODSELx(x, val) \
|
||||
GENMASK(XGMAC_PPS_MAXIDX(x) - 1, XGMAC_PPS_MAXIDX(x) - 2) & \
|
||||
((val) << (XGMAC_PPS_MAXIDX(x) - 2))
|
||||
#define XGMAC_PPSCMDx(x, val) \
|
||||
GENMASK(XGMAC_PPS_MINIDX(x) + 3, XGMAC_PPS_MINIDX(x)) & \
|
||||
((val) << XGMAC_PPS_MINIDX(x))
|
||||
#define XGMAC_PPSCMD_START 0x2
|
||||
#define XGMAC_PPSCMD_STOP 0x5
|
||||
#define XGMAC_PPSENx(x) BIT(4 + (x) * 8)
|
||||
#define XGMAC_PPSx_TARGET_TIME_SEC(x) (0x00000d80 + (x) * 0x10)
|
||||
#define XGMAC_PPSx_TARGET_TIME_NSEC(x) (0x00000d84 + (x) * 0x10)
|
||||
#define XGMAC_TRGTBUSY0 BIT(31)
|
||||
#define XGMAC_PPSx_INTERVAL(x) (0x00000d88 + (x) * 0x10)
|
||||
#define XGMAC_PPSx_WIDTH(x) (0x00000d8c + (x) * 0x10)
|
||||
|
||||
/* MTL Registers */
|
||||
#define XGMAC_MTL_OPMODE 0x00001000
|
||||
#define XGMAC_FRPE BIT(15)
|
||||
#define XGMAC_ETSALG GENMASK(6, 5)
|
||||
#define XGMAC_WRR (0x0 << 5)
|
||||
#define XGMAC_WFQ (0x1 << 5)
|
||||
#define XGMAC_DWRR (0x2 << 5)
|
||||
#define XGMAC_RAA BIT(2)
|
||||
#define XGMAC_MTL_INT_STATUS 0x00001020
|
||||
#define XGMAC_MTL_RXQ_DMA_MAP0 0x00001030
|
||||
#define XGMAC_MTL_RXQ_DMA_MAP1 0x00001034
|
||||
#define XGMAC_QxMDMACH(x) GENMASK((x) * 8 + 7, (x) * 8)
|
||||
#define XGMAC_QxMDMACH_SHIFT(x) ((x) * 8)
|
||||
#define XGMAC_QDDMACH BIT(7)
|
||||
#define XGMAC_TC_PRTY_MAP0 0x00001040
|
||||
#define XGMAC_TC_PRTY_MAP1 0x00001044
|
||||
#define XGMAC_PSTC(x) GENMASK((x) * 8 + 7, (x) * 8)
|
||||
#define XGMAC_PSTC_SHIFT(x) ((x) * 8)
|
||||
#define XGMAC_MTL_RXP_CONTROL_STATUS 0x000010a0
|
||||
#define XGMAC_RXPI BIT(31)
|
||||
#define XGMAC_NPE GENMASK(23, 16)
|
||||
#define XGMAC_NVE GENMASK(7, 0)
|
||||
#define XGMAC_MTL_RXP_IACC_CTRL_ST 0x000010b0
|
||||
#define XGMAC_STARTBUSY BIT(31)
|
||||
#define XGMAC_WRRDN BIT(16)
|
||||
#define XGMAC_ADDR GENMASK(9, 0)
|
||||
#define XGMAC_MTL_RXP_IACC_DATA 0x000010b4
|
||||
#define XGMAC_MTL_ECC_CONTROL 0x000010c0
|
||||
#define XGMAC_MTL_SAFETY_INT_STATUS 0x000010c4
|
||||
#define XGMAC_MEUIS BIT(1)
|
||||
#define XGMAC_MECIS BIT(0)
|
||||
#define XGMAC_MTL_ECC_INT_ENABLE 0x000010c8
|
||||
#define XGMAC_RPCEIE BIT(12)
|
||||
#define XGMAC_ECEIE BIT(8)
|
||||
#define XGMAC_RXCEIE BIT(4)
|
||||
#define XGMAC_TXCEIE BIT(0)
|
||||
#define XGMAC_MTL_ECC_INT_STATUS 0x000010cc
|
||||
#define XGMAC_MTL_DPP_CONTROL 0x000010e0
|
||||
#define XGMAC_DPP_DISABLE BIT(0)
|
||||
#define XGMAC_MTL_TXQ_OPMODE(x) (0x00001100 + (0x80 * (x)))
|
||||
#define XGMAC_TQS GENMASK(25, 16)
|
||||
#define XGMAC_TQS_SHIFT 16
|
||||
#define XGMAC_Q2TCMAP GENMASK(10, 8)
|
||||
#define XGMAC_Q2TCMAP_SHIFT 8
|
||||
#define XGMAC_TTC GENMASK(6, 4)
|
||||
#define XGMAC_TTC_SHIFT 4
|
||||
#define XGMAC_TXQEN GENMASK(3, 2)
|
||||
#define XGMAC_TXQEN_SHIFT 2
|
||||
#define XGMAC_TSF BIT(1)
|
||||
#define XGMAC_MTL_TCx_ETS_CONTROL(x) (0x00001110 + (0x80 * (x)))
|
||||
#define XGMAC_MTL_TCx_QUANTUM_WEIGHT(x) (0x00001118 + (0x80 * (x)))
|
||||
#define XGMAC_MTL_TCx_SENDSLOPE(x) (0x0000111c + (0x80 * (x)))
|
||||
#define XGMAC_MTL_TCx_HICREDIT(x) (0x00001120 + (0x80 * (x)))
|
||||
#define XGMAC_MTL_TCx_LOCREDIT(x) (0x00001124 + (0x80 * (x)))
|
||||
#define XGMAC_CC BIT(3)
|
||||
#define XGMAC_TSA GENMASK(1, 0)
|
||||
#define XGMAC_SP (0x0 << 0)
|
||||
#define XGMAC_CBS (0x1 << 0)
|
||||
#define XGMAC_ETS (0x2 << 0)
|
||||
#define XGMAC_MTL_RXQ_OPMODE(x) (0x00001140 + (0x80 * (x)))
|
||||
#define XGMAC_RQS GENMASK(25, 16)
|
||||
#define XGMAC_RQS_SHIFT 16
|
||||
#define XGMAC_EHFC BIT(7)
|
||||
#define XGMAC_RSF BIT(5)
|
||||
#define XGMAC_RTC GENMASK(1, 0)
|
||||
#define XGMAC_RTC_SHIFT 0
|
||||
#define XGMAC_MTL_RXQ_FLOW_CONTROL(x) (0x00001150 + (0x80 * (x)))
|
||||
#define XGMAC_RFD GENMASK(31, 17)
|
||||
#define XGMAC_RFD_SHIFT 17
|
||||
#define XGMAC_RFA GENMASK(15, 1)
|
||||
#define XGMAC_RFA_SHIFT 1
|
||||
#define XGMAC_MTL_QINTEN(x) (0x00001170 + (0x80 * (x)))
|
||||
#define XGMAC_RXOIE BIT(16)
|
||||
#define XGMAC_MTL_QINT_STATUS(x) (0x00001174 + (0x80 * (x)))
|
||||
#define XGMAC_RXOVFIS BIT(16)
|
||||
#define XGMAC_ABPSIS BIT(1)
|
||||
#define XGMAC_TXUNFIS BIT(0)
|
||||
#define XGMAC_MAC_REGSIZE (XGMAC_MTL_QINT_STATUS(15) / 4)
|
||||
|
||||
/* DMA Registers */
|
||||
#define XGMAC_DMA_MODE 0x00003000
|
||||
#define XGMAC_SWR BIT(0)
|
||||
#define XGMAC_DMA_SYSBUS_MODE 0x00003004
|
||||
#define XGMAC_WR_OSR_LMT GENMASK(29, 24)
|
||||
#define XGMAC_WR_OSR_LMT_SHIFT 24
|
||||
#define XGMAC_RD_OSR_LMT GENMASK(21, 16)
|
||||
#define XGMAC_RD_OSR_LMT_SHIFT 16
|
||||
#define XGMAC_EN_LPI BIT(15)
|
||||
#define XGMAC_LPI_XIT_PKT BIT(14)
|
||||
#define XGMAC_AAL BIT(12)
|
||||
#define XGMAC_EAME BIT(11)
|
||||
#define XGMAC_BLEN GENMASK(7, 1)
|
||||
#define XGMAC_BLEN256 BIT(7)
|
||||
#define XGMAC_BLEN128 BIT(6)
|
||||
#define XGMAC_BLEN64 BIT(5)
|
||||
#define XGMAC_BLEN32 BIT(4)
|
||||
#define XGMAC_BLEN16 BIT(3)
|
||||
#define XGMAC_BLEN8 BIT(2)
|
||||
#define XGMAC_BLEN4 BIT(1)
|
||||
#define XGMAC_UNDEF BIT(0)
|
||||
#define XGMAC_TX_EDMA_CTRL 0x00003040
|
||||
#define XGMAC_TDPS GENMASK(29, 0)
|
||||
#define XGMAC_RX_EDMA_CTRL 0x00003044
|
||||
#define XGMAC_RDPS GENMASK(29, 0)
|
||||
#define XGMAC_DMA_TBS_CTRL0 0x00003054
|
||||
#define XGMAC_DMA_TBS_CTRL1 0x00003058
|
||||
#define XGMAC_DMA_TBS_CTRL2 0x0000305c
|
||||
#define XGMAC_DMA_TBS_CTRL3 0x00003060
|
||||
#define XGMAC_FTOS GENMASK(31, 8)
|
||||
#define XGMAC_FTOV BIT(0)
|
||||
#define XGMAC_DEF_FTOS (XGMAC_FTOS | XGMAC_FTOV)
|
||||
#define XGMAC_DMA_SAFETY_INT_STATUS 0x00003064
|
||||
#define XGMAC_MCSIS BIT(31)
|
||||
#define XGMAC_MSUIS BIT(29)
|
||||
#define XGMAC_MSCIS BIT(28)
|
||||
#define XGMAC_DEUIS BIT(1)
|
||||
#define XGMAC_DECIS BIT(0)
|
||||
#define XGMAC_DMA_ECC_INT_ENABLE 0x00003068
|
||||
#define XGMAC_DCEIE BIT(1)
|
||||
#define XGMAC_TCEIE BIT(0)
|
||||
#define XGMAC_DMA_ECC_INT_STATUS 0x0000306c
|
||||
#define XGMAC_DMA_DPP_INT_STATUS 0x00003074
|
||||
#define XGMAC_DMA_CH_CONTROL(x) (0x00003100 + (0x80 * (x)))
|
||||
#define XGMAC_SPH BIT(24)
|
||||
#define XGMAC_PBLx8 BIT(16)
|
||||
#define XGMAC_DMA_CH_TX_CONTROL(x) (0x00003104 + (0x80 * (x)))
|
||||
#define XGMAC_EDSE BIT(28)
|
||||
#define XGMAC_TxPBL GENMASK(21, 16)
|
||||
#define XGMAC_TxPBL_SHIFT 16
|
||||
#define XGMAC_TSE BIT(12)
|
||||
#define XGMAC_OSP BIT(4)
|
||||
#define XGMAC_TXST BIT(0)
|
||||
#define XGMAC_DMA_CH_RX_CONTROL(x) (0x00003108 + (0x80 * (x)))
|
||||
#define XGMAC_RxPBL GENMASK(21, 16)
|
||||
#define XGMAC_RxPBL_SHIFT 16
|
||||
#define XGMAC_RBSZ GENMASK(14, 1)
|
||||
#define XGMAC_RBSZ_SHIFT 1
|
||||
#define XGMAC_RXST BIT(0)
|
||||
#define XGMAC_DMA_CH_TxDESC_HADDR(x) (0x00003110 + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_TxDESC_LADDR(x) (0x00003114 + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_RxDESC_HADDR(x) (0x00003118 + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_RxDESC_LADDR(x) (0x0000311c + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_TxDESC_TAIL_LPTR(x) (0x00003124 + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_RxDESC_TAIL_LPTR(x) (0x0000312c + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_TxDESC_RING_LEN(x) (0x00003130 + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_RxDESC_RING_LEN(x) (0x00003134 + (0x80 * (x)))
|
||||
#define XGMAC_DMA_CH_INT_EN(x) (0x00003138 + (0x80 * (x)))
|
||||
#define XGMAC_NIE BIT(15)
|
||||
#define XGMAC_AIE BIT(14)
|
||||
#define XGMAC_RBUE BIT(7)
|
||||
#define XGMAC_RIE BIT(6)
|
||||
#define XGMAC_TBUE BIT(2)
|
||||
#define XGMAC_TIE BIT(0)
|
||||
#define XGMAC_DMA_INT_DEFAULT_EN (XGMAC_NIE | XGMAC_AIE | XGMAC_RBUE | \
|
||||
XGMAC_RIE | XGMAC_TIE)
|
||||
#define XGMAC_DMA_INT_DEFAULT_RX (XGMAC_RBUE | XGMAC_RIE)
|
||||
#define XGMAC_DMA_INT_DEFAULT_TX (XGMAC_TIE)
|
||||
#define XGMAC_DMA_CH_Rx_WATCHDOG(x) (0x0000313c + (0x80 * (x)))
|
||||
#define XGMAC_RWT GENMASK(7, 0)
|
||||
#define XGMAC_DMA_CH_STATUS(x) (0x00003160 + (0x80 * (x)))
|
||||
#define XGMAC_NIS BIT(15)
|
||||
#define XGMAC_AIS BIT(14)
|
||||
#define XGMAC_FBE BIT(12)
|
||||
#define XGMAC_RBU BIT(7)
|
||||
#define XGMAC_RI BIT(6)
|
||||
#define XGMAC_TBU BIT(2)
|
||||
#define XGMAC_TPS BIT(1)
|
||||
#define XGMAC_TI BIT(0)
|
||||
#define XGMAC_REGSIZE ((0x0000317c + (0x80 * 15)) / 4)
|
||||
|
||||
#define XGMAC_DMA_STATUS_MSK_COMMON (XGMAC_NIS | XGMAC_AIS | XGMAC_FBE)
|
||||
#define XGMAC_DMA_STATUS_MSK_RX (XGMAC_RBU | XGMAC_RI | \
|
||||
XGMAC_DMA_STATUS_MSK_COMMON)
|
||||
#define XGMAC_DMA_STATUS_MSK_TX (XGMAC_TBU | XGMAC_TPS | XGMAC_TI | \
|
||||
XGMAC_DMA_STATUS_MSK_COMMON)
|
||||
|
||||
/* Descriptors */
|
||||
#define XGMAC_TDES0_LTV BIT(31)
|
||||
#define XGMAC_TDES0_LT GENMASK(7, 0)
|
||||
#define XGMAC_TDES1_LT GENMASK(31, 8)
|
||||
#define XGMAC_TDES2_IVT GENMASK(31, 16)
|
||||
#define XGMAC_TDES2_IVT_SHIFT 16
|
||||
#define XGMAC_TDES2_IOC BIT(31)
|
||||
#define XGMAC_TDES2_TTSE BIT(30)
|
||||
#define XGMAC_TDES2_B2L GENMASK(29, 16)
|
||||
#define XGMAC_TDES2_B2L_SHIFT 16
|
||||
#define XGMAC_TDES2_VTIR GENMASK(15, 14)
|
||||
#define XGMAC_TDES2_VTIR_SHIFT 14
|
||||
#define XGMAC_TDES2_B1L GENMASK(13, 0)
|
||||
#define XGMAC_TDES3_OWN BIT(31)
|
||||
#define XGMAC_TDES3_CTXT BIT(30)
|
||||
#define XGMAC_TDES3_FD BIT(29)
|
||||
#define XGMAC_TDES3_LD BIT(28)
|
||||
#define XGMAC_TDES3_CPC GENMASK(27, 26)
|
||||
#define XGMAC_TDES3_CPC_SHIFT 26
|
||||
#define XGMAC_TDES3_TCMSSV BIT(26)
|
||||
#define XGMAC_TDES3_SAIC GENMASK(25, 23)
|
||||
#define XGMAC_TDES3_SAIC_SHIFT 23
|
||||
#define XGMAC_TDES3_TBSV BIT(24)
|
||||
#define XGMAC_TDES3_THL GENMASK(22, 19)
|
||||
#define XGMAC_TDES3_THL_SHIFT 19
|
||||
#define XGMAC_TDES3_IVTIR GENMASK(19, 18)
|
||||
#define XGMAC_TDES3_IVTIR_SHIFT 18
|
||||
#define XGMAC_TDES3_TSE BIT(18)
|
||||
#define XGMAC_TDES3_IVLTV BIT(17)
|
||||
#define XGMAC_TDES3_CIC GENMASK(17, 16)
|
||||
#define XGMAC_TDES3_CIC_SHIFT 16
|
||||
#define XGMAC_TDES3_TPL GENMASK(17, 0)
|
||||
#define XGMAC_TDES3_VLTV BIT(16)
|
||||
#define XGMAC_TDES3_VT GENMASK(15, 0)
|
||||
#define XGMAC_TDES3_FL GENMASK(14, 0)
|
||||
#define XGMAC_RDES2_HL GENMASK(9, 0)
|
||||
#define XGMAC_RDES3_OWN BIT(31)
|
||||
#define XGMAC_RDES3_CTXT BIT(30)
|
||||
#define XGMAC_RDES3_IOC BIT(30)
|
||||
#define XGMAC_RDES3_LD BIT(28)
|
||||
#define XGMAC_RDES3_CDA BIT(27)
|
||||
#define XGMAC_RDES3_RSV BIT(26)
|
||||
#define XGMAC_RDES3_L34T GENMASK(23, 20)
|
||||
#define XGMAC_RDES3_L34T_SHIFT 20
|
||||
#define XGMAC_L34T_IP4TCP 0x1
|
||||
#define XGMAC_L34T_IP4UDP 0x2
|
||||
#define XGMAC_L34T_IP6TCP 0x9
|
||||
#define XGMAC_L34T_IP6UDP 0xA
|
||||
#define XGMAC_RDES3_ES BIT(15)
|
||||
#define XGMAC_RDES3_PL GENMASK(13, 0)
|
||||
#define XGMAC_RDES3_TSD BIT(6)
|
||||
#define XGMAC_RDES3_TSA BIT(4)
|
||||
|
||||
#endif /* __STMMAC_DWXGMAC2_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,375 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
|
||||
* stmmac XGMAC support.
|
||||
*/
|
||||
|
||||
#include <linux/stmmac.h>
|
||||
#include "common-6.12-ethercat.h"
|
||||
#include "dwxgmac2-6.12-ethercat.h"
|
||||
|
||||
static int dwxgmac2_get_tx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p, void __iomem *ioaddr)
|
||||
{
|
||||
unsigned int tdes3 = le32_to_cpu(p->des3);
|
||||
int ret = tx_done;
|
||||
|
||||
if (unlikely(tdes3 & XGMAC_TDES3_OWN))
|
||||
return tx_dma_own;
|
||||
if (likely(!(tdes3 & XGMAC_TDES3_LD)))
|
||||
return tx_not_ls;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_rx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p)
|
||||
{
|
||||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
|
||||
if (unlikely(rdes3 & XGMAC_RDES3_OWN))
|
||||
return dma_own;
|
||||
if (unlikely(rdes3 & XGMAC_RDES3_CTXT))
|
||||
return discard_frame;
|
||||
if (likely(!(rdes3 & XGMAC_RDES3_LD)))
|
||||
return rx_not_ls;
|
||||
if (unlikely((rdes3 & XGMAC_RDES3_ES) && (rdes3 & XGMAC_RDES3_LD)))
|
||||
return discard_frame;
|
||||
|
||||
return good_frame;
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_tx_len(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des2) & XGMAC_TDES2_B1L);
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des3) & XGMAC_TDES3_OWN) > 0;
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des3 |= cpu_to_le32(XGMAC_TDES3_OWN);
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
|
||||
{
|
||||
u32 flags = XGMAC_RDES3_OWN;
|
||||
|
||||
if (!disable_rx_ic)
|
||||
flags |= XGMAC_RDES3_IOC;
|
||||
|
||||
p->des3 |= cpu_to_le32(flags);
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_tx_ls(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des3) & XGMAC_RDES3_LD) > 0;
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_rx_frame_len(struct dma_desc *p, int rx_coe)
|
||||
{
|
||||
return (le32_to_cpu(p->des3) & XGMAC_RDES3_PL);
|
||||
}
|
||||
|
||||
static void dwxgmac2_enable_tx_timestamp(struct dma_desc *p)
|
||||
{
|
||||
p->des2 |= cpu_to_le32(XGMAC_TDES2_TTSE);
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_tx_timestamp_status(struct dma_desc *p)
|
||||
{
|
||||
return 0; /* Not supported */
|
||||
}
|
||||
|
||||
static inline void dwxgmac2_get_timestamp(void *desc, u32 ats, u64 *ts)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
u64 ns = 0;
|
||||
|
||||
ns += le32_to_cpu(p->des1) * 1000000000ULL;
|
||||
ns += le32_to_cpu(p->des0);
|
||||
|
||||
*ts = ns;
|
||||
}
|
||||
|
||||
static int dwxgmac2_rx_check_timestamp(void *desc)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
bool desc_valid, ts_valid;
|
||||
|
||||
dma_rmb();
|
||||
|
||||
desc_valid = !(rdes3 & XGMAC_RDES3_OWN) && (rdes3 & XGMAC_RDES3_CTXT);
|
||||
ts_valid = !(rdes3 & XGMAC_RDES3_TSD) && (rdes3 & XGMAC_RDES3_TSA);
|
||||
|
||||
if (likely(desc_valid && ts_valid)) {
|
||||
if ((p->des0 == 0xffffffff) && (p->des1 == 0xffffffff))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_rx_timestamp_status(void *desc, void *next_desc,
|
||||
u32 ats)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
int ret = -EBUSY;
|
||||
|
||||
if (likely(rdes3 & XGMAC_RDES3_CDA))
|
||||
ret = dwxgmac2_rx_check_timestamp(next_desc);
|
||||
|
||||
return !ret;
|
||||
}
|
||||
|
||||
static void dwxgmac2_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
|
||||
int mode, int end, int bfsize)
|
||||
{
|
||||
dwxgmac2_set_rx_owner(p, disable_rx_ic);
|
||||
}
|
||||
|
||||
static void dwxgmac2_init_tx_desc(struct dma_desc *p, int mode, int end)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static void dwxgmac2_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
bool csum_flag, int mode, bool tx_own,
|
||||
bool ls, unsigned int tot_pkt_len)
|
||||
{
|
||||
unsigned int tdes3 = le32_to_cpu(p->des3);
|
||||
|
||||
p->des2 |= cpu_to_le32(len & XGMAC_TDES2_B1L);
|
||||
|
||||
tdes3 |= tot_pkt_len & XGMAC_TDES3_FL;
|
||||
if (is_fs)
|
||||
tdes3 |= XGMAC_TDES3_FD;
|
||||
else
|
||||
tdes3 &= ~XGMAC_TDES3_FD;
|
||||
|
||||
if (csum_flag)
|
||||
tdes3 |= 0x3 << XGMAC_TDES3_CIC_SHIFT;
|
||||
else
|
||||
tdes3 &= ~XGMAC_TDES3_CIC;
|
||||
|
||||
if (ls)
|
||||
tdes3 |= XGMAC_TDES3_LD;
|
||||
else
|
||||
tdes3 &= ~XGMAC_TDES3_LD;
|
||||
|
||||
/* Finally set the OWN bit. Later the DMA will start! */
|
||||
if (tx_own)
|
||||
tdes3 |= XGMAC_TDES3_OWN;
|
||||
|
||||
if (is_fs && tx_own)
|
||||
/* When the own bit, for the first frame, has to be set, all
|
||||
* descriptors for the same frame has to be set before, to
|
||||
* avoid race condition.
|
||||
*/
|
||||
dma_wmb();
|
||||
|
||||
p->des3 = cpu_to_le32(tdes3);
|
||||
}
|
||||
|
||||
static void dwxgmac2_prepare_tso_tx_desc(struct dma_desc *p, int is_fs,
|
||||
int len1, int len2, bool tx_own,
|
||||
bool ls, unsigned int tcphdrlen,
|
||||
unsigned int tcppayloadlen)
|
||||
{
|
||||
unsigned int tdes3 = le32_to_cpu(p->des3);
|
||||
|
||||
if (len1)
|
||||
p->des2 |= cpu_to_le32(len1 & XGMAC_TDES2_B1L);
|
||||
if (len2)
|
||||
p->des2 |= cpu_to_le32((len2 << XGMAC_TDES2_B2L_SHIFT) &
|
||||
XGMAC_TDES2_B2L);
|
||||
if (is_fs) {
|
||||
tdes3 |= XGMAC_TDES3_FD | XGMAC_TDES3_TSE;
|
||||
tdes3 |= (tcphdrlen << XGMAC_TDES3_THL_SHIFT) &
|
||||
XGMAC_TDES3_THL;
|
||||
tdes3 |= tcppayloadlen & XGMAC_TDES3_TPL;
|
||||
} else {
|
||||
tdes3 &= ~XGMAC_TDES3_FD;
|
||||
}
|
||||
|
||||
if (ls)
|
||||
tdes3 |= XGMAC_TDES3_LD;
|
||||
else
|
||||
tdes3 &= ~XGMAC_TDES3_LD;
|
||||
|
||||
/* Finally set the OWN bit. Later the DMA will start! */
|
||||
if (tx_own)
|
||||
tdes3 |= XGMAC_TDES3_OWN;
|
||||
|
||||
if (is_fs && tx_own)
|
||||
/* When the own bit, for the first frame, has to be set, all
|
||||
* descriptors for the same frame has to be set before, to
|
||||
* avoid race condition.
|
||||
*/
|
||||
dma_wmb();
|
||||
|
||||
p->des3 = cpu_to_le32(tdes3);
|
||||
}
|
||||
|
||||
static void dwxgmac2_release_tx_desc(struct dma_desc *p, int mode)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_tx_ic(struct dma_desc *p)
|
||||
{
|
||||
p->des2 |= cpu_to_le32(XGMAC_TDES2_IOC);
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_mss(struct dma_desc *p, unsigned int mss)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = cpu_to_le32(mss);
|
||||
p->des3 = cpu_to_le32(XGMAC_TDES3_CTXT | XGMAC_TDES3_TCMSSV);
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_addr(struct dma_desc *p, dma_addr_t addr)
|
||||
{
|
||||
p->des0 = cpu_to_le32(lower_32_bits(addr));
|
||||
p->des1 = cpu_to_le32(upper_32_bits(addr));
|
||||
}
|
||||
|
||||
static void dwxgmac2_clear(struct dma_desc *p)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_rx_hash(struct dma_desc *p, u32 *hash,
|
||||
enum pkt_hash_types *type)
|
||||
{
|
||||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
u32 ptype;
|
||||
|
||||
if (rdes3 & XGMAC_RDES3_RSV) {
|
||||
ptype = (rdes3 & XGMAC_RDES3_L34T) >> XGMAC_RDES3_L34T_SHIFT;
|
||||
|
||||
switch (ptype) {
|
||||
case XGMAC_L34T_IP4TCP:
|
||||
case XGMAC_L34T_IP4UDP:
|
||||
case XGMAC_L34T_IP6TCP:
|
||||
case XGMAC_L34T_IP6UDP:
|
||||
*type = PKT_HASH_TYPE_L4;
|
||||
break;
|
||||
default:
|
||||
*type = PKT_HASH_TYPE_L3;
|
||||
break;
|
||||
}
|
||||
|
||||
*hash = le32_to_cpu(p->des1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void dwxgmac2_get_rx_header_len(struct dma_desc *p, unsigned int *len)
|
||||
{
|
||||
if (le32_to_cpu(p->des3) & XGMAC_RDES3_L34T)
|
||||
*len = le32_to_cpu(p->des2) & XGMAC_RDES2_HL;
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_sec_addr(struct dma_desc *p, dma_addr_t addr, bool is_valid)
|
||||
{
|
||||
p->des2 = cpu_to_le32(lower_32_bits(addr));
|
||||
p->des3 = cpu_to_le32(upper_32_bits(addr));
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_sarc(struct dma_desc *p, u32 sarc_type)
|
||||
{
|
||||
sarc_type <<= XGMAC_TDES3_SAIC_SHIFT;
|
||||
|
||||
p->des3 |= cpu_to_le32(sarc_type & XGMAC_TDES3_SAIC);
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_vlan_tag(struct dma_desc *p, u16 tag, u16 inner_tag,
|
||||
u32 inner_type)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
|
||||
/* Inner VLAN */
|
||||
if (inner_type) {
|
||||
u32 des = inner_tag << XGMAC_TDES2_IVT_SHIFT;
|
||||
|
||||
des &= XGMAC_TDES2_IVT;
|
||||
p->des2 = cpu_to_le32(des);
|
||||
|
||||
des = inner_type << XGMAC_TDES3_IVTIR_SHIFT;
|
||||
des &= XGMAC_TDES3_IVTIR;
|
||||
p->des3 = cpu_to_le32(des | XGMAC_TDES3_IVLTV);
|
||||
}
|
||||
|
||||
/* Outer VLAN */
|
||||
p->des3 |= cpu_to_le32(tag & XGMAC_TDES3_VT);
|
||||
p->des3 |= cpu_to_le32(XGMAC_TDES3_VLTV);
|
||||
|
||||
p->des3 |= cpu_to_le32(XGMAC_TDES3_CTXT);
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_vlan(struct dma_desc *p, u32 type)
|
||||
{
|
||||
type <<= XGMAC_TDES2_VTIR_SHIFT;
|
||||
p->des2 |= cpu_to_le32(type & XGMAC_TDES2_VTIR);
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_tbs(struct dma_edesc *p, u32 sec, u32 nsec)
|
||||
{
|
||||
p->des4 = cpu_to_le32((sec & XGMAC_TDES0_LT) | XGMAC_TDES0_LTV);
|
||||
p->des5 = cpu_to_le32(nsec & XGMAC_TDES1_LT);
|
||||
p->des6 = 0;
|
||||
p->des7 = 0;
|
||||
}
|
||||
|
||||
const struct stmmac_desc_ops dwxgmac210_desc_ops = {
|
||||
.tx_status = dwxgmac2_get_tx_status,
|
||||
.rx_status = dwxgmac2_get_rx_status,
|
||||
.get_tx_len = dwxgmac2_get_tx_len,
|
||||
.get_tx_owner = dwxgmac2_get_tx_owner,
|
||||
.set_tx_owner = dwxgmac2_set_tx_owner,
|
||||
.set_rx_owner = dwxgmac2_set_rx_owner,
|
||||
.get_tx_ls = dwxgmac2_get_tx_ls,
|
||||
.get_rx_frame_len = dwxgmac2_get_rx_frame_len,
|
||||
.enable_tx_timestamp = dwxgmac2_enable_tx_timestamp,
|
||||
.get_tx_timestamp_status = dwxgmac2_get_tx_timestamp_status,
|
||||
.get_rx_timestamp_status = dwxgmac2_get_rx_timestamp_status,
|
||||
.get_timestamp = dwxgmac2_get_timestamp,
|
||||
.set_tx_ic = dwxgmac2_set_tx_ic,
|
||||
.prepare_tx_desc = dwxgmac2_prepare_tx_desc,
|
||||
.prepare_tso_tx_desc = dwxgmac2_prepare_tso_tx_desc,
|
||||
.release_tx_desc = dwxgmac2_release_tx_desc,
|
||||
.init_rx_desc = dwxgmac2_init_rx_desc,
|
||||
.init_tx_desc = dwxgmac2_init_tx_desc,
|
||||
.set_mss = dwxgmac2_set_mss,
|
||||
.set_addr = dwxgmac2_set_addr,
|
||||
.clear = dwxgmac2_clear,
|
||||
.get_rx_hash = dwxgmac2_get_rx_hash,
|
||||
.get_rx_header_len = dwxgmac2_get_rx_header_len,
|
||||
.set_sec_addr = dwxgmac2_set_sec_addr,
|
||||
.set_sarc = dwxgmac2_set_sarc,
|
||||
.set_vlan_tag = dwxgmac2_set_vlan_tag,
|
||||
.set_vlan = dwxgmac2_set_vlan,
|
||||
.set_tbs = dwxgmac2_set_tbs,
|
||||
};
|
||||
|
|
@ -0,0 +1,375 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
|
||||
* stmmac XGMAC support.
|
||||
*/
|
||||
|
||||
#include <linux/stmmac.h>
|
||||
#include "common.h"
|
||||
#include "dwxgmac2.h"
|
||||
|
||||
static int dwxgmac2_get_tx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p, void __iomem *ioaddr)
|
||||
{
|
||||
unsigned int tdes3 = le32_to_cpu(p->des3);
|
||||
int ret = tx_done;
|
||||
|
||||
if (unlikely(tdes3 & XGMAC_TDES3_OWN))
|
||||
return tx_dma_own;
|
||||
if (likely(!(tdes3 & XGMAC_TDES3_LD)))
|
||||
return tx_not_ls;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_rx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p)
|
||||
{
|
||||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
|
||||
if (unlikely(rdes3 & XGMAC_RDES3_OWN))
|
||||
return dma_own;
|
||||
if (unlikely(rdes3 & XGMAC_RDES3_CTXT))
|
||||
return discard_frame;
|
||||
if (likely(!(rdes3 & XGMAC_RDES3_LD)))
|
||||
return rx_not_ls;
|
||||
if (unlikely((rdes3 & XGMAC_RDES3_ES) && (rdes3 & XGMAC_RDES3_LD)))
|
||||
return discard_frame;
|
||||
|
||||
return good_frame;
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_tx_len(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des2) & XGMAC_TDES2_B1L);
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des3) & XGMAC_TDES3_OWN) > 0;
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des3 |= cpu_to_le32(XGMAC_TDES3_OWN);
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
|
||||
{
|
||||
u32 flags = XGMAC_RDES3_OWN;
|
||||
|
||||
if (!disable_rx_ic)
|
||||
flags |= XGMAC_RDES3_IOC;
|
||||
|
||||
p->des3 |= cpu_to_le32(flags);
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_tx_ls(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des3) & XGMAC_RDES3_LD) > 0;
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_rx_frame_len(struct dma_desc *p, int rx_coe)
|
||||
{
|
||||
return (le32_to_cpu(p->des3) & XGMAC_RDES3_PL);
|
||||
}
|
||||
|
||||
static void dwxgmac2_enable_tx_timestamp(struct dma_desc *p)
|
||||
{
|
||||
p->des2 |= cpu_to_le32(XGMAC_TDES2_TTSE);
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_tx_timestamp_status(struct dma_desc *p)
|
||||
{
|
||||
return 0; /* Not supported */
|
||||
}
|
||||
|
||||
static inline void dwxgmac2_get_timestamp(void *desc, u32 ats, u64 *ts)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
u64 ns = 0;
|
||||
|
||||
ns += le32_to_cpu(p->des1) * 1000000000ULL;
|
||||
ns += le32_to_cpu(p->des0);
|
||||
|
||||
*ts = ns;
|
||||
}
|
||||
|
||||
static int dwxgmac2_rx_check_timestamp(void *desc)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
bool desc_valid, ts_valid;
|
||||
|
||||
dma_rmb();
|
||||
|
||||
desc_valid = !(rdes3 & XGMAC_RDES3_OWN) && (rdes3 & XGMAC_RDES3_CTXT);
|
||||
ts_valid = !(rdes3 & XGMAC_RDES3_TSD) && (rdes3 & XGMAC_RDES3_TSA);
|
||||
|
||||
if (likely(desc_valid && ts_valid)) {
|
||||
if ((p->des0 == 0xffffffff) && (p->des1 == 0xffffffff))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_rx_timestamp_status(void *desc, void *next_desc,
|
||||
u32 ats)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
int ret = -EBUSY;
|
||||
|
||||
if (likely(rdes3 & XGMAC_RDES3_CDA))
|
||||
ret = dwxgmac2_rx_check_timestamp(next_desc);
|
||||
|
||||
return !ret;
|
||||
}
|
||||
|
||||
static void dwxgmac2_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
|
||||
int mode, int end, int bfsize)
|
||||
{
|
||||
dwxgmac2_set_rx_owner(p, disable_rx_ic);
|
||||
}
|
||||
|
||||
static void dwxgmac2_init_tx_desc(struct dma_desc *p, int mode, int end)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static void dwxgmac2_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
bool csum_flag, int mode, bool tx_own,
|
||||
bool ls, unsigned int tot_pkt_len)
|
||||
{
|
||||
unsigned int tdes3 = le32_to_cpu(p->des3);
|
||||
|
||||
p->des2 |= cpu_to_le32(len & XGMAC_TDES2_B1L);
|
||||
|
||||
tdes3 |= tot_pkt_len & XGMAC_TDES3_FL;
|
||||
if (is_fs)
|
||||
tdes3 |= XGMAC_TDES3_FD;
|
||||
else
|
||||
tdes3 &= ~XGMAC_TDES3_FD;
|
||||
|
||||
if (csum_flag)
|
||||
tdes3 |= 0x3 << XGMAC_TDES3_CIC_SHIFT;
|
||||
else
|
||||
tdes3 &= ~XGMAC_TDES3_CIC;
|
||||
|
||||
if (ls)
|
||||
tdes3 |= XGMAC_TDES3_LD;
|
||||
else
|
||||
tdes3 &= ~XGMAC_TDES3_LD;
|
||||
|
||||
/* Finally set the OWN bit. Later the DMA will start! */
|
||||
if (tx_own)
|
||||
tdes3 |= XGMAC_TDES3_OWN;
|
||||
|
||||
if (is_fs && tx_own)
|
||||
/* When the own bit, for the first frame, has to be set, all
|
||||
* descriptors for the same frame has to be set before, to
|
||||
* avoid race condition.
|
||||
*/
|
||||
dma_wmb();
|
||||
|
||||
p->des3 = cpu_to_le32(tdes3);
|
||||
}
|
||||
|
||||
static void dwxgmac2_prepare_tso_tx_desc(struct dma_desc *p, int is_fs,
|
||||
int len1, int len2, bool tx_own,
|
||||
bool ls, unsigned int tcphdrlen,
|
||||
unsigned int tcppayloadlen)
|
||||
{
|
||||
unsigned int tdes3 = le32_to_cpu(p->des3);
|
||||
|
||||
if (len1)
|
||||
p->des2 |= cpu_to_le32(len1 & XGMAC_TDES2_B1L);
|
||||
if (len2)
|
||||
p->des2 |= cpu_to_le32((len2 << XGMAC_TDES2_B2L_SHIFT) &
|
||||
XGMAC_TDES2_B2L);
|
||||
if (is_fs) {
|
||||
tdes3 |= XGMAC_TDES3_FD | XGMAC_TDES3_TSE;
|
||||
tdes3 |= (tcphdrlen << XGMAC_TDES3_THL_SHIFT) &
|
||||
XGMAC_TDES3_THL;
|
||||
tdes3 |= tcppayloadlen & XGMAC_TDES3_TPL;
|
||||
} else {
|
||||
tdes3 &= ~XGMAC_TDES3_FD;
|
||||
}
|
||||
|
||||
if (ls)
|
||||
tdes3 |= XGMAC_TDES3_LD;
|
||||
else
|
||||
tdes3 &= ~XGMAC_TDES3_LD;
|
||||
|
||||
/* Finally set the OWN bit. Later the DMA will start! */
|
||||
if (tx_own)
|
||||
tdes3 |= XGMAC_TDES3_OWN;
|
||||
|
||||
if (is_fs && tx_own)
|
||||
/* When the own bit, for the first frame, has to be set, all
|
||||
* descriptors for the same frame has to be set before, to
|
||||
* avoid race condition.
|
||||
*/
|
||||
dma_wmb();
|
||||
|
||||
p->des3 = cpu_to_le32(tdes3);
|
||||
}
|
||||
|
||||
static void dwxgmac2_release_tx_desc(struct dma_desc *p, int mode)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_tx_ic(struct dma_desc *p)
|
||||
{
|
||||
p->des2 |= cpu_to_le32(XGMAC_TDES2_IOC);
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_mss(struct dma_desc *p, unsigned int mss)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = cpu_to_le32(mss);
|
||||
p->des3 = cpu_to_le32(XGMAC_TDES3_CTXT | XGMAC_TDES3_TCMSSV);
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_addr(struct dma_desc *p, dma_addr_t addr)
|
||||
{
|
||||
p->des0 = cpu_to_le32(lower_32_bits(addr));
|
||||
p->des1 = cpu_to_le32(upper_32_bits(addr));
|
||||
}
|
||||
|
||||
static void dwxgmac2_clear(struct dma_desc *p)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_rx_hash(struct dma_desc *p, u32 *hash,
|
||||
enum pkt_hash_types *type)
|
||||
{
|
||||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
u32 ptype;
|
||||
|
||||
if (rdes3 & XGMAC_RDES3_RSV) {
|
||||
ptype = (rdes3 & XGMAC_RDES3_L34T) >> XGMAC_RDES3_L34T_SHIFT;
|
||||
|
||||
switch (ptype) {
|
||||
case XGMAC_L34T_IP4TCP:
|
||||
case XGMAC_L34T_IP4UDP:
|
||||
case XGMAC_L34T_IP6TCP:
|
||||
case XGMAC_L34T_IP6UDP:
|
||||
*type = PKT_HASH_TYPE_L4;
|
||||
break;
|
||||
default:
|
||||
*type = PKT_HASH_TYPE_L3;
|
||||
break;
|
||||
}
|
||||
|
||||
*hash = le32_to_cpu(p->des1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void dwxgmac2_get_rx_header_len(struct dma_desc *p, unsigned int *len)
|
||||
{
|
||||
if (le32_to_cpu(p->des3) & XGMAC_RDES3_L34T)
|
||||
*len = le32_to_cpu(p->des2) & XGMAC_RDES2_HL;
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_sec_addr(struct dma_desc *p, dma_addr_t addr, bool is_valid)
|
||||
{
|
||||
p->des2 = cpu_to_le32(lower_32_bits(addr));
|
||||
p->des3 = cpu_to_le32(upper_32_bits(addr));
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_sarc(struct dma_desc *p, u32 sarc_type)
|
||||
{
|
||||
sarc_type <<= XGMAC_TDES3_SAIC_SHIFT;
|
||||
|
||||
p->des3 |= cpu_to_le32(sarc_type & XGMAC_TDES3_SAIC);
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_vlan_tag(struct dma_desc *p, u16 tag, u16 inner_tag,
|
||||
u32 inner_type)
|
||||
{
|
||||
p->des0 = 0;
|
||||
p->des1 = 0;
|
||||
p->des2 = 0;
|
||||
p->des3 = 0;
|
||||
|
||||
/* Inner VLAN */
|
||||
if (inner_type) {
|
||||
u32 des = inner_tag << XGMAC_TDES2_IVT_SHIFT;
|
||||
|
||||
des &= XGMAC_TDES2_IVT;
|
||||
p->des2 = cpu_to_le32(des);
|
||||
|
||||
des = inner_type << XGMAC_TDES3_IVTIR_SHIFT;
|
||||
des &= XGMAC_TDES3_IVTIR;
|
||||
p->des3 = cpu_to_le32(des | XGMAC_TDES3_IVLTV);
|
||||
}
|
||||
|
||||
/* Outer VLAN */
|
||||
p->des3 |= cpu_to_le32(tag & XGMAC_TDES3_VT);
|
||||
p->des3 |= cpu_to_le32(XGMAC_TDES3_VLTV);
|
||||
|
||||
p->des3 |= cpu_to_le32(XGMAC_TDES3_CTXT);
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_vlan(struct dma_desc *p, u32 type)
|
||||
{
|
||||
type <<= XGMAC_TDES2_VTIR_SHIFT;
|
||||
p->des2 |= cpu_to_le32(type & XGMAC_TDES2_VTIR);
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_tbs(struct dma_edesc *p, u32 sec, u32 nsec)
|
||||
{
|
||||
p->des4 = cpu_to_le32((sec & XGMAC_TDES0_LT) | XGMAC_TDES0_LTV);
|
||||
p->des5 = cpu_to_le32(nsec & XGMAC_TDES1_LT);
|
||||
p->des6 = 0;
|
||||
p->des7 = 0;
|
||||
}
|
||||
|
||||
const struct stmmac_desc_ops dwxgmac210_desc_ops = {
|
||||
.tx_status = dwxgmac2_get_tx_status,
|
||||
.rx_status = dwxgmac2_get_rx_status,
|
||||
.get_tx_len = dwxgmac2_get_tx_len,
|
||||
.get_tx_owner = dwxgmac2_get_tx_owner,
|
||||
.set_tx_owner = dwxgmac2_set_tx_owner,
|
||||
.set_rx_owner = dwxgmac2_set_rx_owner,
|
||||
.get_tx_ls = dwxgmac2_get_tx_ls,
|
||||
.get_rx_frame_len = dwxgmac2_get_rx_frame_len,
|
||||
.enable_tx_timestamp = dwxgmac2_enable_tx_timestamp,
|
||||
.get_tx_timestamp_status = dwxgmac2_get_tx_timestamp_status,
|
||||
.get_rx_timestamp_status = dwxgmac2_get_rx_timestamp_status,
|
||||
.get_timestamp = dwxgmac2_get_timestamp,
|
||||
.set_tx_ic = dwxgmac2_set_tx_ic,
|
||||
.prepare_tx_desc = dwxgmac2_prepare_tx_desc,
|
||||
.prepare_tso_tx_desc = dwxgmac2_prepare_tso_tx_desc,
|
||||
.release_tx_desc = dwxgmac2_release_tx_desc,
|
||||
.init_rx_desc = dwxgmac2_init_rx_desc,
|
||||
.init_tx_desc = dwxgmac2_init_tx_desc,
|
||||
.set_mss = dwxgmac2_set_mss,
|
||||
.set_addr = dwxgmac2_set_addr,
|
||||
.clear = dwxgmac2_clear,
|
||||
.get_rx_hash = dwxgmac2_get_rx_hash,
|
||||
.get_rx_header_len = dwxgmac2_get_rx_header_len,
|
||||
.set_sec_addr = dwxgmac2_set_sec_addr,
|
||||
.set_sarc = dwxgmac2_set_sarc,
|
||||
.set_vlan_tag = dwxgmac2_set_vlan_tag,
|
||||
.set_vlan = dwxgmac2_set_vlan,
|
||||
.set_tbs = dwxgmac2_set_tbs,
|
||||
};
|
||||
|
|
@ -0,0 +1,643 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
|
||||
* stmmac XGMAC support.
|
||||
*/
|
||||
|
||||
#include <linux/iopoll.h>
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
#include "dwxgmac2-6.12-ethercat.h"
|
||||
|
||||
static int dwxgmac2_dma_reset(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_MODE);
|
||||
|
||||
/* DMA SW reset */
|
||||
writel(value | XGMAC_SWR, ioaddr + XGMAC_DMA_MODE);
|
||||
|
||||
return readl_poll_timeout(ioaddr + XGMAC_DMA_MODE, value,
|
||||
!(value & XGMAC_SWR), 0, 100000);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_init(void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_SYSBUS_MODE);
|
||||
|
||||
if (dma_cfg->aal)
|
||||
value |= XGMAC_AAL;
|
||||
|
||||
if (dma_cfg->eame)
|
||||
value |= XGMAC_EAME;
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_SYSBUS_MODE);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_init_chan(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg, u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(chan));
|
||||
|
||||
if (dma_cfg->pblx8)
|
||||
value |= XGMAC_PBLx8;
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(chan));
|
||||
writel(XGMAC_DMA_INT_DEFAULT_EN, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_init_rx_chan(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t phy, u32 chan)
|
||||
{
|
||||
u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
value &= ~XGMAC_RxPBL;
|
||||
value |= (rxpbl << XGMAC_RxPBL_SHIFT) & XGMAC_RxPBL;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
|
||||
writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_HADDR(chan));
|
||||
writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_LADDR(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t phy, u32 chan)
|
||||
{
|
||||
u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
value &= ~XGMAC_TxPBL;
|
||||
value |= (txpbl << XGMAC_TxPBL_SHIFT) & XGMAC_TxPBL;
|
||||
value |= XGMAC_OSP;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
|
||||
writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_HADDR(chan));
|
||||
writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_SYSBUS_MODE);
|
||||
int i;
|
||||
|
||||
if (axi->axi_lpi_en)
|
||||
value |= XGMAC_EN_LPI;
|
||||
if (axi->axi_xit_frm)
|
||||
value |= XGMAC_LPI_XIT_PKT;
|
||||
|
||||
value &= ~XGMAC_WR_OSR_LMT;
|
||||
value |= (axi->axi_wr_osr_lmt << XGMAC_WR_OSR_LMT_SHIFT) &
|
||||
XGMAC_WR_OSR_LMT;
|
||||
|
||||
value &= ~XGMAC_RD_OSR_LMT;
|
||||
value |= (axi->axi_rd_osr_lmt << XGMAC_RD_OSR_LMT_SHIFT) &
|
||||
XGMAC_RD_OSR_LMT;
|
||||
|
||||
if (!axi->axi_fb)
|
||||
value |= XGMAC_UNDEF;
|
||||
|
||||
value &= ~XGMAC_BLEN;
|
||||
for (i = 0; i < AXI_BLEN; i++) {
|
||||
switch (axi->axi_blen[i]) {
|
||||
case 256:
|
||||
value |= XGMAC_BLEN256;
|
||||
break;
|
||||
case 128:
|
||||
value |= XGMAC_BLEN128;
|
||||
break;
|
||||
case 64:
|
||||
value |= XGMAC_BLEN64;
|
||||
break;
|
||||
case 32:
|
||||
value |= XGMAC_BLEN32;
|
||||
break;
|
||||
case 16:
|
||||
value |= XGMAC_BLEN16;
|
||||
break;
|
||||
case 8:
|
||||
value |= XGMAC_BLEN8;
|
||||
break;
|
||||
case 4:
|
||||
value |= XGMAC_BLEN4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_SYSBUS_MODE);
|
||||
writel(XGMAC_TDPS, ioaddr + XGMAC_TX_EDMA_CTRL);
|
||||
writel(XGMAC_RDPS, ioaddr + XGMAC_RX_EDMA_CTRL);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_dump_regs(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 *reg_space)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = (XGMAC_DMA_MODE / 4); i < XGMAC_REGSIZE; i++)
|
||||
reg_space[i] = readl(ioaddr + i * 4);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int mode, u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_MTL_RXQ_OPMODE(channel));
|
||||
unsigned int rqs = fifosz / 256 - 1;
|
||||
|
||||
if (mode == SF_DMA_MODE) {
|
||||
value |= XGMAC_RSF;
|
||||
} else {
|
||||
value &= ~XGMAC_RSF;
|
||||
value &= ~XGMAC_RTC;
|
||||
|
||||
if (mode <= 64)
|
||||
value |= 0x0 << XGMAC_RTC_SHIFT;
|
||||
else if (mode <= 96)
|
||||
value |= 0x2 << XGMAC_RTC_SHIFT;
|
||||
else
|
||||
value |= 0x3 << XGMAC_RTC_SHIFT;
|
||||
}
|
||||
|
||||
value &= ~XGMAC_RQS;
|
||||
value |= (rqs << XGMAC_RQS_SHIFT) & XGMAC_RQS;
|
||||
|
||||
if ((fifosz >= 4096) && (qmode != MTL_QUEUE_AVB)) {
|
||||
u32 flow = readl(ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(channel));
|
||||
unsigned int rfd, rfa;
|
||||
|
||||
value |= XGMAC_EHFC;
|
||||
|
||||
/* Set Threshold for Activating Flow Control to min 2 frames,
|
||||
* i.e. 1500 * 2 = 3000 bytes.
|
||||
*
|
||||
* Set Threshold for Deactivating Flow Control to min 1 frame,
|
||||
* i.e. 1500 bytes.
|
||||
*/
|
||||
switch (fifosz) {
|
||||
case 4096:
|
||||
/* This violates the above formula because of FIFO size
|
||||
* limit therefore overflow may occur in spite of this.
|
||||
*/
|
||||
rfd = 0x03; /* Full-2.5K */
|
||||
rfa = 0x01; /* Full-1.5K */
|
||||
break;
|
||||
|
||||
default:
|
||||
rfd = 0x07; /* Full-4.5K */
|
||||
rfa = 0x04; /* Full-3K */
|
||||
break;
|
||||
}
|
||||
|
||||
flow &= ~XGMAC_RFD;
|
||||
flow |= rfd << XGMAC_RFD_SHIFT;
|
||||
|
||||
flow &= ~XGMAC_RFA;
|
||||
flow |= rfa << XGMAC_RFA_SHIFT;
|
||||
|
||||
writel(flow, ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(channel));
|
||||
}
|
||||
|
||||
writel(value, ioaddr + XGMAC_MTL_RXQ_OPMODE(channel));
|
||||
|
||||
/* Enable MTL RX overflow */
|
||||
value = readl(ioaddr + XGMAC_MTL_QINTEN(channel));
|
||||
writel(value | XGMAC_RXOIE, ioaddr + XGMAC_MTL_QINTEN(channel));
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int mode, u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
|
||||
unsigned int tqs = fifosz / 256 - 1;
|
||||
|
||||
if (mode == SF_DMA_MODE) {
|
||||
value |= XGMAC_TSF;
|
||||
} else {
|
||||
value &= ~XGMAC_TSF;
|
||||
value &= ~XGMAC_TTC;
|
||||
|
||||
if (mode <= 64)
|
||||
value |= 0x0 << XGMAC_TTC_SHIFT;
|
||||
else if (mode <= 96)
|
||||
value |= 0x2 << XGMAC_TTC_SHIFT;
|
||||
else if (mode <= 128)
|
||||
value |= 0x3 << XGMAC_TTC_SHIFT;
|
||||
else if (mode <= 192)
|
||||
value |= 0x4 << XGMAC_TTC_SHIFT;
|
||||
else if (mode <= 256)
|
||||
value |= 0x5 << XGMAC_TTC_SHIFT;
|
||||
else if (mode <= 384)
|
||||
value |= 0x6 << XGMAC_TTC_SHIFT;
|
||||
else
|
||||
value |= 0x7 << XGMAC_TTC_SHIFT;
|
||||
}
|
||||
|
||||
/* Use static TC to Queue mapping */
|
||||
value |= (channel << XGMAC_Q2TCMAP_SHIFT) & XGMAC_Q2TCMAP;
|
||||
|
||||
value &= ~XGMAC_TXQEN;
|
||||
if (qmode != MTL_QUEUE_AVB)
|
||||
value |= 0x2 << XGMAC_TXQEN_SHIFT;
|
||||
else
|
||||
value |= 0x1 << XGMAC_TXQEN_SHIFT;
|
||||
|
||||
value &= ~XGMAC_TQS;
|
||||
value |= (tqs << XGMAC_TQS_SHIFT) & XGMAC_TQS;
|
||||
|
||||
writel(value, ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
|
||||
}
|
||||
|
||||
static void dwxgmac2_enable_dma_irq(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 chan,
|
||||
bool rx, bool tx)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
|
||||
|
||||
if (rx)
|
||||
value |= XGMAC_DMA_INT_DEFAULT_RX;
|
||||
if (tx)
|
||||
value |= XGMAC_DMA_INT_DEFAULT_TX;
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_disable_dma_irq(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 chan,
|
||||
bool rx, bool tx)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
|
||||
|
||||
if (rx)
|
||||
value &= ~XGMAC_DMA_INT_DEFAULT_RX;
|
||||
if (tx)
|
||||
value &= ~XGMAC_DMA_INT_DEFAULT_TX;
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_start_tx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 chan)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
value |= XGMAC_TXST;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
|
||||
value = readl(ioaddr + XGMAC_TX_CONFIG);
|
||||
value |= XGMAC_CONFIG_TE;
|
||||
writel(value, ioaddr + XGMAC_TX_CONFIG);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
value &= ~XGMAC_TXST;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
|
||||
value = readl(ioaddr + XGMAC_TX_CONFIG);
|
||||
value &= ~XGMAC_CONFIG_TE;
|
||||
writel(value, ioaddr + XGMAC_TX_CONFIG);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_start_rx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 chan)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
value |= XGMAC_RXST;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
|
||||
value = readl(ioaddr + XGMAC_RX_CONFIG);
|
||||
value |= XGMAC_CONFIG_RE;
|
||||
writel(value, ioaddr + XGMAC_RX_CONFIG);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
value &= ~XGMAC_RXST;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
}
|
||||
|
||||
static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 chan,
|
||||
u32 dir)
|
||||
{
|
||||
struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);
|
||||
u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan));
|
||||
u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
|
||||
int ret = 0;
|
||||
|
||||
if (dir == DMA_DIR_RX)
|
||||
intr_status &= XGMAC_DMA_STATUS_MSK_RX;
|
||||
else if (dir == DMA_DIR_TX)
|
||||
intr_status &= XGMAC_DMA_STATUS_MSK_TX;
|
||||
|
||||
/* ABNORMAL interrupts */
|
||||
if (unlikely(intr_status & XGMAC_AIS)) {
|
||||
if (unlikely(intr_status & XGMAC_RBU)) {
|
||||
x->rx_buf_unav_irq++;
|
||||
ret |= handle_rx;
|
||||
}
|
||||
if (unlikely(intr_status & XGMAC_TPS)) {
|
||||
x->tx_process_stopped_irq++;
|
||||
ret |= tx_hard_error;
|
||||
}
|
||||
if (unlikely(intr_status & XGMAC_FBE)) {
|
||||
x->fatal_bus_error_irq++;
|
||||
ret |= tx_hard_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* TX/RX NORMAL interrupts */
|
||||
if (likely(intr_status & XGMAC_NIS)) {
|
||||
if (likely(intr_status & XGMAC_RI)) {
|
||||
u64_stats_update_begin(&stats->syncp);
|
||||
u64_stats_inc(&stats->rx_normal_irq_n[chan]);
|
||||
u64_stats_update_end(&stats->syncp);
|
||||
ret |= handle_rx;
|
||||
}
|
||||
if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) {
|
||||
u64_stats_update_begin(&stats->syncp);
|
||||
u64_stats_inc(&stats->tx_normal_irq_n[chan]);
|
||||
u64_stats_update_end(&stats->syncp);
|
||||
ret |= handle_tx;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear interrupts */
|
||||
writel(intr_en & intr_status, ioaddr + XGMAC_DMA_CH_STATUS(chan));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_hw_feature(void __iomem *ioaddr,
|
||||
struct dma_features *dma_cap)
|
||||
{
|
||||
u32 hw_cap;
|
||||
|
||||
/* MAC HW feature 0 */
|
||||
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE0);
|
||||
dma_cap->edma = (hw_cap & XGMAC_HWFEAT_EDMA) >> 31;
|
||||
dma_cap->ediffc = (hw_cap & XGMAC_HWFEAT_EDIFFC) >> 30;
|
||||
dma_cap->vxn = (hw_cap & XGMAC_HWFEAT_VXN) >> 29;
|
||||
dma_cap->vlins = (hw_cap & XGMAC_HWFEAT_SAVLANINS) >> 27;
|
||||
dma_cap->tssrc = (hw_cap & XGMAC_HWFEAT_TSSTSSEL) >> 25;
|
||||
dma_cap->multi_addr = (hw_cap & XGMAC_HWFEAT_ADDMACADRSEL) >> 18;
|
||||
dma_cap->rx_coe = (hw_cap & XGMAC_HWFEAT_RXCOESEL) >> 16;
|
||||
dma_cap->tx_coe = (hw_cap & XGMAC_HWFEAT_TXCOESEL) >> 14;
|
||||
dma_cap->eee = (hw_cap & XGMAC_HWFEAT_EEESEL) >> 13;
|
||||
dma_cap->atime_stamp = (hw_cap & XGMAC_HWFEAT_TSSEL) >> 12;
|
||||
dma_cap->av = (hw_cap & XGMAC_HWFEAT_AVSEL) >> 11;
|
||||
dma_cap->av &= !((hw_cap & XGMAC_HWFEAT_RAVSEL) >> 10);
|
||||
dma_cap->arpoffsel = (hw_cap & XGMAC_HWFEAT_ARPOFFSEL) >> 9;
|
||||
dma_cap->rmon = (hw_cap & XGMAC_HWFEAT_MMCSEL) >> 8;
|
||||
dma_cap->pmt_magic_frame = (hw_cap & XGMAC_HWFEAT_MGKSEL) >> 7;
|
||||
dma_cap->pmt_remote_wake_up = (hw_cap & XGMAC_HWFEAT_RWKSEL) >> 6;
|
||||
dma_cap->sma_mdio = (hw_cap & XGMAC_HWFEAT_SMASEL) >> 5;
|
||||
dma_cap->vlhash = (hw_cap & XGMAC_HWFEAT_VLHASH) >> 4;
|
||||
dma_cap->half_duplex = (hw_cap & XGMAC_HWFEAT_HDSEL) >> 3;
|
||||
dma_cap->mbps_1000 = (hw_cap & XGMAC_HWFEAT_GMIISEL) >> 1;
|
||||
|
||||
/* MAC HW feature 1 */
|
||||
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1);
|
||||
dma_cap->l3l4fnum = (hw_cap & XGMAC_HWFEAT_L3L4FNUM) >> 27;
|
||||
/* If L3L4FNUM < 8, then the number of L3L4 filters supported by
|
||||
* XGMAC is equal to L3L4FNUM. From L3L4FNUM >= 8 the number of
|
||||
* L3L4 filters goes on like 8, 16, 32, ... Current maximum of
|
||||
* L3L4FNUM = 10.
|
||||
*/
|
||||
if (dma_cap->l3l4fnum >= 8 && dma_cap->l3l4fnum <= 10)
|
||||
dma_cap->l3l4fnum = 8 << (dma_cap->l3l4fnum - 8);
|
||||
else if (dma_cap->l3l4fnum > 10)
|
||||
dma_cap->l3l4fnum = 32;
|
||||
|
||||
dma_cap->hash_tb_sz = (hw_cap & XGMAC_HWFEAT_HASHTBLSZ) >> 24;
|
||||
dma_cap->numtc = ((hw_cap & XGMAC_HWFEAT_NUMTC) >> 21) + 1;
|
||||
dma_cap->rssen = (hw_cap & XGMAC_HWFEAT_RSSEN) >> 20;
|
||||
dma_cap->dbgmem = (hw_cap & XGMAC_HWFEAT_DBGMEMA) >> 19;
|
||||
dma_cap->tsoen = (hw_cap & XGMAC_HWFEAT_TSOEN) >> 18;
|
||||
dma_cap->sphen = (hw_cap & XGMAC_HWFEAT_SPHEN) >> 17;
|
||||
dma_cap->dcben = (hw_cap & XGMAC_HWFEAT_DCBEN) >> 16;
|
||||
|
||||
dma_cap->addr64 = (hw_cap & XGMAC_HWFEAT_ADDR64) >> 14;
|
||||
switch (dma_cap->addr64) {
|
||||
case 0:
|
||||
dma_cap->addr64 = 32;
|
||||
break;
|
||||
case 1:
|
||||
dma_cap->addr64 = 40;
|
||||
break;
|
||||
case 2:
|
||||
dma_cap->addr64 = 48;
|
||||
break;
|
||||
default:
|
||||
dma_cap->addr64 = 32;
|
||||
break;
|
||||
}
|
||||
|
||||
dma_cap->advthword = (hw_cap & XGMAC_HWFEAT_ADVTHWORD) >> 13;
|
||||
dma_cap->ptoen = (hw_cap & XGMAC_HWFEAT_PTOEN) >> 12;
|
||||
dma_cap->osten = (hw_cap & XGMAC_HWFEAT_OSTEN) >> 11;
|
||||
dma_cap->tx_fifo_size =
|
||||
128 << ((hw_cap & XGMAC_HWFEAT_TXFIFOSIZE) >> 6);
|
||||
dma_cap->pfcen = (hw_cap & XGMAC_HWFEAT_PFCEN) >> 5;
|
||||
dma_cap->rx_fifo_size =
|
||||
128 << ((hw_cap & XGMAC_HWFEAT_RXFIFOSIZE) >> 0);
|
||||
|
||||
/* MAC HW feature 2 */
|
||||
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE2);
|
||||
dma_cap->aux_snapshot_n = (hw_cap & XGMAC_HWFEAT_AUXSNAPNUM) >> 28;
|
||||
dma_cap->pps_out_num = (hw_cap & XGMAC_HWFEAT_PPSOUTNUM) >> 24;
|
||||
dma_cap->number_tx_channel =
|
||||
((hw_cap & XGMAC_HWFEAT_TXCHCNT) >> 18) + 1;
|
||||
dma_cap->number_rx_channel =
|
||||
((hw_cap & XGMAC_HWFEAT_RXCHCNT) >> 12) + 1;
|
||||
dma_cap->number_tx_queues =
|
||||
((hw_cap & XGMAC_HWFEAT_TXQCNT) >> 6) + 1;
|
||||
dma_cap->number_rx_queues =
|
||||
((hw_cap & XGMAC_HWFEAT_RXQCNT) >> 0) + 1;
|
||||
|
||||
/* MAC HW feature 3 */
|
||||
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE3);
|
||||
dma_cap->tbs_ch_num = ((hw_cap & XGMAC_HWFEAT_TBSCH) >> 28) + 1;
|
||||
dma_cap->tbssel = (hw_cap & XGMAC_HWFEAT_TBSSEL) >> 27;
|
||||
dma_cap->fpesel = (hw_cap & XGMAC_HWFEAT_FPESEL) >> 26;
|
||||
dma_cap->sgfsel = (hw_cap & XGMAC_HWFEAT_SGFSEL) >> 25;
|
||||
dma_cap->estwid = (hw_cap & XGMAC_HWFEAT_ESTWID) >> 23;
|
||||
dma_cap->estdep = (hw_cap & XGMAC_HWFEAT_ESTDEP) >> 20;
|
||||
dma_cap->estsel = (hw_cap & XGMAC_HWFEAT_ESTSEL) >> 19;
|
||||
dma_cap->ttsfd = (hw_cap & XGMAC_HWFEAT_TTSFD) >> 16;
|
||||
dma_cap->asp = (hw_cap & XGMAC_HWFEAT_ASP) >> 14;
|
||||
dma_cap->dvlan = (hw_cap & XGMAC_HWFEAT_DVLAN) >> 13;
|
||||
dma_cap->frpes = (hw_cap & XGMAC_HWFEAT_FRPES) >> 11;
|
||||
dma_cap->frpbs = (hw_cap & XGMAC_HWFEAT_FRPPB) >> 9;
|
||||
dma_cap->pou_ost_en = (hw_cap & XGMAC_HWFEAT_POUOST) >> 8;
|
||||
dma_cap->frppipe_num = ((hw_cap & XGMAC_HWFEAT_FRPPIPE) >> 5) + 1;
|
||||
dma_cap->cbtisel = (hw_cap & XGMAC_HWFEAT_CBTISEL) >> 4;
|
||||
dma_cap->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3;
|
||||
dma_cap->nrvf_num = (hw_cap & XGMAC_HWFEAT_NRVF) >> 0;
|
||||
|
||||
/* MAC HW feature 4 */
|
||||
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE4);
|
||||
dma_cap->asp |= (hw_cap & XGMAC_HWFEAT_EASP) >> 2;
|
||||
dma_cap->pcsel = (hw_cap & XGMAC_HWFEAT_PCSEL) >> 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwxgmac2_rx_watchdog(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 riwt, u32 queue)
|
||||
{
|
||||
writel(riwt & XGMAC_RWT, ioaddr + XGMAC_DMA_CH_Rx_WATCHDOG(queue));
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_rx_ring_len(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 len, u32 chan)
|
||||
{
|
||||
writel(len, ioaddr + XGMAC_DMA_CH_RxDESC_RING_LEN(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_tx_ring_len(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 len, u32 chan)
|
||||
{
|
||||
writel(len, ioaddr + XGMAC_DMA_CH_TxDESC_RING_LEN(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_rx_tail_ptr(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 ptr, u32 chan)
|
||||
{
|
||||
writel(ptr, ioaddr + XGMAC_DMA_CH_RxDESC_TAIL_LPTR(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_tx_tail_ptr(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 ptr, u32 chan)
|
||||
{
|
||||
writel(ptr, ioaddr + XGMAC_DMA_CH_TxDESC_TAIL_LPTR(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_enable_tso(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
|
||||
if (en)
|
||||
value |= XGMAC_TSE;
|
||||
else
|
||||
value &= ~XGMAC_TSE;
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_qmode(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 channel, u8 qmode)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
|
||||
u32 flow = readl(ioaddr + XGMAC_RX_FLOW_CTRL);
|
||||
|
||||
value &= ~XGMAC_TXQEN;
|
||||
if (qmode != MTL_QUEUE_AVB) {
|
||||
value |= 0x2 << XGMAC_TXQEN_SHIFT;
|
||||
writel(0, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(channel));
|
||||
} else {
|
||||
value |= 0x1 << XGMAC_TXQEN_SHIFT;
|
||||
writel(flow & (~XGMAC_RFE), ioaddr + XGMAC_RX_FLOW_CTRL);
|
||||
}
|
||||
|
||||
writel(value, ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_bfsize(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int bfsize, u32 chan)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
value &= ~XGMAC_RBSZ;
|
||||
value |= bfsize << XGMAC_RBSZ_SHIFT;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_enable_sph(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_RX_CONFIG);
|
||||
|
||||
value &= ~XGMAC_CONFIG_HDSMS;
|
||||
value |= XGMAC_CONFIG_HDSMS_256; /* Segment max 256 bytes */
|
||||
writel(value, ioaddr + XGMAC_RX_CONFIG);
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(chan));
|
||||
if (en)
|
||||
value |= XGMAC_SPH;
|
||||
else
|
||||
value &= ~XGMAC_SPH;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(chan));
|
||||
}
|
||||
|
||||
static int dwxgmac2_enable_tbs(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
|
||||
if (en)
|
||||
value |= XGMAC_EDSE;
|
||||
else
|
||||
value &= ~XGMAC_EDSE;
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)) & XGMAC_EDSE;
|
||||
if (en && !value)
|
||||
return -EIO;
|
||||
|
||||
writel(XGMAC_DEF_FTOS, ioaddr + XGMAC_DMA_TBS_CTRL0);
|
||||
writel(XGMAC_DEF_FTOS, ioaddr + XGMAC_DMA_TBS_CTRL1);
|
||||
writel(XGMAC_DEF_FTOS, ioaddr + XGMAC_DMA_TBS_CTRL2);
|
||||
writel(XGMAC_DEF_FTOS, ioaddr + XGMAC_DMA_TBS_CTRL3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct stmmac_dma_ops dwxgmac210_dma_ops = {
|
||||
.reset = dwxgmac2_dma_reset,
|
||||
.init = dwxgmac2_dma_init,
|
||||
.init_chan = dwxgmac2_dma_init_chan,
|
||||
.init_rx_chan = dwxgmac2_dma_init_rx_chan,
|
||||
.init_tx_chan = dwxgmac2_dma_init_tx_chan,
|
||||
.axi = dwxgmac2_dma_axi,
|
||||
.dump_regs = dwxgmac2_dma_dump_regs,
|
||||
.dma_rx_mode = dwxgmac2_dma_rx_mode,
|
||||
.dma_tx_mode = dwxgmac2_dma_tx_mode,
|
||||
.enable_dma_irq = dwxgmac2_enable_dma_irq,
|
||||
.disable_dma_irq = dwxgmac2_disable_dma_irq,
|
||||
.start_tx = dwxgmac2_dma_start_tx,
|
||||
.stop_tx = dwxgmac2_dma_stop_tx,
|
||||
.start_rx = dwxgmac2_dma_start_rx,
|
||||
.stop_rx = dwxgmac2_dma_stop_rx,
|
||||
.dma_interrupt = dwxgmac2_dma_interrupt,
|
||||
.get_hw_feature = dwxgmac2_get_hw_feature,
|
||||
.rx_watchdog = dwxgmac2_rx_watchdog,
|
||||
.set_rx_ring_len = dwxgmac2_set_rx_ring_len,
|
||||
.set_tx_ring_len = dwxgmac2_set_tx_ring_len,
|
||||
.set_rx_tail_ptr = dwxgmac2_set_rx_tail_ptr,
|
||||
.set_tx_tail_ptr = dwxgmac2_set_tx_tail_ptr,
|
||||
.enable_tso = dwxgmac2_enable_tso,
|
||||
.qmode = dwxgmac2_qmode,
|
||||
.set_bfsize = dwxgmac2_set_bfsize,
|
||||
.enable_sph = dwxgmac2_enable_sph,
|
||||
.enable_tbs = dwxgmac2_enable_tbs,
|
||||
};
|
||||
|
|
@ -0,0 +1,643 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
|
||||
* stmmac XGMAC support.
|
||||
*/
|
||||
|
||||
#include <linux/iopoll.h>
|
||||
#include "stmmac.h"
|
||||
#include "dwxgmac2.h"
|
||||
|
||||
static int dwxgmac2_dma_reset(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_MODE);
|
||||
|
||||
/* DMA SW reset */
|
||||
writel(value | XGMAC_SWR, ioaddr + XGMAC_DMA_MODE);
|
||||
|
||||
return readl_poll_timeout(ioaddr + XGMAC_DMA_MODE, value,
|
||||
!(value & XGMAC_SWR), 0, 100000);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_init(void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_SYSBUS_MODE);
|
||||
|
||||
if (dma_cfg->aal)
|
||||
value |= XGMAC_AAL;
|
||||
|
||||
if (dma_cfg->eame)
|
||||
value |= XGMAC_EAME;
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_SYSBUS_MODE);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_init_chan(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg, u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(chan));
|
||||
|
||||
if (dma_cfg->pblx8)
|
||||
value |= XGMAC_PBLx8;
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(chan));
|
||||
writel(XGMAC_DMA_INT_DEFAULT_EN, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_init_rx_chan(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t phy, u32 chan)
|
||||
{
|
||||
u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
value &= ~XGMAC_RxPBL;
|
||||
value |= (rxpbl << XGMAC_RxPBL_SHIFT) & XGMAC_RxPBL;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
|
||||
writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_HADDR(chan));
|
||||
writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_LADDR(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t phy, u32 chan)
|
||||
{
|
||||
u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
value &= ~XGMAC_TxPBL;
|
||||
value |= (txpbl << XGMAC_TxPBL_SHIFT) & XGMAC_TxPBL;
|
||||
value |= XGMAC_OSP;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
|
||||
writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_HADDR(chan));
|
||||
writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_SYSBUS_MODE);
|
||||
int i;
|
||||
|
||||
if (axi->axi_lpi_en)
|
||||
value |= XGMAC_EN_LPI;
|
||||
if (axi->axi_xit_frm)
|
||||
value |= XGMAC_LPI_XIT_PKT;
|
||||
|
||||
value &= ~XGMAC_WR_OSR_LMT;
|
||||
value |= (axi->axi_wr_osr_lmt << XGMAC_WR_OSR_LMT_SHIFT) &
|
||||
XGMAC_WR_OSR_LMT;
|
||||
|
||||
value &= ~XGMAC_RD_OSR_LMT;
|
||||
value |= (axi->axi_rd_osr_lmt << XGMAC_RD_OSR_LMT_SHIFT) &
|
||||
XGMAC_RD_OSR_LMT;
|
||||
|
||||
if (!axi->axi_fb)
|
||||
value |= XGMAC_UNDEF;
|
||||
|
||||
value &= ~XGMAC_BLEN;
|
||||
for (i = 0; i < AXI_BLEN; i++) {
|
||||
switch (axi->axi_blen[i]) {
|
||||
case 256:
|
||||
value |= XGMAC_BLEN256;
|
||||
break;
|
||||
case 128:
|
||||
value |= XGMAC_BLEN128;
|
||||
break;
|
||||
case 64:
|
||||
value |= XGMAC_BLEN64;
|
||||
break;
|
||||
case 32:
|
||||
value |= XGMAC_BLEN32;
|
||||
break;
|
||||
case 16:
|
||||
value |= XGMAC_BLEN16;
|
||||
break;
|
||||
case 8:
|
||||
value |= XGMAC_BLEN8;
|
||||
break;
|
||||
case 4:
|
||||
value |= XGMAC_BLEN4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_SYSBUS_MODE);
|
||||
writel(XGMAC_TDPS, ioaddr + XGMAC_TX_EDMA_CTRL);
|
||||
writel(XGMAC_RDPS, ioaddr + XGMAC_RX_EDMA_CTRL);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_dump_regs(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 *reg_space)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = (XGMAC_DMA_MODE / 4); i < XGMAC_REGSIZE; i++)
|
||||
reg_space[i] = readl(ioaddr + i * 4);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int mode, u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_MTL_RXQ_OPMODE(channel));
|
||||
unsigned int rqs = fifosz / 256 - 1;
|
||||
|
||||
if (mode == SF_DMA_MODE) {
|
||||
value |= XGMAC_RSF;
|
||||
} else {
|
||||
value &= ~XGMAC_RSF;
|
||||
value &= ~XGMAC_RTC;
|
||||
|
||||
if (mode <= 64)
|
||||
value |= 0x0 << XGMAC_RTC_SHIFT;
|
||||
else if (mode <= 96)
|
||||
value |= 0x2 << XGMAC_RTC_SHIFT;
|
||||
else
|
||||
value |= 0x3 << XGMAC_RTC_SHIFT;
|
||||
}
|
||||
|
||||
value &= ~XGMAC_RQS;
|
||||
value |= (rqs << XGMAC_RQS_SHIFT) & XGMAC_RQS;
|
||||
|
||||
if ((fifosz >= 4096) && (qmode != MTL_QUEUE_AVB)) {
|
||||
u32 flow = readl(ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(channel));
|
||||
unsigned int rfd, rfa;
|
||||
|
||||
value |= XGMAC_EHFC;
|
||||
|
||||
/* Set Threshold for Activating Flow Control to min 2 frames,
|
||||
* i.e. 1500 * 2 = 3000 bytes.
|
||||
*
|
||||
* Set Threshold for Deactivating Flow Control to min 1 frame,
|
||||
* i.e. 1500 bytes.
|
||||
*/
|
||||
switch (fifosz) {
|
||||
case 4096:
|
||||
/* This violates the above formula because of FIFO size
|
||||
* limit therefore overflow may occur in spite of this.
|
||||
*/
|
||||
rfd = 0x03; /* Full-2.5K */
|
||||
rfa = 0x01; /* Full-1.5K */
|
||||
break;
|
||||
|
||||
default:
|
||||
rfd = 0x07; /* Full-4.5K */
|
||||
rfa = 0x04; /* Full-3K */
|
||||
break;
|
||||
}
|
||||
|
||||
flow &= ~XGMAC_RFD;
|
||||
flow |= rfd << XGMAC_RFD_SHIFT;
|
||||
|
||||
flow &= ~XGMAC_RFA;
|
||||
flow |= rfa << XGMAC_RFA_SHIFT;
|
||||
|
||||
writel(flow, ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(channel));
|
||||
}
|
||||
|
||||
writel(value, ioaddr + XGMAC_MTL_RXQ_OPMODE(channel));
|
||||
|
||||
/* Enable MTL RX overflow */
|
||||
value = readl(ioaddr + XGMAC_MTL_QINTEN(channel));
|
||||
writel(value | XGMAC_RXOIE, ioaddr + XGMAC_MTL_QINTEN(channel));
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int mode, u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
|
||||
unsigned int tqs = fifosz / 256 - 1;
|
||||
|
||||
if (mode == SF_DMA_MODE) {
|
||||
value |= XGMAC_TSF;
|
||||
} else {
|
||||
value &= ~XGMAC_TSF;
|
||||
value &= ~XGMAC_TTC;
|
||||
|
||||
if (mode <= 64)
|
||||
value |= 0x0 << XGMAC_TTC_SHIFT;
|
||||
else if (mode <= 96)
|
||||
value |= 0x2 << XGMAC_TTC_SHIFT;
|
||||
else if (mode <= 128)
|
||||
value |= 0x3 << XGMAC_TTC_SHIFT;
|
||||
else if (mode <= 192)
|
||||
value |= 0x4 << XGMAC_TTC_SHIFT;
|
||||
else if (mode <= 256)
|
||||
value |= 0x5 << XGMAC_TTC_SHIFT;
|
||||
else if (mode <= 384)
|
||||
value |= 0x6 << XGMAC_TTC_SHIFT;
|
||||
else
|
||||
value |= 0x7 << XGMAC_TTC_SHIFT;
|
||||
}
|
||||
|
||||
/* Use static TC to Queue mapping */
|
||||
value |= (channel << XGMAC_Q2TCMAP_SHIFT) & XGMAC_Q2TCMAP;
|
||||
|
||||
value &= ~XGMAC_TXQEN;
|
||||
if (qmode != MTL_QUEUE_AVB)
|
||||
value |= 0x2 << XGMAC_TXQEN_SHIFT;
|
||||
else
|
||||
value |= 0x1 << XGMAC_TXQEN_SHIFT;
|
||||
|
||||
value &= ~XGMAC_TQS;
|
||||
value |= (tqs << XGMAC_TQS_SHIFT) & XGMAC_TQS;
|
||||
|
||||
writel(value, ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
|
||||
}
|
||||
|
||||
static void dwxgmac2_enable_dma_irq(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 chan,
|
||||
bool rx, bool tx)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
|
||||
|
||||
if (rx)
|
||||
value |= XGMAC_DMA_INT_DEFAULT_RX;
|
||||
if (tx)
|
||||
value |= XGMAC_DMA_INT_DEFAULT_TX;
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_disable_dma_irq(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 chan,
|
||||
bool rx, bool tx)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
|
||||
|
||||
if (rx)
|
||||
value &= ~XGMAC_DMA_INT_DEFAULT_RX;
|
||||
if (tx)
|
||||
value &= ~XGMAC_DMA_INT_DEFAULT_TX;
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_start_tx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 chan)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
value |= XGMAC_TXST;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
|
||||
value = readl(ioaddr + XGMAC_TX_CONFIG);
|
||||
value |= XGMAC_CONFIG_TE;
|
||||
writel(value, ioaddr + XGMAC_TX_CONFIG);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
value &= ~XGMAC_TXST;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
|
||||
value = readl(ioaddr + XGMAC_TX_CONFIG);
|
||||
value &= ~XGMAC_CONFIG_TE;
|
||||
writel(value, ioaddr + XGMAC_TX_CONFIG);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_start_rx(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 chan)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
value |= XGMAC_RXST;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
|
||||
value = readl(ioaddr + XGMAC_RX_CONFIG);
|
||||
value |= XGMAC_CONFIG_RE;
|
||||
writel(value, ioaddr + XGMAC_RX_CONFIG);
|
||||
}
|
||||
|
||||
static void dwxgmac2_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
value &= ~XGMAC_RXST;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
}
|
||||
|
||||
static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 chan,
|
||||
u32 dir)
|
||||
{
|
||||
struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);
|
||||
u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan));
|
||||
u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
|
||||
int ret = 0;
|
||||
|
||||
if (dir == DMA_DIR_RX)
|
||||
intr_status &= XGMAC_DMA_STATUS_MSK_RX;
|
||||
else if (dir == DMA_DIR_TX)
|
||||
intr_status &= XGMAC_DMA_STATUS_MSK_TX;
|
||||
|
||||
/* ABNORMAL interrupts */
|
||||
if (unlikely(intr_status & XGMAC_AIS)) {
|
||||
if (unlikely(intr_status & XGMAC_RBU)) {
|
||||
x->rx_buf_unav_irq++;
|
||||
ret |= handle_rx;
|
||||
}
|
||||
if (unlikely(intr_status & XGMAC_TPS)) {
|
||||
x->tx_process_stopped_irq++;
|
||||
ret |= tx_hard_error;
|
||||
}
|
||||
if (unlikely(intr_status & XGMAC_FBE)) {
|
||||
x->fatal_bus_error_irq++;
|
||||
ret |= tx_hard_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* TX/RX NORMAL interrupts */
|
||||
if (likely(intr_status & XGMAC_NIS)) {
|
||||
if (likely(intr_status & XGMAC_RI)) {
|
||||
u64_stats_update_begin(&stats->syncp);
|
||||
u64_stats_inc(&stats->rx_normal_irq_n[chan]);
|
||||
u64_stats_update_end(&stats->syncp);
|
||||
ret |= handle_rx;
|
||||
}
|
||||
if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) {
|
||||
u64_stats_update_begin(&stats->syncp);
|
||||
u64_stats_inc(&stats->tx_normal_irq_n[chan]);
|
||||
u64_stats_update_end(&stats->syncp);
|
||||
ret |= handle_tx;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear interrupts */
|
||||
writel(intr_en & intr_status, ioaddr + XGMAC_DMA_CH_STATUS(chan));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwxgmac2_get_hw_feature(void __iomem *ioaddr,
|
||||
struct dma_features *dma_cap)
|
||||
{
|
||||
u32 hw_cap;
|
||||
|
||||
/* MAC HW feature 0 */
|
||||
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE0);
|
||||
dma_cap->edma = (hw_cap & XGMAC_HWFEAT_EDMA) >> 31;
|
||||
dma_cap->ediffc = (hw_cap & XGMAC_HWFEAT_EDIFFC) >> 30;
|
||||
dma_cap->vxn = (hw_cap & XGMAC_HWFEAT_VXN) >> 29;
|
||||
dma_cap->vlins = (hw_cap & XGMAC_HWFEAT_SAVLANINS) >> 27;
|
||||
dma_cap->tssrc = (hw_cap & XGMAC_HWFEAT_TSSTSSEL) >> 25;
|
||||
dma_cap->multi_addr = (hw_cap & XGMAC_HWFEAT_ADDMACADRSEL) >> 18;
|
||||
dma_cap->rx_coe = (hw_cap & XGMAC_HWFEAT_RXCOESEL) >> 16;
|
||||
dma_cap->tx_coe = (hw_cap & XGMAC_HWFEAT_TXCOESEL) >> 14;
|
||||
dma_cap->eee = (hw_cap & XGMAC_HWFEAT_EEESEL) >> 13;
|
||||
dma_cap->atime_stamp = (hw_cap & XGMAC_HWFEAT_TSSEL) >> 12;
|
||||
dma_cap->av = (hw_cap & XGMAC_HWFEAT_AVSEL) >> 11;
|
||||
dma_cap->av &= !((hw_cap & XGMAC_HWFEAT_RAVSEL) >> 10);
|
||||
dma_cap->arpoffsel = (hw_cap & XGMAC_HWFEAT_ARPOFFSEL) >> 9;
|
||||
dma_cap->rmon = (hw_cap & XGMAC_HWFEAT_MMCSEL) >> 8;
|
||||
dma_cap->pmt_magic_frame = (hw_cap & XGMAC_HWFEAT_MGKSEL) >> 7;
|
||||
dma_cap->pmt_remote_wake_up = (hw_cap & XGMAC_HWFEAT_RWKSEL) >> 6;
|
||||
dma_cap->sma_mdio = (hw_cap & XGMAC_HWFEAT_SMASEL) >> 5;
|
||||
dma_cap->vlhash = (hw_cap & XGMAC_HWFEAT_VLHASH) >> 4;
|
||||
dma_cap->half_duplex = (hw_cap & XGMAC_HWFEAT_HDSEL) >> 3;
|
||||
dma_cap->mbps_1000 = (hw_cap & XGMAC_HWFEAT_GMIISEL) >> 1;
|
||||
|
||||
/* MAC HW feature 1 */
|
||||
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1);
|
||||
dma_cap->l3l4fnum = (hw_cap & XGMAC_HWFEAT_L3L4FNUM) >> 27;
|
||||
/* If L3L4FNUM < 8, then the number of L3L4 filters supported by
|
||||
* XGMAC is equal to L3L4FNUM. From L3L4FNUM >= 8 the number of
|
||||
* L3L4 filters goes on like 8, 16, 32, ... Current maximum of
|
||||
* L3L4FNUM = 10.
|
||||
*/
|
||||
if (dma_cap->l3l4fnum >= 8 && dma_cap->l3l4fnum <= 10)
|
||||
dma_cap->l3l4fnum = 8 << (dma_cap->l3l4fnum - 8);
|
||||
else if (dma_cap->l3l4fnum > 10)
|
||||
dma_cap->l3l4fnum = 32;
|
||||
|
||||
dma_cap->hash_tb_sz = (hw_cap & XGMAC_HWFEAT_HASHTBLSZ) >> 24;
|
||||
dma_cap->numtc = ((hw_cap & XGMAC_HWFEAT_NUMTC) >> 21) + 1;
|
||||
dma_cap->rssen = (hw_cap & XGMAC_HWFEAT_RSSEN) >> 20;
|
||||
dma_cap->dbgmem = (hw_cap & XGMAC_HWFEAT_DBGMEMA) >> 19;
|
||||
dma_cap->tsoen = (hw_cap & XGMAC_HWFEAT_TSOEN) >> 18;
|
||||
dma_cap->sphen = (hw_cap & XGMAC_HWFEAT_SPHEN) >> 17;
|
||||
dma_cap->dcben = (hw_cap & XGMAC_HWFEAT_DCBEN) >> 16;
|
||||
|
||||
dma_cap->addr64 = (hw_cap & XGMAC_HWFEAT_ADDR64) >> 14;
|
||||
switch (dma_cap->addr64) {
|
||||
case 0:
|
||||
dma_cap->addr64 = 32;
|
||||
break;
|
||||
case 1:
|
||||
dma_cap->addr64 = 40;
|
||||
break;
|
||||
case 2:
|
||||
dma_cap->addr64 = 48;
|
||||
break;
|
||||
default:
|
||||
dma_cap->addr64 = 32;
|
||||
break;
|
||||
}
|
||||
|
||||
dma_cap->advthword = (hw_cap & XGMAC_HWFEAT_ADVTHWORD) >> 13;
|
||||
dma_cap->ptoen = (hw_cap & XGMAC_HWFEAT_PTOEN) >> 12;
|
||||
dma_cap->osten = (hw_cap & XGMAC_HWFEAT_OSTEN) >> 11;
|
||||
dma_cap->tx_fifo_size =
|
||||
128 << ((hw_cap & XGMAC_HWFEAT_TXFIFOSIZE) >> 6);
|
||||
dma_cap->pfcen = (hw_cap & XGMAC_HWFEAT_PFCEN) >> 5;
|
||||
dma_cap->rx_fifo_size =
|
||||
128 << ((hw_cap & XGMAC_HWFEAT_RXFIFOSIZE) >> 0);
|
||||
|
||||
/* MAC HW feature 2 */
|
||||
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE2);
|
||||
dma_cap->aux_snapshot_n = (hw_cap & XGMAC_HWFEAT_AUXSNAPNUM) >> 28;
|
||||
dma_cap->pps_out_num = (hw_cap & XGMAC_HWFEAT_PPSOUTNUM) >> 24;
|
||||
dma_cap->number_tx_channel =
|
||||
((hw_cap & XGMAC_HWFEAT_TXCHCNT) >> 18) + 1;
|
||||
dma_cap->number_rx_channel =
|
||||
((hw_cap & XGMAC_HWFEAT_RXCHCNT) >> 12) + 1;
|
||||
dma_cap->number_tx_queues =
|
||||
((hw_cap & XGMAC_HWFEAT_TXQCNT) >> 6) + 1;
|
||||
dma_cap->number_rx_queues =
|
||||
((hw_cap & XGMAC_HWFEAT_RXQCNT) >> 0) + 1;
|
||||
|
||||
/* MAC HW feature 3 */
|
||||
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE3);
|
||||
dma_cap->tbs_ch_num = ((hw_cap & XGMAC_HWFEAT_TBSCH) >> 28) + 1;
|
||||
dma_cap->tbssel = (hw_cap & XGMAC_HWFEAT_TBSSEL) >> 27;
|
||||
dma_cap->fpesel = (hw_cap & XGMAC_HWFEAT_FPESEL) >> 26;
|
||||
dma_cap->sgfsel = (hw_cap & XGMAC_HWFEAT_SGFSEL) >> 25;
|
||||
dma_cap->estwid = (hw_cap & XGMAC_HWFEAT_ESTWID) >> 23;
|
||||
dma_cap->estdep = (hw_cap & XGMAC_HWFEAT_ESTDEP) >> 20;
|
||||
dma_cap->estsel = (hw_cap & XGMAC_HWFEAT_ESTSEL) >> 19;
|
||||
dma_cap->ttsfd = (hw_cap & XGMAC_HWFEAT_TTSFD) >> 16;
|
||||
dma_cap->asp = (hw_cap & XGMAC_HWFEAT_ASP) >> 14;
|
||||
dma_cap->dvlan = (hw_cap & XGMAC_HWFEAT_DVLAN) >> 13;
|
||||
dma_cap->frpes = (hw_cap & XGMAC_HWFEAT_FRPES) >> 11;
|
||||
dma_cap->frpbs = (hw_cap & XGMAC_HWFEAT_FRPPB) >> 9;
|
||||
dma_cap->pou_ost_en = (hw_cap & XGMAC_HWFEAT_POUOST) >> 8;
|
||||
dma_cap->frppipe_num = ((hw_cap & XGMAC_HWFEAT_FRPPIPE) >> 5) + 1;
|
||||
dma_cap->cbtisel = (hw_cap & XGMAC_HWFEAT_CBTISEL) >> 4;
|
||||
dma_cap->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3;
|
||||
dma_cap->nrvf_num = (hw_cap & XGMAC_HWFEAT_NRVF) >> 0;
|
||||
|
||||
/* MAC HW feature 4 */
|
||||
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE4);
|
||||
dma_cap->asp |= (hw_cap & XGMAC_HWFEAT_EASP) >> 2;
|
||||
dma_cap->pcsel = (hw_cap & XGMAC_HWFEAT_PCSEL) >> 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwxgmac2_rx_watchdog(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 riwt, u32 queue)
|
||||
{
|
||||
writel(riwt & XGMAC_RWT, ioaddr + XGMAC_DMA_CH_Rx_WATCHDOG(queue));
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_rx_ring_len(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 len, u32 chan)
|
||||
{
|
||||
writel(len, ioaddr + XGMAC_DMA_CH_RxDESC_RING_LEN(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_tx_ring_len(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 len, u32 chan)
|
||||
{
|
||||
writel(len, ioaddr + XGMAC_DMA_CH_TxDESC_RING_LEN(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_rx_tail_ptr(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 ptr, u32 chan)
|
||||
{
|
||||
writel(ptr, ioaddr + XGMAC_DMA_CH_RxDESC_TAIL_LPTR(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_tx_tail_ptr(struct stmmac_priv *priv,
|
||||
void __iomem *ioaddr, u32 ptr, u32 chan)
|
||||
{
|
||||
writel(ptr, ioaddr + XGMAC_DMA_CH_TxDESC_TAIL_LPTR(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_enable_tso(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
|
||||
if (en)
|
||||
value |= XGMAC_TSE;
|
||||
else
|
||||
value &= ~XGMAC_TSE;
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_qmode(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 channel, u8 qmode)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
|
||||
u32 flow = readl(ioaddr + XGMAC_RX_FLOW_CTRL);
|
||||
|
||||
value &= ~XGMAC_TXQEN;
|
||||
if (qmode != MTL_QUEUE_AVB) {
|
||||
value |= 0x2 << XGMAC_TXQEN_SHIFT;
|
||||
writel(0, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(channel));
|
||||
} else {
|
||||
value |= 0x1 << XGMAC_TXQEN_SHIFT;
|
||||
writel(flow & (~XGMAC_RFE), ioaddr + XGMAC_RX_FLOW_CTRL);
|
||||
}
|
||||
|
||||
writel(value, ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
|
||||
}
|
||||
|
||||
static void dwxgmac2_set_bfsize(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int bfsize, u32 chan)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
value &= ~XGMAC_RBSZ;
|
||||
value |= bfsize << XGMAC_RBSZ_SHIFT;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
|
||||
}
|
||||
|
||||
static void dwxgmac2_enable_sph(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_RX_CONFIG);
|
||||
|
||||
value &= ~XGMAC_CONFIG_HDSMS;
|
||||
value |= XGMAC_CONFIG_HDSMS_256; /* Segment max 256 bytes */
|
||||
writel(value, ioaddr + XGMAC_RX_CONFIG);
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(chan));
|
||||
if (en)
|
||||
value |= XGMAC_SPH;
|
||||
else
|
||||
value &= ~XGMAC_SPH;
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(chan));
|
||||
}
|
||||
|
||||
static int dwxgmac2_enable_tbs(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan)
|
||||
{
|
||||
u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
|
||||
if (en)
|
||||
value |= XGMAC_EDSE;
|
||||
else
|
||||
value &= ~XGMAC_EDSE;
|
||||
|
||||
writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
|
||||
|
||||
value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)) & XGMAC_EDSE;
|
||||
if (en && !value)
|
||||
return -EIO;
|
||||
|
||||
writel(XGMAC_DEF_FTOS, ioaddr + XGMAC_DMA_TBS_CTRL0);
|
||||
writel(XGMAC_DEF_FTOS, ioaddr + XGMAC_DMA_TBS_CTRL1);
|
||||
writel(XGMAC_DEF_FTOS, ioaddr + XGMAC_DMA_TBS_CTRL2);
|
||||
writel(XGMAC_DEF_FTOS, ioaddr + XGMAC_DMA_TBS_CTRL3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct stmmac_dma_ops dwxgmac210_dma_ops = {
|
||||
.reset = dwxgmac2_dma_reset,
|
||||
.init = dwxgmac2_dma_init,
|
||||
.init_chan = dwxgmac2_dma_init_chan,
|
||||
.init_rx_chan = dwxgmac2_dma_init_rx_chan,
|
||||
.init_tx_chan = dwxgmac2_dma_init_tx_chan,
|
||||
.axi = dwxgmac2_dma_axi,
|
||||
.dump_regs = dwxgmac2_dma_dump_regs,
|
||||
.dma_rx_mode = dwxgmac2_dma_rx_mode,
|
||||
.dma_tx_mode = dwxgmac2_dma_tx_mode,
|
||||
.enable_dma_irq = dwxgmac2_enable_dma_irq,
|
||||
.disable_dma_irq = dwxgmac2_disable_dma_irq,
|
||||
.start_tx = dwxgmac2_dma_start_tx,
|
||||
.stop_tx = dwxgmac2_dma_stop_tx,
|
||||
.start_rx = dwxgmac2_dma_start_rx,
|
||||
.stop_rx = dwxgmac2_dma_stop_rx,
|
||||
.dma_interrupt = dwxgmac2_dma_interrupt,
|
||||
.get_hw_feature = dwxgmac2_get_hw_feature,
|
||||
.rx_watchdog = dwxgmac2_rx_watchdog,
|
||||
.set_rx_ring_len = dwxgmac2_set_rx_ring_len,
|
||||
.set_tx_ring_len = dwxgmac2_set_tx_ring_len,
|
||||
.set_rx_tail_ptr = dwxgmac2_set_rx_tail_ptr,
|
||||
.set_tx_tail_ptr = dwxgmac2_set_tx_tail_ptr,
|
||||
.enable_tso = dwxgmac2_enable_tso,
|
||||
.qmode = dwxgmac2_qmode,
|
||||
.set_bfsize = dwxgmac2_set_bfsize,
|
||||
.enable_sph = dwxgmac2_enable_sph,
|
||||
.enable_tbs = dwxgmac2_enable_tbs,
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2020 Synopsys, Inc. and/or its affiliates.
|
||||
* Synopsys DesignWare XLGMAC definitions.
|
||||
*/
|
||||
|
||||
#ifndef __STMMAC_DWXLGMAC2_H__
|
||||
#define __STMMAC_DWXLGMAC2_H__
|
||||
|
||||
/* MAC Registers */
|
||||
#define XLGMAC_CONFIG_SS GENMASK(30, 28)
|
||||
#define XLGMAC_CONFIG_SS_SHIFT 28
|
||||
#define XLGMAC_CONFIG_SS_40G (0x0 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_CONFIG_SS_25G (0x1 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_CONFIG_SS_50G (0x2 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_CONFIG_SS_100G (0x3 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_CONFIG_SS_10G (0x4 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_CONFIG_SS_2500 (0x6 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_CONFIG_SS_1000 (0x7 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_RXQ_ENABLE_CTRL0 0x00000140
|
||||
|
||||
#endif /* __STMMAC_DWXLGMAC2_H__ */
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2020 Synopsys, Inc. and/or its affiliates.
|
||||
* Synopsys DesignWare XLGMAC definitions.
|
||||
*/
|
||||
|
||||
#ifndef __STMMAC_DWXLGMAC2_H__
|
||||
#define __STMMAC_DWXLGMAC2_H__
|
||||
|
||||
/* MAC Registers */
|
||||
#define XLGMAC_CONFIG_SS GENMASK(30, 28)
|
||||
#define XLGMAC_CONFIG_SS_SHIFT 28
|
||||
#define XLGMAC_CONFIG_SS_40G (0x0 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_CONFIG_SS_25G (0x1 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_CONFIG_SS_50G (0x2 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_CONFIG_SS_100G (0x3 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_CONFIG_SS_10G (0x4 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_CONFIG_SS_2500 (0x6 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_CONFIG_SS_1000 (0x7 << XLGMAC_CONFIG_SS_SHIFT)
|
||||
#define XLGMAC_RXQ_ENABLE_CTRL0 0x00000140
|
||||
|
||||
#endif /* __STMMAC_DWXLGMAC2_H__ */
|
||||
|
|
@ -0,0 +1,470 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This contains the functions to handle the enhanced descriptors.
|
||||
|
||||
Copyright (C) 2007-2014 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/stmmac.h>
|
||||
#include "common-6.12-ethercat.h"
|
||||
#include "descs_com-6.12-ethercat.h"
|
||||
|
||||
static int enh_desc_get_tx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p, void __iomem *ioaddr)
|
||||
{
|
||||
unsigned int tdes0 = le32_to_cpu(p->des0);
|
||||
int ret = tx_done;
|
||||
|
||||
/* Get tx owner first */
|
||||
if (unlikely(tdes0 & ETDES0_OWN))
|
||||
return tx_dma_own;
|
||||
|
||||
/* Verify tx error by looking at the last segment. */
|
||||
if (likely(!(tdes0 & ETDES0_LAST_SEGMENT)))
|
||||
return tx_not_ls;
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_ERROR_SUMMARY)) {
|
||||
if (unlikely(tdes0 & ETDES0_JABBER_TIMEOUT))
|
||||
x->tx_jabber++;
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_FRAME_FLUSHED)) {
|
||||
x->tx_frame_flushed++;
|
||||
dwmac_dma_flush_tx_fifo(ioaddr);
|
||||
}
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_LOSS_CARRIER)) {
|
||||
x->tx_losscarrier++;
|
||||
}
|
||||
if (unlikely(tdes0 & ETDES0_NO_CARRIER)) {
|
||||
x->tx_carrier++;
|
||||
}
|
||||
if (unlikely((tdes0 & ETDES0_LATE_COLLISION) ||
|
||||
(tdes0 & ETDES0_EXCESSIVE_COLLISIONS)))
|
||||
x->tx_collision +=
|
||||
(tdes0 & ETDES0_COLLISION_COUNT_MASK) >> 3;
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_EXCESSIVE_DEFERRAL))
|
||||
x->tx_deferred++;
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_UNDERFLOW_ERROR)) {
|
||||
dwmac_dma_flush_tx_fifo(ioaddr);
|
||||
x->tx_underflow++;
|
||||
}
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_IP_HEADER_ERROR))
|
||||
x->tx_ip_header_error++;
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_PAYLOAD_ERROR)) {
|
||||
x->tx_payload_error++;
|
||||
dwmac_dma_flush_tx_fifo(ioaddr);
|
||||
}
|
||||
|
||||
ret = tx_err;
|
||||
}
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_DEFERRED))
|
||||
x->tx_deferred++;
|
||||
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
if (tdes0 & ETDES0_VLAN_FRAME)
|
||||
x->tx_vlan++;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_len(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des1) & ETDES1_BUFFER1_SIZE_MASK);
|
||||
}
|
||||
|
||||
static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
|
||||
{
|
||||
int ret = good_frame;
|
||||
u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7;
|
||||
|
||||
/* bits 5 7 0 | Frame status
|
||||
* ----------------------------------------------------------
|
||||
* 0 0 0 | IEEE 802.3 Type frame (length < 1536 octects)
|
||||
* 1 0 0 | IPv4/6 No CSUM errorS.
|
||||
* 1 0 1 | IPv4/6 CSUM PAYLOAD error
|
||||
* 1 1 0 | IPv4/6 CSUM IP HR error
|
||||
* 1 1 1 | IPv4/6 IP PAYLOAD AND HEADER errorS
|
||||
* 0 0 1 | IPv4/6 unsupported IP PAYLOAD
|
||||
* 0 1 1 | COE bypassed.. no IPv4/6 frame
|
||||
* 0 1 0 | Reserved.
|
||||
*/
|
||||
if (status == 0x0)
|
||||
ret = llc_snap;
|
||||
else if (status == 0x4)
|
||||
ret = good_frame;
|
||||
else if (status == 0x5)
|
||||
ret = csum_none;
|
||||
else if (status == 0x6)
|
||||
ret = csum_none;
|
||||
else if (status == 0x7)
|
||||
ret = csum_none;
|
||||
else if (status == 0x1)
|
||||
ret = discard_frame;
|
||||
else if (status == 0x3)
|
||||
ret = discard_frame;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void enh_desc_get_ext_status(struct stmmac_extra_stats *x,
|
||||
struct dma_extended_desc *p)
|
||||
{
|
||||
unsigned int rdes0 = le32_to_cpu(p->basic.des0);
|
||||
unsigned int rdes4 = le32_to_cpu(p->des4);
|
||||
|
||||
if (unlikely(rdes0 & ERDES0_RX_MAC_ADDR)) {
|
||||
int message_type = (rdes4 & ERDES4_MSG_TYPE_MASK) >> 8;
|
||||
|
||||
if (rdes4 & ERDES4_IP_HDR_ERR)
|
||||
x->ip_hdr_err++;
|
||||
if (rdes4 & ERDES4_IP_PAYLOAD_ERR)
|
||||
x->ip_payload_err++;
|
||||
if (rdes4 & ERDES4_IP_CSUM_BYPASSED)
|
||||
x->ip_csum_bypassed++;
|
||||
if (rdes4 & ERDES4_IPV4_PKT_RCVD)
|
||||
x->ipv4_pkt_rcvd++;
|
||||
if (rdes4 & ERDES4_IPV6_PKT_RCVD)
|
||||
x->ipv6_pkt_rcvd++;
|
||||
|
||||
if (message_type == RDES_EXT_NO_PTP)
|
||||
x->no_ptp_rx_msg_type_ext++;
|
||||
else if (message_type == RDES_EXT_SYNC)
|
||||
x->ptp_rx_msg_type_sync++;
|
||||
else if (message_type == RDES_EXT_FOLLOW_UP)
|
||||
x->ptp_rx_msg_type_follow_up++;
|
||||
else if (message_type == RDES_EXT_DELAY_REQ)
|
||||
x->ptp_rx_msg_type_delay_req++;
|
||||
else if (message_type == RDES_EXT_DELAY_RESP)
|
||||
x->ptp_rx_msg_type_delay_resp++;
|
||||
else if (message_type == RDES_EXT_PDELAY_REQ)
|
||||
x->ptp_rx_msg_type_pdelay_req++;
|
||||
else if (message_type == RDES_EXT_PDELAY_RESP)
|
||||
x->ptp_rx_msg_type_pdelay_resp++;
|
||||
else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP)
|
||||
x->ptp_rx_msg_type_pdelay_follow_up++;
|
||||
else if (message_type == RDES_PTP_ANNOUNCE)
|
||||
x->ptp_rx_msg_type_announce++;
|
||||
else if (message_type == RDES_PTP_MANAGEMENT)
|
||||
x->ptp_rx_msg_type_management++;
|
||||
else if (message_type == RDES_PTP_PKT_RESERVED_TYPE)
|
||||
x->ptp_rx_msg_pkt_reserved_type++;
|
||||
|
||||
if (rdes4 & ERDES4_PTP_FRAME_TYPE)
|
||||
x->ptp_frame_type++;
|
||||
if (rdes4 & ERDES4_PTP_VER)
|
||||
x->ptp_ver++;
|
||||
if (rdes4 & ERDES4_TIMESTAMP_DROPPED)
|
||||
x->timestamp_dropped++;
|
||||
if (rdes4 & ERDES4_AV_PKT_RCVD)
|
||||
x->av_pkt_rcvd++;
|
||||
if (rdes4 & ERDES4_AV_TAGGED_PKT_RCVD)
|
||||
x->av_tagged_pkt_rcvd++;
|
||||
if ((rdes4 & ERDES4_VLAN_TAG_PRI_VAL_MASK) >> 18)
|
||||
x->vlan_tag_priority_val++;
|
||||
if (rdes4 & ERDES4_L3_FILTER_MATCH)
|
||||
x->l3_filter_match++;
|
||||
if (rdes4 & ERDES4_L4_FILTER_MATCH)
|
||||
x->l4_filter_match++;
|
||||
if ((rdes4 & ERDES4_L3_L4_FILT_NO_MATCH_MASK) >> 26)
|
||||
x->l3_l4_filter_no_match++;
|
||||
}
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p)
|
||||
{
|
||||
unsigned int rdes0 = le32_to_cpu(p->des0);
|
||||
int ret = good_frame;
|
||||
|
||||
if (unlikely(rdes0 & RDES0_OWN))
|
||||
return dma_own;
|
||||
|
||||
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
|
||||
x->rx_length++;
|
||||
return discard_frame;
|
||||
}
|
||||
|
||||
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
|
||||
if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) {
|
||||
x->rx_desc++;
|
||||
x->rx_length++;
|
||||
}
|
||||
if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
|
||||
x->rx_gmac_overflow++;
|
||||
|
||||
if (unlikely(rdes0 & RDES0_IPC_CSUM_ERROR))
|
||||
pr_err("\tIPC Csum Error/Giant frame\n");
|
||||
|
||||
if (unlikely(rdes0 & RDES0_COLLISION))
|
||||
x->rx_collision++;
|
||||
if (unlikely(rdes0 & RDES0_RECEIVE_WATCHDOG))
|
||||
x->rx_watchdog++;
|
||||
|
||||
if (unlikely(rdes0 & RDES0_MII_ERROR)) /* GMII */
|
||||
x->rx_mii++;
|
||||
|
||||
if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
|
||||
x->rx_crc_errors++;
|
||||
}
|
||||
ret = discard_frame;
|
||||
}
|
||||
|
||||
/* After a payload csum error, the ES bit is set.
|
||||
* It doesn't match with the information reported into the databook.
|
||||
* At any rate, we need to understand if the CSUM hw computation is ok
|
||||
* and report this info to the upper layers. */
|
||||
if (likely(ret == good_frame))
|
||||
ret = enh_desc_coe_rdes0(!!(rdes0 & RDES0_IPC_CSUM_ERROR),
|
||||
!!(rdes0 & RDES0_FRAME_TYPE),
|
||||
!!(rdes0 & ERDES0_RX_MAC_ADDR));
|
||||
|
||||
if (unlikely(rdes0 & RDES0_DRIBBLING))
|
||||
x->dribbling_bit++;
|
||||
|
||||
if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL)) {
|
||||
x->sa_rx_filter_fail++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(rdes0 & RDES0_DA_FILTER_FAIL)) {
|
||||
x->da_rx_filter_fail++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) {
|
||||
x->rx_length++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
if (rdes0 & RDES0_VLAN_TAG)
|
||||
x->rx_vlan++;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
|
||||
int mode, int end, int bfsize)
|
||||
{
|
||||
int bfsize1;
|
||||
|
||||
p->des0 |= cpu_to_le32(RDES0_OWN);
|
||||
|
||||
bfsize1 = min(bfsize, BUF_SIZE_8KiB);
|
||||
p->des1 |= cpu_to_le32(bfsize1 & ERDES1_BUFFER1_SIZE_MASK);
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ehn_desc_rx_set_on_chain(p);
|
||||
else
|
||||
ehn_desc_rx_set_on_ring(p, end, bfsize);
|
||||
|
||||
if (disable_rx_ic)
|
||||
p->des1 |= cpu_to_le32(ERDES1_DISABLE_IC);
|
||||
}
|
||||
|
||||
static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end)
|
||||
{
|
||||
p->des0 &= cpu_to_le32(~ETDES0_OWN);
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
enh_desc_end_tx_desc_on_chain(p);
|
||||
else
|
||||
enh_desc_end_tx_desc_on_ring(p, end);
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des0) & ETDES0_OWN) >> 31;
|
||||
}
|
||||
|
||||
static void enh_desc_set_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(ETDES0_OWN);
|
||||
}
|
||||
|
||||
static void enh_desc_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(RDES0_OWN);
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_ls(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des0) & ETDES0_LAST_SEGMENT) >> 29;
|
||||
}
|
||||
|
||||
static void enh_desc_release_tx_desc(struct dma_desc *p, int mode)
|
||||
{
|
||||
int ter = (le32_to_cpu(p->des0) & ETDES0_END_RING) >> 21;
|
||||
|
||||
memset(p, 0, offsetof(struct dma_desc, des2));
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
enh_desc_end_tx_desc_on_chain(p);
|
||||
else
|
||||
enh_desc_end_tx_desc_on_ring(p, ter);
|
||||
}
|
||||
|
||||
static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
bool csum_flag, int mode, bool tx_own,
|
||||
bool ls, unsigned int tot_pkt_len)
|
||||
{
|
||||
unsigned int tdes0 = le32_to_cpu(p->des0);
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
enh_set_tx_desc_len_on_chain(p, len);
|
||||
else
|
||||
enh_set_tx_desc_len_on_ring(p, len);
|
||||
|
||||
if (is_fs)
|
||||
tdes0 |= ETDES0_FIRST_SEGMENT;
|
||||
else
|
||||
tdes0 &= ~ETDES0_FIRST_SEGMENT;
|
||||
|
||||
if (likely(csum_flag))
|
||||
tdes0 |= (TX_CIC_FULL << ETDES0_CHECKSUM_INSERTION_SHIFT);
|
||||
else
|
||||
tdes0 &= ~(TX_CIC_FULL << ETDES0_CHECKSUM_INSERTION_SHIFT);
|
||||
|
||||
if (ls)
|
||||
tdes0 |= ETDES0_LAST_SEGMENT;
|
||||
|
||||
/* Finally set the OWN bit. Later the DMA will start! */
|
||||
if (tx_own)
|
||||
tdes0 |= ETDES0_OWN;
|
||||
|
||||
if (is_fs && tx_own)
|
||||
/* When the own bit, for the first frame, has to be set, all
|
||||
* descriptors for the same frame has to be set before, to
|
||||
* avoid race condition.
|
||||
*/
|
||||
dma_wmb();
|
||||
|
||||
p->des0 = cpu_to_le32(tdes0);
|
||||
}
|
||||
|
||||
static void enh_desc_set_tx_ic(struct dma_desc *p)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(ETDES0_INTERRUPT);
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
|
||||
{
|
||||
unsigned int csum = 0;
|
||||
/* The type-1 checksum offload engines append the checksum at
|
||||
* the end of frame and the two bytes of checksum are added in
|
||||
* the length.
|
||||
* Adjust for that in the framelen for type-1 checksum offload
|
||||
* engines.
|
||||
*/
|
||||
if (rx_coe_type == STMMAC_RX_COE_TYPE1)
|
||||
csum = 2;
|
||||
|
||||
return (((le32_to_cpu(p->des0) & RDES0_FRAME_LEN_MASK)
|
||||
>> RDES0_FRAME_LEN_SHIFT) - csum);
|
||||
}
|
||||
|
||||
static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(ETDES0_TIME_STAMP_ENABLE);
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des0) & ETDES0_TIME_STAMP_STATUS) >> 17;
|
||||
}
|
||||
|
||||
static void enh_desc_get_timestamp(void *desc, u32 ats, u64 *ts)
|
||||
{
|
||||
u64 ns;
|
||||
|
||||
if (ats) {
|
||||
struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
|
||||
ns = le32_to_cpu(p->des6);
|
||||
/* convert high/sec time stamp value to nanosecond */
|
||||
ns += le32_to_cpu(p->des7) * 1000000000ULL;
|
||||
} else {
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
ns = le32_to_cpu(p->des2);
|
||||
ns += le32_to_cpu(p->des3) * 1000000000ULL;
|
||||
}
|
||||
|
||||
*ts = ns;
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_timestamp_status(void *desc, void *next_desc,
|
||||
u32 ats)
|
||||
{
|
||||
if (ats) {
|
||||
struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
|
||||
return (le32_to_cpu(p->basic.des0) & RDES0_IPC_CSUM_ERROR) >> 7;
|
||||
} else {
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
if ((le32_to_cpu(p->des2) == 0xffffffff) &&
|
||||
(le32_to_cpu(p->des3) == 0xffffffff))
|
||||
/* timestamp is corrupted, hence don't store it */
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void enh_desc_display_ring(void *head, unsigned int size, bool rx,
|
||||
dma_addr_t dma_rx_phy, unsigned int desc_size)
|
||||
{
|
||||
struct dma_extended_desc *ep = (struct dma_extended_desc *)head;
|
||||
dma_addr_t dma_addr;
|
||||
int i;
|
||||
|
||||
pr_info("Extended %s descriptor ring:\n", rx ? "RX" : "TX");
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
u64 x;
|
||||
dma_addr = dma_rx_phy + i * sizeof(*ep);
|
||||
|
||||
x = *(u64 *)ep;
|
||||
pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x\n",
|
||||
i, &dma_addr,
|
||||
(unsigned int)x, (unsigned int)(x >> 32),
|
||||
ep->basic.des2, ep->basic.des3);
|
||||
ep++;
|
||||
}
|
||||
pr_info("\n");
|
||||
}
|
||||
|
||||
static void enh_desc_set_addr(struct dma_desc *p, dma_addr_t addr)
|
||||
{
|
||||
p->des2 = cpu_to_le32(addr);
|
||||
}
|
||||
|
||||
static void enh_desc_clear(struct dma_desc *p)
|
||||
{
|
||||
p->des2 = 0;
|
||||
}
|
||||
|
||||
const struct stmmac_desc_ops enh_desc_ops = {
|
||||
.tx_status = enh_desc_get_tx_status,
|
||||
.rx_status = enh_desc_get_rx_status,
|
||||
.get_tx_len = enh_desc_get_tx_len,
|
||||
.init_rx_desc = enh_desc_init_rx_desc,
|
||||
.init_tx_desc = enh_desc_init_tx_desc,
|
||||
.get_tx_owner = enh_desc_get_tx_owner,
|
||||
.release_tx_desc = enh_desc_release_tx_desc,
|
||||
.prepare_tx_desc = enh_desc_prepare_tx_desc,
|
||||
.set_tx_ic = enh_desc_set_tx_ic,
|
||||
.get_tx_ls = enh_desc_get_tx_ls,
|
||||
.set_tx_owner = enh_desc_set_tx_owner,
|
||||
.set_rx_owner = enh_desc_set_rx_owner,
|
||||
.get_rx_frame_len = enh_desc_get_rx_frame_len,
|
||||
.rx_extended_status = enh_desc_get_ext_status,
|
||||
.enable_tx_timestamp = enh_desc_enable_tx_timestamp,
|
||||
.get_tx_timestamp_status = enh_desc_get_tx_timestamp_status,
|
||||
.get_timestamp = enh_desc_get_timestamp,
|
||||
.get_rx_timestamp_status = enh_desc_get_rx_timestamp_status,
|
||||
.display_ring = enh_desc_display_ring,
|
||||
.set_addr = enh_desc_set_addr,
|
||||
.clear = enh_desc_clear,
|
||||
};
|
||||
|
|
@ -0,0 +1,470 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This contains the functions to handle the enhanced descriptors.
|
||||
|
||||
Copyright (C) 2007-2014 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/stmmac.h>
|
||||
#include "common.h"
|
||||
#include "descs_com.h"
|
||||
|
||||
static int enh_desc_get_tx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p, void __iomem *ioaddr)
|
||||
{
|
||||
unsigned int tdes0 = le32_to_cpu(p->des0);
|
||||
int ret = tx_done;
|
||||
|
||||
/* Get tx owner first */
|
||||
if (unlikely(tdes0 & ETDES0_OWN))
|
||||
return tx_dma_own;
|
||||
|
||||
/* Verify tx error by looking at the last segment. */
|
||||
if (likely(!(tdes0 & ETDES0_LAST_SEGMENT)))
|
||||
return tx_not_ls;
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_ERROR_SUMMARY)) {
|
||||
if (unlikely(tdes0 & ETDES0_JABBER_TIMEOUT))
|
||||
x->tx_jabber++;
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_FRAME_FLUSHED)) {
|
||||
x->tx_frame_flushed++;
|
||||
dwmac_dma_flush_tx_fifo(ioaddr);
|
||||
}
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_LOSS_CARRIER)) {
|
||||
x->tx_losscarrier++;
|
||||
}
|
||||
if (unlikely(tdes0 & ETDES0_NO_CARRIER)) {
|
||||
x->tx_carrier++;
|
||||
}
|
||||
if (unlikely((tdes0 & ETDES0_LATE_COLLISION) ||
|
||||
(tdes0 & ETDES0_EXCESSIVE_COLLISIONS)))
|
||||
x->tx_collision +=
|
||||
(tdes0 & ETDES0_COLLISION_COUNT_MASK) >> 3;
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_EXCESSIVE_DEFERRAL))
|
||||
x->tx_deferred++;
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_UNDERFLOW_ERROR)) {
|
||||
dwmac_dma_flush_tx_fifo(ioaddr);
|
||||
x->tx_underflow++;
|
||||
}
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_IP_HEADER_ERROR))
|
||||
x->tx_ip_header_error++;
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_PAYLOAD_ERROR)) {
|
||||
x->tx_payload_error++;
|
||||
dwmac_dma_flush_tx_fifo(ioaddr);
|
||||
}
|
||||
|
||||
ret = tx_err;
|
||||
}
|
||||
|
||||
if (unlikely(tdes0 & ETDES0_DEFERRED))
|
||||
x->tx_deferred++;
|
||||
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
if (tdes0 & ETDES0_VLAN_FRAME)
|
||||
x->tx_vlan++;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_len(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des1) & ETDES1_BUFFER1_SIZE_MASK);
|
||||
}
|
||||
|
||||
static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
|
||||
{
|
||||
int ret = good_frame;
|
||||
u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7;
|
||||
|
||||
/* bits 5 7 0 | Frame status
|
||||
* ----------------------------------------------------------
|
||||
* 0 0 0 | IEEE 802.3 Type frame (length < 1536 octects)
|
||||
* 1 0 0 | IPv4/6 No CSUM errorS.
|
||||
* 1 0 1 | IPv4/6 CSUM PAYLOAD error
|
||||
* 1 1 0 | IPv4/6 CSUM IP HR error
|
||||
* 1 1 1 | IPv4/6 IP PAYLOAD AND HEADER errorS
|
||||
* 0 0 1 | IPv4/6 unsupported IP PAYLOAD
|
||||
* 0 1 1 | COE bypassed.. no IPv4/6 frame
|
||||
* 0 1 0 | Reserved.
|
||||
*/
|
||||
if (status == 0x0)
|
||||
ret = llc_snap;
|
||||
else if (status == 0x4)
|
||||
ret = good_frame;
|
||||
else if (status == 0x5)
|
||||
ret = csum_none;
|
||||
else if (status == 0x6)
|
||||
ret = csum_none;
|
||||
else if (status == 0x7)
|
||||
ret = csum_none;
|
||||
else if (status == 0x1)
|
||||
ret = discard_frame;
|
||||
else if (status == 0x3)
|
||||
ret = discard_frame;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void enh_desc_get_ext_status(struct stmmac_extra_stats *x,
|
||||
struct dma_extended_desc *p)
|
||||
{
|
||||
unsigned int rdes0 = le32_to_cpu(p->basic.des0);
|
||||
unsigned int rdes4 = le32_to_cpu(p->des4);
|
||||
|
||||
if (unlikely(rdes0 & ERDES0_RX_MAC_ADDR)) {
|
||||
int message_type = (rdes4 & ERDES4_MSG_TYPE_MASK) >> 8;
|
||||
|
||||
if (rdes4 & ERDES4_IP_HDR_ERR)
|
||||
x->ip_hdr_err++;
|
||||
if (rdes4 & ERDES4_IP_PAYLOAD_ERR)
|
||||
x->ip_payload_err++;
|
||||
if (rdes4 & ERDES4_IP_CSUM_BYPASSED)
|
||||
x->ip_csum_bypassed++;
|
||||
if (rdes4 & ERDES4_IPV4_PKT_RCVD)
|
||||
x->ipv4_pkt_rcvd++;
|
||||
if (rdes4 & ERDES4_IPV6_PKT_RCVD)
|
||||
x->ipv6_pkt_rcvd++;
|
||||
|
||||
if (message_type == RDES_EXT_NO_PTP)
|
||||
x->no_ptp_rx_msg_type_ext++;
|
||||
else if (message_type == RDES_EXT_SYNC)
|
||||
x->ptp_rx_msg_type_sync++;
|
||||
else if (message_type == RDES_EXT_FOLLOW_UP)
|
||||
x->ptp_rx_msg_type_follow_up++;
|
||||
else if (message_type == RDES_EXT_DELAY_REQ)
|
||||
x->ptp_rx_msg_type_delay_req++;
|
||||
else if (message_type == RDES_EXT_DELAY_RESP)
|
||||
x->ptp_rx_msg_type_delay_resp++;
|
||||
else if (message_type == RDES_EXT_PDELAY_REQ)
|
||||
x->ptp_rx_msg_type_pdelay_req++;
|
||||
else if (message_type == RDES_EXT_PDELAY_RESP)
|
||||
x->ptp_rx_msg_type_pdelay_resp++;
|
||||
else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP)
|
||||
x->ptp_rx_msg_type_pdelay_follow_up++;
|
||||
else if (message_type == RDES_PTP_ANNOUNCE)
|
||||
x->ptp_rx_msg_type_announce++;
|
||||
else if (message_type == RDES_PTP_MANAGEMENT)
|
||||
x->ptp_rx_msg_type_management++;
|
||||
else if (message_type == RDES_PTP_PKT_RESERVED_TYPE)
|
||||
x->ptp_rx_msg_pkt_reserved_type++;
|
||||
|
||||
if (rdes4 & ERDES4_PTP_FRAME_TYPE)
|
||||
x->ptp_frame_type++;
|
||||
if (rdes4 & ERDES4_PTP_VER)
|
||||
x->ptp_ver++;
|
||||
if (rdes4 & ERDES4_TIMESTAMP_DROPPED)
|
||||
x->timestamp_dropped++;
|
||||
if (rdes4 & ERDES4_AV_PKT_RCVD)
|
||||
x->av_pkt_rcvd++;
|
||||
if (rdes4 & ERDES4_AV_TAGGED_PKT_RCVD)
|
||||
x->av_tagged_pkt_rcvd++;
|
||||
if ((rdes4 & ERDES4_VLAN_TAG_PRI_VAL_MASK) >> 18)
|
||||
x->vlan_tag_priority_val++;
|
||||
if (rdes4 & ERDES4_L3_FILTER_MATCH)
|
||||
x->l3_filter_match++;
|
||||
if (rdes4 & ERDES4_L4_FILTER_MATCH)
|
||||
x->l4_filter_match++;
|
||||
if ((rdes4 & ERDES4_L3_L4_FILT_NO_MATCH_MASK) >> 26)
|
||||
x->l3_l4_filter_no_match++;
|
||||
}
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p)
|
||||
{
|
||||
unsigned int rdes0 = le32_to_cpu(p->des0);
|
||||
int ret = good_frame;
|
||||
|
||||
if (unlikely(rdes0 & RDES0_OWN))
|
||||
return dma_own;
|
||||
|
||||
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
|
||||
x->rx_length++;
|
||||
return discard_frame;
|
||||
}
|
||||
|
||||
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
|
||||
if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) {
|
||||
x->rx_desc++;
|
||||
x->rx_length++;
|
||||
}
|
||||
if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
|
||||
x->rx_gmac_overflow++;
|
||||
|
||||
if (unlikely(rdes0 & RDES0_IPC_CSUM_ERROR))
|
||||
pr_err("\tIPC Csum Error/Giant frame\n");
|
||||
|
||||
if (unlikely(rdes0 & RDES0_COLLISION))
|
||||
x->rx_collision++;
|
||||
if (unlikely(rdes0 & RDES0_RECEIVE_WATCHDOG))
|
||||
x->rx_watchdog++;
|
||||
|
||||
if (unlikely(rdes0 & RDES0_MII_ERROR)) /* GMII */
|
||||
x->rx_mii++;
|
||||
|
||||
if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
|
||||
x->rx_crc_errors++;
|
||||
}
|
||||
ret = discard_frame;
|
||||
}
|
||||
|
||||
/* After a payload csum error, the ES bit is set.
|
||||
* It doesn't match with the information reported into the databook.
|
||||
* At any rate, we need to understand if the CSUM hw computation is ok
|
||||
* and report this info to the upper layers. */
|
||||
if (likely(ret == good_frame))
|
||||
ret = enh_desc_coe_rdes0(!!(rdes0 & RDES0_IPC_CSUM_ERROR),
|
||||
!!(rdes0 & RDES0_FRAME_TYPE),
|
||||
!!(rdes0 & ERDES0_RX_MAC_ADDR));
|
||||
|
||||
if (unlikely(rdes0 & RDES0_DRIBBLING))
|
||||
x->dribbling_bit++;
|
||||
|
||||
if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL)) {
|
||||
x->sa_rx_filter_fail++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(rdes0 & RDES0_DA_FILTER_FAIL)) {
|
||||
x->da_rx_filter_fail++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) {
|
||||
x->rx_length++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
if (rdes0 & RDES0_VLAN_TAG)
|
||||
x->rx_vlan++;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
|
||||
int mode, int end, int bfsize)
|
||||
{
|
||||
int bfsize1;
|
||||
|
||||
p->des0 |= cpu_to_le32(RDES0_OWN);
|
||||
|
||||
bfsize1 = min(bfsize, BUF_SIZE_8KiB);
|
||||
p->des1 |= cpu_to_le32(bfsize1 & ERDES1_BUFFER1_SIZE_MASK);
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ehn_desc_rx_set_on_chain(p);
|
||||
else
|
||||
ehn_desc_rx_set_on_ring(p, end, bfsize);
|
||||
|
||||
if (disable_rx_ic)
|
||||
p->des1 |= cpu_to_le32(ERDES1_DISABLE_IC);
|
||||
}
|
||||
|
||||
static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end)
|
||||
{
|
||||
p->des0 &= cpu_to_le32(~ETDES0_OWN);
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
enh_desc_end_tx_desc_on_chain(p);
|
||||
else
|
||||
enh_desc_end_tx_desc_on_ring(p, end);
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des0) & ETDES0_OWN) >> 31;
|
||||
}
|
||||
|
||||
static void enh_desc_set_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(ETDES0_OWN);
|
||||
}
|
||||
|
||||
static void enh_desc_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(RDES0_OWN);
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_ls(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des0) & ETDES0_LAST_SEGMENT) >> 29;
|
||||
}
|
||||
|
||||
static void enh_desc_release_tx_desc(struct dma_desc *p, int mode)
|
||||
{
|
||||
int ter = (le32_to_cpu(p->des0) & ETDES0_END_RING) >> 21;
|
||||
|
||||
memset(p, 0, offsetof(struct dma_desc, des2));
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
enh_desc_end_tx_desc_on_chain(p);
|
||||
else
|
||||
enh_desc_end_tx_desc_on_ring(p, ter);
|
||||
}
|
||||
|
||||
static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
bool csum_flag, int mode, bool tx_own,
|
||||
bool ls, unsigned int tot_pkt_len)
|
||||
{
|
||||
unsigned int tdes0 = le32_to_cpu(p->des0);
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
enh_set_tx_desc_len_on_chain(p, len);
|
||||
else
|
||||
enh_set_tx_desc_len_on_ring(p, len);
|
||||
|
||||
if (is_fs)
|
||||
tdes0 |= ETDES0_FIRST_SEGMENT;
|
||||
else
|
||||
tdes0 &= ~ETDES0_FIRST_SEGMENT;
|
||||
|
||||
if (likely(csum_flag))
|
||||
tdes0 |= (TX_CIC_FULL << ETDES0_CHECKSUM_INSERTION_SHIFT);
|
||||
else
|
||||
tdes0 &= ~(TX_CIC_FULL << ETDES0_CHECKSUM_INSERTION_SHIFT);
|
||||
|
||||
if (ls)
|
||||
tdes0 |= ETDES0_LAST_SEGMENT;
|
||||
|
||||
/* Finally set the OWN bit. Later the DMA will start! */
|
||||
if (tx_own)
|
||||
tdes0 |= ETDES0_OWN;
|
||||
|
||||
if (is_fs && tx_own)
|
||||
/* When the own bit, for the first frame, has to be set, all
|
||||
* descriptors for the same frame has to be set before, to
|
||||
* avoid race condition.
|
||||
*/
|
||||
dma_wmb();
|
||||
|
||||
p->des0 = cpu_to_le32(tdes0);
|
||||
}
|
||||
|
||||
static void enh_desc_set_tx_ic(struct dma_desc *p)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(ETDES0_INTERRUPT);
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
|
||||
{
|
||||
unsigned int csum = 0;
|
||||
/* The type-1 checksum offload engines append the checksum at
|
||||
* the end of frame and the two bytes of checksum are added in
|
||||
* the length.
|
||||
* Adjust for that in the framelen for type-1 checksum offload
|
||||
* engines.
|
||||
*/
|
||||
if (rx_coe_type == STMMAC_RX_COE_TYPE1)
|
||||
csum = 2;
|
||||
|
||||
return (((le32_to_cpu(p->des0) & RDES0_FRAME_LEN_MASK)
|
||||
>> RDES0_FRAME_LEN_SHIFT) - csum);
|
||||
}
|
||||
|
||||
static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(ETDES0_TIME_STAMP_ENABLE);
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des0) & ETDES0_TIME_STAMP_STATUS) >> 17;
|
||||
}
|
||||
|
||||
static void enh_desc_get_timestamp(void *desc, u32 ats, u64 *ts)
|
||||
{
|
||||
u64 ns;
|
||||
|
||||
if (ats) {
|
||||
struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
|
||||
ns = le32_to_cpu(p->des6);
|
||||
/* convert high/sec time stamp value to nanosecond */
|
||||
ns += le32_to_cpu(p->des7) * 1000000000ULL;
|
||||
} else {
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
ns = le32_to_cpu(p->des2);
|
||||
ns += le32_to_cpu(p->des3) * 1000000000ULL;
|
||||
}
|
||||
|
||||
*ts = ns;
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_timestamp_status(void *desc, void *next_desc,
|
||||
u32 ats)
|
||||
{
|
||||
if (ats) {
|
||||
struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
|
||||
return (le32_to_cpu(p->basic.des0) & RDES0_IPC_CSUM_ERROR) >> 7;
|
||||
} else {
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
if ((le32_to_cpu(p->des2) == 0xffffffff) &&
|
||||
(le32_to_cpu(p->des3) == 0xffffffff))
|
||||
/* timestamp is corrupted, hence don't store it */
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void enh_desc_display_ring(void *head, unsigned int size, bool rx,
|
||||
dma_addr_t dma_rx_phy, unsigned int desc_size)
|
||||
{
|
||||
struct dma_extended_desc *ep = (struct dma_extended_desc *)head;
|
||||
dma_addr_t dma_addr;
|
||||
int i;
|
||||
|
||||
pr_info("Extended %s descriptor ring:\n", rx ? "RX" : "TX");
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
u64 x;
|
||||
dma_addr = dma_rx_phy + i * sizeof(*ep);
|
||||
|
||||
x = *(u64 *)ep;
|
||||
pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x\n",
|
||||
i, &dma_addr,
|
||||
(unsigned int)x, (unsigned int)(x >> 32),
|
||||
ep->basic.des2, ep->basic.des3);
|
||||
ep++;
|
||||
}
|
||||
pr_info("\n");
|
||||
}
|
||||
|
||||
static void enh_desc_set_addr(struct dma_desc *p, dma_addr_t addr)
|
||||
{
|
||||
p->des2 = cpu_to_le32(addr);
|
||||
}
|
||||
|
||||
static void enh_desc_clear(struct dma_desc *p)
|
||||
{
|
||||
p->des2 = 0;
|
||||
}
|
||||
|
||||
const struct stmmac_desc_ops enh_desc_ops = {
|
||||
.tx_status = enh_desc_get_tx_status,
|
||||
.rx_status = enh_desc_get_rx_status,
|
||||
.get_tx_len = enh_desc_get_tx_len,
|
||||
.init_rx_desc = enh_desc_init_rx_desc,
|
||||
.init_tx_desc = enh_desc_init_tx_desc,
|
||||
.get_tx_owner = enh_desc_get_tx_owner,
|
||||
.release_tx_desc = enh_desc_release_tx_desc,
|
||||
.prepare_tx_desc = enh_desc_prepare_tx_desc,
|
||||
.set_tx_ic = enh_desc_set_tx_ic,
|
||||
.get_tx_ls = enh_desc_get_tx_ls,
|
||||
.set_tx_owner = enh_desc_set_tx_owner,
|
||||
.set_rx_owner = enh_desc_set_rx_owner,
|
||||
.get_rx_frame_len = enh_desc_get_rx_frame_len,
|
||||
.rx_extended_status = enh_desc_get_ext_status,
|
||||
.enable_tx_timestamp = enh_desc_enable_tx_timestamp,
|
||||
.get_tx_timestamp_status = enh_desc_get_tx_timestamp_status,
|
||||
.get_timestamp = enh_desc_get_timestamp,
|
||||
.get_rx_timestamp_status = enh_desc_get_rx_timestamp_status,
|
||||
.display_ring = enh_desc_display_ring,
|
||||
.set_addr = enh_desc_set_addr,
|
||||
.clear = enh_desc_clear,
|
||||
};
|
||||
|
|
@ -0,0 +1,376 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
|
||||
* stmmac HW Interface Handling
|
||||
*/
|
||||
|
||||
#include "common-6.12-ethercat.h"
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
#include "stmmac_ptp-6.12-ethercat.h"
|
||||
#include "stmmac_est-6.12-ethercat.h"
|
||||
|
||||
static u32 stmmac_get_id(struct stmmac_priv *priv, u32 id_reg)
|
||||
{
|
||||
u32 reg = readl(priv->ioaddr + id_reg);
|
||||
|
||||
if (!reg) {
|
||||
dev_info(priv->device, "Version ID not available\n");
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
dev_info(priv->device, "User ID: 0x%x, Synopsys ID: 0x%x\n",
|
||||
(unsigned int)(reg & GENMASK(15, 8)) >> 8,
|
||||
(unsigned int)(reg & GENMASK(7, 0)));
|
||||
return reg & GENMASK(7, 0);
|
||||
}
|
||||
|
||||
static u32 stmmac_get_dev_id(struct stmmac_priv *priv, u32 id_reg)
|
||||
{
|
||||
u32 reg = readl(priv->ioaddr + id_reg);
|
||||
|
||||
if (!reg) {
|
||||
dev_info(priv->device, "Version ID not available\n");
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
return (reg & GENMASK(15, 8)) >> 8;
|
||||
}
|
||||
|
||||
static void stmmac_dwmac_mode_quirk(struct stmmac_priv *priv)
|
||||
{
|
||||
struct mac_device_info *mac = priv->hw;
|
||||
|
||||
if (priv->chain_mode) {
|
||||
dev_info(priv->device, "Chain mode enabled\n");
|
||||
priv->mode = STMMAC_CHAIN_MODE;
|
||||
mac->mode = &chain_mode_ops;
|
||||
} else {
|
||||
dev_info(priv->device, "Ring mode enabled\n");
|
||||
priv->mode = STMMAC_RING_MODE;
|
||||
mac->mode = &ring_mode_ops;
|
||||
}
|
||||
}
|
||||
|
||||
static int stmmac_dwmac1_quirks(struct stmmac_priv *priv)
|
||||
{
|
||||
struct mac_device_info *mac = priv->hw;
|
||||
|
||||
if (priv->plat->enh_desc) {
|
||||
dev_info(priv->device, "Enhanced/Alternate descriptors\n");
|
||||
|
||||
/* GMAC older than 3.50 has no extended descriptors */
|
||||
if (priv->synopsys_id >= DWMAC_CORE_3_50) {
|
||||
dev_info(priv->device, "Enabled extended descriptors\n");
|
||||
priv->extend_desc = 1;
|
||||
} else {
|
||||
dev_warn(priv->device, "Extended descriptors not supported\n");
|
||||
}
|
||||
|
||||
mac->desc = &enh_desc_ops;
|
||||
} else {
|
||||
dev_info(priv->device, "Normal descriptors\n");
|
||||
mac->desc = &ndesc_ops;
|
||||
}
|
||||
|
||||
stmmac_dwmac_mode_quirk(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
|
||||
{
|
||||
stmmac_dwmac_mode_quirk(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_dwxlgmac_quirks(struct stmmac_priv *priv)
|
||||
{
|
||||
priv->hw->xlgmac = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmmac_reset(struct stmmac_priv *priv, void __iomem *ioaddr)
|
||||
{
|
||||
struct plat_stmmacenet_data *plat = priv ? priv->plat : NULL;
|
||||
|
||||
if (!priv)
|
||||
return -EINVAL;
|
||||
|
||||
if (plat && plat->fix_soc_reset)
|
||||
return plat->fix_soc_reset(plat, ioaddr);
|
||||
|
||||
return stmmac_do_callback(priv, dma, reset, ioaddr);
|
||||
}
|
||||
|
||||
static const struct stmmac_hwif_entry {
|
||||
bool gmac;
|
||||
bool gmac4;
|
||||
bool xgmac;
|
||||
u32 min_id;
|
||||
u32 dev_id;
|
||||
const struct stmmac_regs_off regs;
|
||||
const void *desc;
|
||||
const void *dma;
|
||||
const void *mac;
|
||||
const void *hwtimestamp;
|
||||
const void *mode;
|
||||
const void *tc;
|
||||
const void *mmc;
|
||||
const void *est;
|
||||
int (*setup)(struct stmmac_priv *priv);
|
||||
int (*quirks)(struct stmmac_priv *priv);
|
||||
} stmmac_hw[] = {
|
||||
/* NOTE: New HW versions shall go to the end of this table */
|
||||
{
|
||||
.gmac = false,
|
||||
.gmac4 = false,
|
||||
.xgmac = false,
|
||||
.min_id = 0,
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC3_X_OFFSET,
|
||||
.mmc_off = MMC_GMAC3_X_OFFSET,
|
||||
},
|
||||
.desc = NULL,
|
||||
.dma = &dwmac100_dma_ops,
|
||||
.mac = &dwmac100_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = NULL,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.setup = dwmac100_setup,
|
||||
.quirks = stmmac_dwmac1_quirks,
|
||||
}, {
|
||||
.gmac = true,
|
||||
.gmac4 = false,
|
||||
.xgmac = false,
|
||||
.min_id = 0,
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC3_X_OFFSET,
|
||||
.mmc_off = MMC_GMAC3_X_OFFSET,
|
||||
},
|
||||
.desc = NULL,
|
||||
.dma = &dwmac1000_dma_ops,
|
||||
.mac = &dwmac1000_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = NULL,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.setup = dwmac1000_setup,
|
||||
.quirks = stmmac_dwmac1_quirks,
|
||||
}, {
|
||||
.gmac = false,
|
||||
.gmac4 = true,
|
||||
.xgmac = false,
|
||||
.min_id = 0,
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac4_dma_ops,
|
||||
.mac = &dwmac4_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = &dwmac4_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
.quirks = stmmac_dwmac4_quirks,
|
||||
}, {
|
||||
.gmac = false,
|
||||
.gmac4 = true,
|
||||
.xgmac = false,
|
||||
.min_id = DWMAC_CORE_4_00,
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac4_dma_ops,
|
||||
.mac = &dwmac410_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = &dwmac4_ring_mode_ops,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
.quirks = NULL,
|
||||
}, {
|
||||
.gmac = false,
|
||||
.gmac4 = true,
|
||||
.xgmac = false,
|
||||
.min_id = DWMAC_CORE_4_10,
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac410_dma_ops,
|
||||
.mac = &dwmac410_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = &dwmac4_ring_mode_ops,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
.quirks = NULL,
|
||||
}, {
|
||||
.gmac = false,
|
||||
.gmac4 = true,
|
||||
.xgmac = false,
|
||||
.min_id = DWMAC_CORE_5_10,
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac410_dma_ops,
|
||||
.mac = &dwmac510_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = &dwmac4_ring_mode_ops,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
.quirks = NULL,
|
||||
}, {
|
||||
.gmac = false,
|
||||
.gmac4 = false,
|
||||
.xgmac = true,
|
||||
.min_id = DWXGMAC_CORE_2_10,
|
||||
.dev_id = DWXGMAC_ID,
|
||||
.regs = {
|
||||
.ptp_off = PTP_XGMAC_OFFSET,
|
||||
.mmc_off = MMC_XGMAC_OFFSET,
|
||||
.est_off = EST_XGMAC_OFFSET,
|
||||
},
|
||||
.desc = &dwxgmac210_desc_ops,
|
||||
.dma = &dwxgmac210_dma_ops,
|
||||
.mac = &dwxgmac210_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = &dwxgmac_tc_ops,
|
||||
.mmc = &dwxgmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwxgmac2_setup,
|
||||
.quirks = NULL,
|
||||
}, {
|
||||
.gmac = false,
|
||||
.gmac4 = false,
|
||||
.xgmac = true,
|
||||
.min_id = DWXLGMAC_CORE_2_00,
|
||||
.dev_id = DWXLGMAC_ID,
|
||||
.regs = {
|
||||
.ptp_off = PTP_XGMAC_OFFSET,
|
||||
.mmc_off = MMC_XGMAC_OFFSET,
|
||||
.est_off = EST_XGMAC_OFFSET,
|
||||
},
|
||||
.desc = &dwxgmac210_desc_ops,
|
||||
.dma = &dwxgmac210_dma_ops,
|
||||
.mac = &dwxlgmac2_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = &dwxgmac_tc_ops,
|
||||
.mmc = &dwxgmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwxlgmac2_setup,
|
||||
.quirks = stmmac_dwxlgmac_quirks,
|
||||
},
|
||||
};
|
||||
|
||||
int stmmac_hwif_init(struct stmmac_priv *priv)
|
||||
{
|
||||
bool needs_xgmac = priv->plat->has_xgmac;
|
||||
bool needs_gmac4 = priv->plat->has_gmac4;
|
||||
bool needs_gmac = priv->plat->has_gmac;
|
||||
const struct stmmac_hwif_entry *entry;
|
||||
struct mac_device_info *mac;
|
||||
bool needs_setup = true;
|
||||
u32 id, dev_id = 0;
|
||||
int i, ret;
|
||||
|
||||
if (needs_gmac) {
|
||||
id = stmmac_get_id(priv, GMAC_VERSION);
|
||||
} else if (needs_gmac4 || needs_xgmac) {
|
||||
id = stmmac_get_id(priv, GMAC4_VERSION);
|
||||
if (needs_xgmac)
|
||||
dev_id = stmmac_get_dev_id(priv, GMAC4_VERSION);
|
||||
} else {
|
||||
id = 0;
|
||||
}
|
||||
|
||||
/* Save ID for later use */
|
||||
priv->synopsys_id = id;
|
||||
|
||||
/* Lets assume some safe values first */
|
||||
priv->ptpaddr = priv->ioaddr +
|
||||
(needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET);
|
||||
priv->mmcaddr = priv->ioaddr +
|
||||
(needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET);
|
||||
if (needs_gmac4)
|
||||
priv->estaddr = priv->ioaddr + EST_GMAC4_OFFSET;
|
||||
else if (needs_xgmac)
|
||||
priv->estaddr = priv->ioaddr + EST_XGMAC_OFFSET;
|
||||
|
||||
/* Check for HW specific setup first */
|
||||
if (priv->plat->setup) {
|
||||
mac = priv->plat->setup(priv);
|
||||
needs_setup = false;
|
||||
} else {
|
||||
mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);
|
||||
}
|
||||
|
||||
if (!mac)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Fallback to generic HW */
|
||||
for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) {
|
||||
entry = &stmmac_hw[i];
|
||||
|
||||
if (needs_gmac ^ entry->gmac)
|
||||
continue;
|
||||
if (needs_gmac4 ^ entry->gmac4)
|
||||
continue;
|
||||
if (needs_xgmac ^ entry->xgmac)
|
||||
continue;
|
||||
/* Use synopsys_id var because some setups can override this */
|
||||
if (priv->synopsys_id < entry->min_id)
|
||||
continue;
|
||||
if (needs_xgmac && (dev_id ^ entry->dev_id))
|
||||
continue;
|
||||
|
||||
/* Only use generic HW helpers if needed */
|
||||
mac->desc = mac->desc ? : entry->desc;
|
||||
mac->dma = mac->dma ? : entry->dma;
|
||||
mac->mac = mac->mac ? : entry->mac;
|
||||
mac->ptp = mac->ptp ? : entry->hwtimestamp;
|
||||
mac->mode = mac->mode ? : entry->mode;
|
||||
mac->tc = mac->tc ? : entry->tc;
|
||||
mac->mmc = mac->mmc ? : entry->mmc;
|
||||
mac->est = mac->est ? : entry->est;
|
||||
|
||||
priv->hw = mac;
|
||||
priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
|
||||
priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
|
||||
if (entry->est)
|
||||
priv->estaddr = priv->ioaddr + entry->regs.est_off;
|
||||
|
||||
/* Entry found */
|
||||
if (needs_setup) {
|
||||
ret = entry->setup(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Save quirks, if needed for posterior use */
|
||||
priv->hwif_quirks = entry->quirks;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(priv->device, "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n",
|
||||
id, needs_gmac, needs_gmac4);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -0,0 +1,712 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
|
||||
// Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
|
||||
// stmmac HW Interface Callbacks
|
||||
|
||||
#ifndef __STMMAC_HWIF_H__
|
||||
#define __STMMAC_HWIF_H__
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/stmmac.h>
|
||||
#include <net/pkt_cls.h>
|
||||
|
||||
#define stmmac_do_void_callback(__priv, __module, __cname, __arg0, __args...) \
|
||||
({ \
|
||||
int __result = -EINVAL; \
|
||||
if ((__priv)->hw->__module && (__priv)->hw->__module->__cname) { \
|
||||
(__priv)->hw->__module->__cname((__arg0), ##__args); \
|
||||
__result = 0; \
|
||||
} \
|
||||
__result; \
|
||||
})
|
||||
#define stmmac_do_callback(__priv, __module, __cname, __arg0, __args...) \
|
||||
({ \
|
||||
int __result = -EINVAL; \
|
||||
if ((__priv)->hw->__module && (__priv)->hw->__module->__cname) \
|
||||
__result = (__priv)->hw->__module->__cname((__arg0), ##__args); \
|
||||
__result; \
|
||||
})
|
||||
|
||||
struct stmmac_extra_stats;
|
||||
struct stmmac_priv;
|
||||
struct stmmac_safety_stats;
|
||||
struct stmmac_fpe_cfg;
|
||||
enum stmmac_mpacket_type;
|
||||
struct dma_desc;
|
||||
struct dma_extended_desc;
|
||||
struct dma_edesc;
|
||||
|
||||
/* Descriptors helpers */
|
||||
struct stmmac_desc_ops {
|
||||
/* DMA RX descriptor ring initialization */
|
||||
void (*init_rx_desc)(struct dma_desc *p, int disable_rx_ic, int mode,
|
||||
int end, int bfsize);
|
||||
/* DMA TX descriptor ring initialization */
|
||||
void (*init_tx_desc)(struct dma_desc *p, int mode, int end);
|
||||
/* Invoked by the xmit function to prepare the tx descriptor */
|
||||
void (*prepare_tx_desc)(struct dma_desc *p, int is_fs, int len,
|
||||
bool csum_flag, int mode, bool tx_own, bool ls,
|
||||
unsigned int tot_pkt_len);
|
||||
void (*prepare_tso_tx_desc)(struct dma_desc *p, int is_fs, int len1,
|
||||
int len2, bool tx_own, bool ls, unsigned int tcphdrlen,
|
||||
unsigned int tcppayloadlen);
|
||||
/* Set/get the owner of the descriptor */
|
||||
void (*set_tx_owner)(struct dma_desc *p);
|
||||
int (*get_tx_owner)(struct dma_desc *p);
|
||||
/* Clean the tx descriptor as soon as the tx irq is received */
|
||||
void (*release_tx_desc)(struct dma_desc *p, int mode);
|
||||
/* Clear interrupt on tx frame completion. When this bit is
|
||||
* set an interrupt happens as soon as the frame is transmitted */
|
||||
void (*set_tx_ic)(struct dma_desc *p);
|
||||
/* Last tx segment reports the transmit status */
|
||||
int (*get_tx_ls)(struct dma_desc *p);
|
||||
/* Get the tag of the descriptor */
|
||||
u16 (*get_rx_vlan_tci)(struct dma_desc *p);
|
||||
/* Get the valid status of descriptor */
|
||||
bool (*get_rx_vlan_valid)(struct dma_desc *p);
|
||||
/* Return the transmit status looking at the TDES1 */
|
||||
int (*tx_status)(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p, void __iomem *ioaddr);
|
||||
/* Get the buffer size from the descriptor */
|
||||
int (*get_tx_len)(struct dma_desc *p);
|
||||
/* Handle extra events on specific interrupts hw dependent */
|
||||
void (*set_rx_owner)(struct dma_desc *p, int disable_rx_ic);
|
||||
/* Get the receive frame size */
|
||||
int (*get_rx_frame_len)(struct dma_desc *p, int rx_coe_type);
|
||||
/* Return the reception status looking at the RDES1 */
|
||||
int (*rx_status)(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p);
|
||||
void (*rx_extended_status)(struct stmmac_extra_stats *x,
|
||||
struct dma_extended_desc *p);
|
||||
/* Set tx timestamp enable bit */
|
||||
void (*enable_tx_timestamp) (struct dma_desc *p);
|
||||
/* get tx timestamp status */
|
||||
int (*get_tx_timestamp_status) (struct dma_desc *p);
|
||||
/* get timestamp value */
|
||||
void (*get_timestamp)(void *desc, u32 ats, u64 *ts);
|
||||
/* get rx timestamp status */
|
||||
int (*get_rx_timestamp_status)(void *desc, void *next_desc, u32 ats);
|
||||
/* Display ring */
|
||||
void (*display_ring)(void *head, unsigned int size, bool rx,
|
||||
dma_addr_t dma_rx_phy, unsigned int desc_size);
|
||||
/* set MSS via context descriptor */
|
||||
void (*set_mss)(struct dma_desc *p, unsigned int mss);
|
||||
/* set descriptor skbuff address */
|
||||
void (*set_addr)(struct dma_desc *p, dma_addr_t addr);
|
||||
/* clear descriptor */
|
||||
void (*clear)(struct dma_desc *p);
|
||||
/* RSS */
|
||||
int (*get_rx_hash)(struct dma_desc *p, u32 *hash,
|
||||
enum pkt_hash_types *type);
|
||||
void (*get_rx_header_len)(struct dma_desc *p, unsigned int *len);
|
||||
void (*set_sec_addr)(struct dma_desc *p, dma_addr_t addr, bool buf2_valid);
|
||||
void (*set_sarc)(struct dma_desc *p, u32 sarc_type);
|
||||
void (*set_vlan_tag)(struct dma_desc *p, u16 tag, u16 inner_tag,
|
||||
u32 inner_type);
|
||||
void (*set_vlan)(struct dma_desc *p, u32 type);
|
||||
void (*set_tbs)(struct dma_edesc *p, u32 sec, u32 nsec);
|
||||
};
|
||||
|
||||
#define stmmac_init_rx_desc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, init_rx_desc, __args)
|
||||
#define stmmac_init_tx_desc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, init_tx_desc, __args)
|
||||
#define stmmac_prepare_tx_desc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, prepare_tx_desc, __args)
|
||||
#define stmmac_prepare_tso_tx_desc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, prepare_tso_tx_desc, __args)
|
||||
#define stmmac_set_tx_owner(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_tx_owner, __args)
|
||||
#define stmmac_get_tx_owner(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_tx_owner, __args)
|
||||
#define stmmac_release_tx_desc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, release_tx_desc, __args)
|
||||
#define stmmac_set_tx_ic(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_tx_ic, __args)
|
||||
#define stmmac_get_tx_ls(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_tx_ls, __args)
|
||||
#define stmmac_get_rx_vlan_tci(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_rx_vlan_tci, __args)
|
||||
#define stmmac_get_rx_vlan_valid(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_rx_vlan_valid, __args)
|
||||
#define stmmac_tx_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, tx_status, __args)
|
||||
#define stmmac_get_tx_len(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_tx_len, __args)
|
||||
#define stmmac_set_rx_owner(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_rx_owner, __args)
|
||||
#define stmmac_get_rx_frame_len(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_rx_frame_len, __args)
|
||||
#define stmmac_rx_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, rx_status, __args)
|
||||
#define stmmac_rx_extended_status(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, rx_extended_status, __args)
|
||||
#define stmmac_enable_tx_timestamp(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, enable_tx_timestamp, __args)
|
||||
#define stmmac_get_tx_timestamp_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_tx_timestamp_status, __args)
|
||||
#define stmmac_get_timestamp(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, get_timestamp, __args)
|
||||
#define stmmac_get_rx_timestamp_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_rx_timestamp_status, __args)
|
||||
#define stmmac_display_ring(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, display_ring, __args)
|
||||
#define stmmac_set_mss(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_mss, __args)
|
||||
#define stmmac_set_desc_addr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_addr, __args)
|
||||
#define stmmac_clear_desc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, clear, __args)
|
||||
#define stmmac_get_rx_hash(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_rx_hash, __args)
|
||||
#define stmmac_get_rx_header_len(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, get_rx_header_len, __args)
|
||||
#define stmmac_set_desc_sec_addr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_sec_addr, __args)
|
||||
#define stmmac_set_desc_sarc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_sarc, __args)
|
||||
#define stmmac_set_desc_vlan_tag(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_vlan_tag, __args)
|
||||
#define stmmac_set_desc_vlan(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_vlan, __args)
|
||||
#define stmmac_set_desc_tbs(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_tbs, __args)
|
||||
|
||||
struct stmmac_dma_cfg;
|
||||
struct dma_features;
|
||||
|
||||
/* Specific DMA helpers */
|
||||
struct stmmac_dma_ops {
|
||||
/* DMA core initialization */
|
||||
int (*reset)(void __iomem *ioaddr);
|
||||
void (*init)(void __iomem *ioaddr, struct stmmac_dma_cfg *dma_cfg);
|
||||
void (*init_chan)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg, u32 chan);
|
||||
void (*init_rx_chan)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t phy, u32 chan);
|
||||
void (*init_tx_chan)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t phy, u32 chan);
|
||||
/* Configure the AXI Bus Mode Register */
|
||||
void (*axi)(void __iomem *ioaddr, struct stmmac_axi *axi);
|
||||
/* Dump DMA registers */
|
||||
void (*dump_regs)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 *reg_space);
|
||||
void (*dma_rx_mode)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int mode, u32 channel,
|
||||
int fifosz, u8 qmode);
|
||||
void (*dma_tx_mode)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int mode, u32 channel, int fifosz, u8 qmode);
|
||||
/* To track extra statistic (if supported) */
|
||||
void (*dma_diagnostic_fr)(struct stmmac_extra_stats *x,
|
||||
void __iomem *ioaddr);
|
||||
void (*enable_dma_transmission)(void __iomem *ioaddr, u32 chan);
|
||||
void (*enable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void (*disable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void (*start_tx)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void (*stop_tx)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void (*start_rx)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void (*stop_rx)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
int (*dma_interrupt)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 chan, u32 dir);
|
||||
/* If supported then get the optional core features */
|
||||
int (*get_hw_feature)(void __iomem *ioaddr,
|
||||
struct dma_features *dma_cap);
|
||||
/* Program the HW RX Watchdog */
|
||||
void (*rx_watchdog)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 riwt, u32 queue);
|
||||
void (*set_tx_ring_len)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 len, u32 chan);
|
||||
void (*set_rx_ring_len)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 len, u32 chan);
|
||||
void (*set_rx_tail_ptr)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 tail_ptr, u32 chan);
|
||||
void (*set_tx_tail_ptr)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 tail_ptr, u32 chan);
|
||||
void (*enable_tso)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan);
|
||||
void (*qmode)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 channel, u8 qmode);
|
||||
void (*set_bfsize)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int bfsize, u32 chan);
|
||||
void (*enable_sph)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan);
|
||||
int (*enable_tbs)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan);
|
||||
};
|
||||
|
||||
#define stmmac_dma_init(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, init, __args)
|
||||
#define stmmac_init_chan(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, init_chan, __priv, __args)
|
||||
#define stmmac_init_rx_chan(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, init_rx_chan, __priv, __args)
|
||||
#define stmmac_init_tx_chan(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, init_tx_chan, __priv, __args)
|
||||
#define stmmac_axi(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, axi, __args)
|
||||
#define stmmac_dump_dma_regs(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, dump_regs, __priv, __args)
|
||||
#define stmmac_dma_rx_mode(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, dma_rx_mode, __priv, __args)
|
||||
#define stmmac_dma_tx_mode(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, dma_tx_mode, __priv, __args)
|
||||
#define stmmac_dma_diagnostic_fr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, dma_diagnostic_fr, __args)
|
||||
#define stmmac_enable_dma_transmission(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, enable_dma_transmission, __args)
|
||||
#define stmmac_enable_dma_irq(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, enable_dma_irq, __priv, __args)
|
||||
#define stmmac_disable_dma_irq(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, disable_dma_irq, __priv, __args)
|
||||
#define stmmac_start_tx(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, start_tx, __priv, __args)
|
||||
#define stmmac_stop_tx(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, stop_tx, __priv, __args)
|
||||
#define stmmac_start_rx(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, start_rx, __priv, __args)
|
||||
#define stmmac_stop_rx(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, stop_rx, __priv, __args)
|
||||
#define stmmac_dma_interrupt_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, dma, dma_interrupt, __priv, __args)
|
||||
#define stmmac_get_hw_feature(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, dma, get_hw_feature, __args)
|
||||
#define stmmac_rx_watchdog(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, rx_watchdog, __priv, __args)
|
||||
#define stmmac_set_tx_ring_len(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, set_tx_ring_len, __priv, __args)
|
||||
#define stmmac_set_rx_ring_len(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, set_rx_ring_len, __priv, __args)
|
||||
#define stmmac_set_rx_tail_ptr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, set_rx_tail_ptr, __priv, __args)
|
||||
#define stmmac_set_tx_tail_ptr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, set_tx_tail_ptr, __priv, __args)
|
||||
#define stmmac_enable_tso(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, enable_tso, __priv, __args)
|
||||
#define stmmac_dma_qmode(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, qmode, __priv, __args)
|
||||
#define stmmac_set_dma_bfsize(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, set_bfsize, __priv, __args)
|
||||
#define stmmac_enable_sph(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, enable_sph, __priv, __args)
|
||||
#define stmmac_enable_tbs(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, dma, enable_tbs, __priv, __args)
|
||||
|
||||
struct mac_device_info;
|
||||
struct net_device;
|
||||
struct rgmii_adv;
|
||||
struct stmmac_tc_entry;
|
||||
struct stmmac_pps_cfg;
|
||||
struct stmmac_rss;
|
||||
struct stmmac_est;
|
||||
|
||||
/* Helpers to program the MAC core */
|
||||
struct stmmac_ops {
|
||||
/* MAC core initialization */
|
||||
void (*core_init)(struct mac_device_info *hw, struct net_device *dev);
|
||||
/* Update MAC capabilities */
|
||||
void (*update_caps)(struct stmmac_priv *priv);
|
||||
/* Enable the MAC RX/TX */
|
||||
void (*set_mac)(void __iomem *ioaddr, bool enable);
|
||||
/* Enable and verify that the IPC module is supported */
|
||||
int (*rx_ipc)(struct mac_device_info *hw);
|
||||
/* Enable RX Queues */
|
||||
void (*rx_queue_enable)(struct mac_device_info *hw, u8 mode, u32 queue);
|
||||
/* RX Queues Priority */
|
||||
void (*rx_queue_prio)(struct mac_device_info *hw, u32 prio, u32 queue);
|
||||
/* TX Queues Priority */
|
||||
void (*tx_queue_prio)(struct mac_device_info *hw, u32 prio, u32 queue);
|
||||
/* RX Queues Routing */
|
||||
void (*rx_queue_routing)(struct mac_device_info *hw, u8 packet,
|
||||
u32 queue);
|
||||
/* Program RX Algorithms */
|
||||
void (*prog_mtl_rx_algorithms)(struct mac_device_info *hw, u32 rx_alg);
|
||||
/* Program TX Algorithms */
|
||||
void (*prog_mtl_tx_algorithms)(struct mac_device_info *hw, u32 tx_alg);
|
||||
/* Set MTL TX queues weight */
|
||||
void (*set_mtl_tx_queue_weight)(struct stmmac_priv *priv,
|
||||
struct mac_device_info *hw,
|
||||
u32 weight, u32 queue);
|
||||
/* RX MTL queue to RX dma mapping */
|
||||
void (*map_mtl_to_dma)(struct mac_device_info *hw, u32 queue, u32 chan);
|
||||
/* Configure AV Algorithm */
|
||||
void (*config_cbs)(struct stmmac_priv *priv, struct mac_device_info *hw,
|
||||
u32 send_slope, u32 idle_slope, u32 high_credit,
|
||||
u32 low_credit, u32 queue);
|
||||
/* Dump MAC registers */
|
||||
void (*dump_regs)(struct mac_device_info *hw, u32 *reg_space);
|
||||
/* Handle extra events on specific interrupts hw dependent */
|
||||
int (*host_irq_status)(struct mac_device_info *hw,
|
||||
struct stmmac_extra_stats *x);
|
||||
/* Handle MTL interrupts */
|
||||
int (*host_mtl_irq_status)(struct stmmac_priv *priv,
|
||||
struct mac_device_info *hw, u32 chan);
|
||||
/* Multicast filter setting */
|
||||
void (*set_filter)(struct mac_device_info *hw, struct net_device *dev);
|
||||
/* Flow control setting */
|
||||
void (*flow_ctrl)(struct mac_device_info *hw, unsigned int duplex,
|
||||
unsigned int fc, unsigned int pause_time, u32 tx_cnt);
|
||||
/* Set power management mode (e.g. magic frame) */
|
||||
void (*pmt)(struct mac_device_info *hw, unsigned long mode);
|
||||
/* Set/Get Unicast MAC addresses */
|
||||
void (*set_umac_addr)(struct mac_device_info *hw,
|
||||
const unsigned char *addr,
|
||||
unsigned int reg_n);
|
||||
void (*get_umac_addr)(struct mac_device_info *hw, unsigned char *addr,
|
||||
unsigned int reg_n);
|
||||
void (*set_eee_mode)(struct mac_device_info *hw,
|
||||
bool en_tx_lpi_clockgating);
|
||||
void (*reset_eee_mode)(struct mac_device_info *hw);
|
||||
void (*set_eee_lpi_entry_timer)(struct mac_device_info *hw, int et);
|
||||
void (*set_eee_timer)(struct mac_device_info *hw, int ls, int tw);
|
||||
void (*set_eee_pls)(struct mac_device_info *hw, int link);
|
||||
void (*debug)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 rx_queues,
|
||||
u32 tx_queues);
|
||||
/* PCS calls */
|
||||
void (*pcs_ctrl_ane)(void __iomem *ioaddr, bool ane, bool srgmi_ral,
|
||||
bool loopback);
|
||||
void (*pcs_get_adv_lp)(void __iomem *ioaddr, struct rgmii_adv *adv);
|
||||
/* Safety Features */
|
||||
int (*safety_feat_config)(void __iomem *ioaddr, unsigned int asp,
|
||||
struct stmmac_safety_feature_cfg *safety_cfg);
|
||||
int (*safety_feat_irq_status)(struct net_device *ndev,
|
||||
void __iomem *ioaddr, unsigned int asp,
|
||||
struct stmmac_safety_stats *stats);
|
||||
int (*safety_feat_dump)(struct stmmac_safety_stats *stats,
|
||||
int index, unsigned long *count, const char **desc);
|
||||
/* Flexible RX Parser */
|
||||
int (*rxp_config)(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
|
||||
unsigned int count);
|
||||
/* Flexible PPS */
|
||||
int (*flex_pps_config)(void __iomem *ioaddr, int index,
|
||||
struct stmmac_pps_cfg *cfg, bool enable,
|
||||
u32 sub_second_inc, u32 systime_flags);
|
||||
/* Loopback for selftests */
|
||||
void (*set_mac_loopback)(void __iomem *ioaddr, bool enable);
|
||||
/* RSS */
|
||||
int (*rss_configure)(struct mac_device_info *hw,
|
||||
struct stmmac_rss *cfg, u32 num_rxq);
|
||||
/* VLAN */
|
||||
void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash,
|
||||
u16 perfect_match, bool is_double);
|
||||
void (*enable_vlan)(struct mac_device_info *hw, u32 type);
|
||||
void (*rx_hw_vlan)(struct mac_device_info *hw, struct dma_desc *rx_desc,
|
||||
struct sk_buff *skb);
|
||||
void (*set_hw_vlan_mode)(struct mac_device_info *hw);
|
||||
int (*add_hw_vlan_rx_fltr)(struct net_device *dev,
|
||||
struct mac_device_info *hw,
|
||||
__be16 proto, u16 vid);
|
||||
int (*del_hw_vlan_rx_fltr)(struct net_device *dev,
|
||||
struct mac_device_info *hw,
|
||||
__be16 proto, u16 vid);
|
||||
void (*restore_hw_vlan_rx_fltr)(struct net_device *dev,
|
||||
struct mac_device_info *hw);
|
||||
/* TX Timestamp */
|
||||
int (*get_mac_tx_timestamp)(struct mac_device_info *hw, u64 *ts);
|
||||
/* Source Address Insertion / Replacement */
|
||||
void (*sarc_configure)(void __iomem *ioaddr, int val);
|
||||
/* Filtering */
|
||||
int (*config_l3_filter)(struct mac_device_info *hw, u32 filter_no,
|
||||
bool en, bool ipv6, bool sa, bool inv,
|
||||
u32 match);
|
||||
int (*config_l4_filter)(struct mac_device_info *hw, u32 filter_no,
|
||||
bool en, bool udp, bool sa, bool inv,
|
||||
u32 match);
|
||||
void (*set_arp_offload)(struct mac_device_info *hw, bool en, u32 addr);
|
||||
void (*fpe_configure)(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
||||
u32 num_txq, u32 num_rxq,
|
||||
bool tx_enable, bool pmac_enable);
|
||||
void (*fpe_send_mpacket)(void __iomem *ioaddr,
|
||||
struct stmmac_fpe_cfg *cfg,
|
||||
enum stmmac_mpacket_type type);
|
||||
int (*fpe_irq_status)(void __iomem *ioaddr, struct net_device *dev);
|
||||
int (*fpe_get_add_frag_size)(const void __iomem *ioaddr);
|
||||
void (*fpe_set_add_frag_size)(void __iomem *ioaddr, u32 add_frag_size);
|
||||
int (*fpe_map_preemption_class)(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack,
|
||||
u32 pclass);
|
||||
};
|
||||
|
||||
#define stmmac_core_init(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, core_init, __args)
|
||||
#define stmmac_mac_update_caps(__priv) \
|
||||
stmmac_do_void_callback(__priv, mac, update_caps, __priv)
|
||||
#define stmmac_mac_set(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_mac, __args)
|
||||
#define stmmac_rx_ipc(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, rx_ipc, __args)
|
||||
#define stmmac_rx_queue_enable(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, rx_queue_enable, __args)
|
||||
#define stmmac_rx_queue_prio(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, rx_queue_prio, __args)
|
||||
#define stmmac_tx_queue_prio(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, tx_queue_prio, __args)
|
||||
#define stmmac_rx_queue_routing(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, rx_queue_routing, __args)
|
||||
#define stmmac_prog_mtl_rx_algorithms(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, prog_mtl_rx_algorithms, __args)
|
||||
#define stmmac_prog_mtl_tx_algorithms(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, prog_mtl_tx_algorithms, __args)
|
||||
#define stmmac_set_mtl_tx_queue_weight(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_mtl_tx_queue_weight, __priv, __args)
|
||||
#define stmmac_map_mtl_to_dma(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, map_mtl_to_dma, __args)
|
||||
#define stmmac_config_cbs(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, config_cbs, __priv, __args)
|
||||
#define stmmac_dump_mac_regs(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, dump_regs, __args)
|
||||
#define stmmac_host_irq_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, host_irq_status, __args)
|
||||
#define stmmac_host_mtl_irq_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, host_mtl_irq_status, __priv, __args)
|
||||
#define stmmac_set_filter(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_filter, __args)
|
||||
#define stmmac_flow_ctrl(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, flow_ctrl, __args)
|
||||
#define stmmac_pmt(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, pmt, __args)
|
||||
#define stmmac_set_umac_addr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_umac_addr, __args)
|
||||
#define stmmac_get_umac_addr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, get_umac_addr, __args)
|
||||
#define stmmac_set_eee_mode(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_eee_mode, __args)
|
||||
#define stmmac_reset_eee_mode(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, reset_eee_mode, __args)
|
||||
#define stmmac_set_eee_lpi_timer(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_eee_lpi_entry_timer, __args)
|
||||
#define stmmac_set_eee_timer(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_eee_timer, __args)
|
||||
#define stmmac_set_eee_pls(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_eee_pls, __args)
|
||||
#define stmmac_mac_debug(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, debug, __priv, __args)
|
||||
#define stmmac_pcs_ctrl_ane(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, pcs_ctrl_ane, __args)
|
||||
#define stmmac_pcs_get_adv_lp(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, pcs_get_adv_lp, __args)
|
||||
#define stmmac_safety_feat_config(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, safety_feat_config, __args)
|
||||
#define stmmac_safety_feat_irq_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, safety_feat_irq_status, __args)
|
||||
#define stmmac_safety_feat_dump(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, safety_feat_dump, __args)
|
||||
#define stmmac_rxp_config(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, rxp_config, __args)
|
||||
#define stmmac_flex_pps_config(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, flex_pps_config, __args)
|
||||
#define stmmac_set_mac_loopback(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_mac_loopback, __args)
|
||||
#define stmmac_rss_configure(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, rss_configure, __args)
|
||||
#define stmmac_update_vlan_hash(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, update_vlan_hash, __args)
|
||||
#define stmmac_enable_vlan(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, enable_vlan, __args)
|
||||
#define stmmac_rx_hw_vlan(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, rx_hw_vlan, __args)
|
||||
#define stmmac_set_hw_vlan_mode(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_hw_vlan_mode, __args)
|
||||
#define stmmac_add_hw_vlan_rx_fltr(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, add_hw_vlan_rx_fltr, __args)
|
||||
#define stmmac_del_hw_vlan_rx_fltr(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, del_hw_vlan_rx_fltr, __args)
|
||||
#define stmmac_restore_hw_vlan_rx_fltr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, restore_hw_vlan_rx_fltr, __args)
|
||||
#define stmmac_get_mac_tx_timestamp(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, get_mac_tx_timestamp, __args)
|
||||
#define stmmac_sarc_configure(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, sarc_configure, __args)
|
||||
#define stmmac_config_l3_filter(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, config_l3_filter, __args)
|
||||
#define stmmac_config_l4_filter(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, config_l4_filter, __args)
|
||||
#define stmmac_set_arp_offload(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_arp_offload, __args)
|
||||
#define stmmac_fpe_configure(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_configure, __args)
|
||||
#define stmmac_fpe_send_mpacket(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_send_mpacket, __args)
|
||||
#define stmmac_fpe_irq_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, fpe_irq_status, __args)
|
||||
#define stmmac_fpe_get_add_frag_size(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, fpe_get_add_frag_size, __args)
|
||||
#define stmmac_fpe_set_add_frag_size(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_set_add_frag_size, __args)
|
||||
#define stmmac_fpe_map_preemption_class(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_map_preemption_class, __args)
|
||||
|
||||
/* PTP and HW Timer helpers */
|
||||
struct stmmac_hwtimestamp {
|
||||
void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
|
||||
void (*config_sub_second_increment)(void __iomem *ioaddr, u32 ptp_clock,
|
||||
int gmac4, u32 *ssinc);
|
||||
int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
|
||||
int (*config_addend) (void __iomem *ioaddr, u32 addend);
|
||||
int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec,
|
||||
int add_sub, int gmac4);
|
||||
void (*get_systime) (void __iomem *ioaddr, u64 *systime);
|
||||
void (*get_ptptime)(void __iomem *ioaddr, u64 *ptp_time);
|
||||
void (*timestamp_interrupt)(struct stmmac_priv *priv);
|
||||
void (*hwtstamp_correct_latency)(struct stmmac_priv *priv);
|
||||
};
|
||||
|
||||
#define stmmac_config_hw_tstamping(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, config_hw_tstamping, __args)
|
||||
#define stmmac_config_sub_second_increment(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, config_sub_second_increment, __args)
|
||||
#define stmmac_init_systime(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, ptp, init_systime, __args)
|
||||
#define stmmac_config_addend(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, ptp, config_addend, __args)
|
||||
#define stmmac_adjust_systime(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, ptp, adjust_systime, __args)
|
||||
#define stmmac_get_systime(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, get_systime, __args)
|
||||
#define stmmac_get_ptptime(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, get_ptptime, __args)
|
||||
#define stmmac_timestamp_interrupt(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, timestamp_interrupt, __args)
|
||||
#define stmmac_hwtstamp_correct_latency(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, hwtstamp_correct_latency, __args)
|
||||
|
||||
struct stmmac_tx_queue;
|
||||
struct stmmac_rx_queue;
|
||||
|
||||
/* Helpers to manage the descriptors for chain and ring modes */
|
||||
struct stmmac_mode_ops {
|
||||
void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,
|
||||
unsigned int extend_desc);
|
||||
unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
|
||||
int (*jumbo_frm)(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
|
||||
int csum);
|
||||
int (*set_16kib_bfsize)(int mtu);
|
||||
void (*init_desc3)(struct dma_desc *p);
|
||||
void (*refill_desc3)(struct stmmac_rx_queue *rx_q, struct dma_desc *p);
|
||||
void (*clean_desc3)(struct stmmac_tx_queue *tx_q, struct dma_desc *p);
|
||||
};
|
||||
|
||||
#define stmmac_mode_init(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mode, init, __args)
|
||||
#define stmmac_is_jumbo_frm(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mode, is_jumbo_frm, __args)
|
||||
#define stmmac_jumbo_frm(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mode, jumbo_frm, __args)
|
||||
#define stmmac_set_16kib_bfsize(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mode, set_16kib_bfsize, __args)
|
||||
#define stmmac_init_desc3(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mode, init_desc3, __args)
|
||||
#define stmmac_refill_desc3(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mode, refill_desc3, __args)
|
||||
#define stmmac_clean_desc3(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mode, clean_desc3, __args)
|
||||
|
||||
struct tc_cls_u32_offload;
|
||||
struct tc_cbs_qopt_offload;
|
||||
struct flow_cls_offload;
|
||||
struct tc_taprio_qopt_offload;
|
||||
struct tc_etf_qopt_offload;
|
||||
struct tc_query_caps_base;
|
||||
|
||||
struct stmmac_tc_ops {
|
||||
int (*init)(struct stmmac_priv *priv);
|
||||
int (*setup_cls_u32)(struct stmmac_priv *priv,
|
||||
struct tc_cls_u32_offload *cls);
|
||||
int (*setup_cbs)(struct stmmac_priv *priv,
|
||||
struct tc_cbs_qopt_offload *qopt);
|
||||
int (*setup_cls)(struct stmmac_priv *priv,
|
||||
struct flow_cls_offload *cls);
|
||||
int (*setup_taprio)(struct stmmac_priv *priv,
|
||||
struct tc_taprio_qopt_offload *qopt);
|
||||
int (*setup_etf)(struct stmmac_priv *priv,
|
||||
struct tc_etf_qopt_offload *qopt);
|
||||
int (*query_caps)(struct stmmac_priv *priv,
|
||||
struct tc_query_caps_base *base);
|
||||
int (*setup_mqprio)(struct stmmac_priv *priv,
|
||||
struct tc_mqprio_qopt_offload *qopt);
|
||||
};
|
||||
|
||||
#define stmmac_tc_init(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, init, __args)
|
||||
#define stmmac_tc_setup_cls_u32(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_cls_u32, __args)
|
||||
#define stmmac_tc_setup_cbs(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_cbs, __args)
|
||||
#define stmmac_tc_setup_cls(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_cls, __args)
|
||||
#define stmmac_tc_setup_taprio(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_taprio, __args)
|
||||
#define stmmac_tc_setup_etf(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_etf, __args)
|
||||
#define stmmac_tc_query_caps(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, query_caps, __args)
|
||||
#define stmmac_tc_setup_mqprio(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_mqprio, __args)
|
||||
|
||||
struct stmmac_counters;
|
||||
|
||||
struct stmmac_mmc_ops {
|
||||
void (*ctrl)(void __iomem *ioaddr, unsigned int mode);
|
||||
void (*intr_all_mask)(void __iomem *ioaddr);
|
||||
void (*read)(void __iomem *ioaddr, struct stmmac_counters *mmc);
|
||||
};
|
||||
|
||||
#define stmmac_mmc_ctrl(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mmc, ctrl, __args)
|
||||
#define stmmac_mmc_intr_all_mask(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mmc, intr_all_mask, __args)
|
||||
#define stmmac_mmc_read(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mmc, read, __args)
|
||||
|
||||
struct stmmac_est_ops {
|
||||
int (*configure)(struct stmmac_priv *priv, struct stmmac_est *cfg,
|
||||
unsigned int ptp_rate);
|
||||
void (*irq_status)(struct stmmac_priv *priv, struct net_device *dev,
|
||||
struct stmmac_extra_stats *x, u32 txqcnt);
|
||||
};
|
||||
|
||||
#define stmmac_est_configure(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, est, configure, __args)
|
||||
#define stmmac_est_irq_status(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, est, irq_status, __args)
|
||||
|
||||
struct stmmac_regs_off {
|
||||
u32 ptp_off;
|
||||
u32 mmc_off;
|
||||
u32 est_off;
|
||||
};
|
||||
|
||||
extern const struct stmmac_ops dwmac100_ops;
|
||||
extern const struct stmmac_dma_ops dwmac100_dma_ops;
|
||||
extern const struct stmmac_ops dwmac1000_ops;
|
||||
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
|
||||
extern const struct stmmac_ops dwmac4_ops;
|
||||
extern const struct stmmac_dma_ops dwmac4_dma_ops;
|
||||
extern const struct stmmac_ops dwmac410_ops;
|
||||
extern const struct stmmac_dma_ops dwmac410_dma_ops;
|
||||
extern const struct stmmac_ops dwmac510_ops;
|
||||
extern const struct stmmac_tc_ops dwmac4_tc_ops;
|
||||
extern const struct stmmac_tc_ops dwmac510_tc_ops;
|
||||
extern const struct stmmac_tc_ops dwxgmac_tc_ops;
|
||||
extern const struct stmmac_ops dwxgmac210_ops;
|
||||
extern const struct stmmac_ops dwxlgmac2_ops;
|
||||
extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
|
||||
extern const struct stmmac_desc_ops dwxgmac210_desc_ops;
|
||||
extern const struct stmmac_mmc_ops dwmac_mmc_ops;
|
||||
extern const struct stmmac_mmc_ops dwxgmac_mmc_ops;
|
||||
extern const struct stmmac_est_ops dwmac510_est_ops;
|
||||
|
||||
#define GMAC_VERSION 0x00000020 /* GMAC CORE Version */
|
||||
#define GMAC4_VERSION 0x00000110 /* GMAC4+ CORE Version */
|
||||
|
||||
int stmmac_reset(struct stmmac_priv *priv, void __iomem *ioaddr);
|
||||
int stmmac_hwif_init(struct stmmac_priv *priv);
|
||||
|
||||
#endif /* __STMMAC_HWIF_H__ */
|
||||
|
|
@ -0,0 +1,376 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
|
||||
* stmmac HW Interface Handling
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_ptp.h"
|
||||
#include "stmmac_est.h"
|
||||
|
||||
static u32 stmmac_get_id(struct stmmac_priv *priv, u32 id_reg)
|
||||
{
|
||||
u32 reg = readl(priv->ioaddr + id_reg);
|
||||
|
||||
if (!reg) {
|
||||
dev_info(priv->device, "Version ID not available\n");
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
dev_info(priv->device, "User ID: 0x%x, Synopsys ID: 0x%x\n",
|
||||
(unsigned int)(reg & GENMASK(15, 8)) >> 8,
|
||||
(unsigned int)(reg & GENMASK(7, 0)));
|
||||
return reg & GENMASK(7, 0);
|
||||
}
|
||||
|
||||
static u32 stmmac_get_dev_id(struct stmmac_priv *priv, u32 id_reg)
|
||||
{
|
||||
u32 reg = readl(priv->ioaddr + id_reg);
|
||||
|
||||
if (!reg) {
|
||||
dev_info(priv->device, "Version ID not available\n");
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
return (reg & GENMASK(15, 8)) >> 8;
|
||||
}
|
||||
|
||||
static void stmmac_dwmac_mode_quirk(struct stmmac_priv *priv)
|
||||
{
|
||||
struct mac_device_info *mac = priv->hw;
|
||||
|
||||
if (priv->chain_mode) {
|
||||
dev_info(priv->device, "Chain mode enabled\n");
|
||||
priv->mode = STMMAC_CHAIN_MODE;
|
||||
mac->mode = &chain_mode_ops;
|
||||
} else {
|
||||
dev_info(priv->device, "Ring mode enabled\n");
|
||||
priv->mode = STMMAC_RING_MODE;
|
||||
mac->mode = &ring_mode_ops;
|
||||
}
|
||||
}
|
||||
|
||||
static int stmmac_dwmac1_quirks(struct stmmac_priv *priv)
|
||||
{
|
||||
struct mac_device_info *mac = priv->hw;
|
||||
|
||||
if (priv->plat->enh_desc) {
|
||||
dev_info(priv->device, "Enhanced/Alternate descriptors\n");
|
||||
|
||||
/* GMAC older than 3.50 has no extended descriptors */
|
||||
if (priv->synopsys_id >= DWMAC_CORE_3_50) {
|
||||
dev_info(priv->device, "Enabled extended descriptors\n");
|
||||
priv->extend_desc = 1;
|
||||
} else {
|
||||
dev_warn(priv->device, "Extended descriptors not supported\n");
|
||||
}
|
||||
|
||||
mac->desc = &enh_desc_ops;
|
||||
} else {
|
||||
dev_info(priv->device, "Normal descriptors\n");
|
||||
mac->desc = &ndesc_ops;
|
||||
}
|
||||
|
||||
stmmac_dwmac_mode_quirk(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
|
||||
{
|
||||
stmmac_dwmac_mode_quirk(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_dwxlgmac_quirks(struct stmmac_priv *priv)
|
||||
{
|
||||
priv->hw->xlgmac = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmmac_reset(struct stmmac_priv *priv, void __iomem *ioaddr)
|
||||
{
|
||||
struct plat_stmmacenet_data *plat = priv ? priv->plat : NULL;
|
||||
|
||||
if (!priv)
|
||||
return -EINVAL;
|
||||
|
||||
if (plat && plat->fix_soc_reset)
|
||||
return plat->fix_soc_reset(plat, ioaddr);
|
||||
|
||||
return stmmac_do_callback(priv, dma, reset, ioaddr);
|
||||
}
|
||||
|
||||
static const struct stmmac_hwif_entry {
|
||||
bool gmac;
|
||||
bool gmac4;
|
||||
bool xgmac;
|
||||
u32 min_id;
|
||||
u32 dev_id;
|
||||
const struct stmmac_regs_off regs;
|
||||
const void *desc;
|
||||
const void *dma;
|
||||
const void *mac;
|
||||
const void *hwtimestamp;
|
||||
const void *mode;
|
||||
const void *tc;
|
||||
const void *mmc;
|
||||
const void *est;
|
||||
int (*setup)(struct stmmac_priv *priv);
|
||||
int (*quirks)(struct stmmac_priv *priv);
|
||||
} stmmac_hw[] = {
|
||||
/* NOTE: New HW versions shall go to the end of this table */
|
||||
{
|
||||
.gmac = false,
|
||||
.gmac4 = false,
|
||||
.xgmac = false,
|
||||
.min_id = 0,
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC3_X_OFFSET,
|
||||
.mmc_off = MMC_GMAC3_X_OFFSET,
|
||||
},
|
||||
.desc = NULL,
|
||||
.dma = &dwmac100_dma_ops,
|
||||
.mac = &dwmac100_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = NULL,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.setup = dwmac100_setup,
|
||||
.quirks = stmmac_dwmac1_quirks,
|
||||
}, {
|
||||
.gmac = true,
|
||||
.gmac4 = false,
|
||||
.xgmac = false,
|
||||
.min_id = 0,
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC3_X_OFFSET,
|
||||
.mmc_off = MMC_GMAC3_X_OFFSET,
|
||||
},
|
||||
.desc = NULL,
|
||||
.dma = &dwmac1000_dma_ops,
|
||||
.mac = &dwmac1000_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = NULL,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.setup = dwmac1000_setup,
|
||||
.quirks = stmmac_dwmac1_quirks,
|
||||
}, {
|
||||
.gmac = false,
|
||||
.gmac4 = true,
|
||||
.xgmac = false,
|
||||
.min_id = 0,
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac4_dma_ops,
|
||||
.mac = &dwmac4_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = &dwmac4_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
.quirks = stmmac_dwmac4_quirks,
|
||||
}, {
|
||||
.gmac = false,
|
||||
.gmac4 = true,
|
||||
.xgmac = false,
|
||||
.min_id = DWMAC_CORE_4_00,
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac4_dma_ops,
|
||||
.mac = &dwmac410_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = &dwmac4_ring_mode_ops,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
.quirks = NULL,
|
||||
}, {
|
||||
.gmac = false,
|
||||
.gmac4 = true,
|
||||
.xgmac = false,
|
||||
.min_id = DWMAC_CORE_4_10,
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac410_dma_ops,
|
||||
.mac = &dwmac410_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = &dwmac4_ring_mode_ops,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
.quirks = NULL,
|
||||
}, {
|
||||
.gmac = false,
|
||||
.gmac4 = true,
|
||||
.xgmac = false,
|
||||
.min_id = DWMAC_CORE_5_10,
|
||||
.regs = {
|
||||
.ptp_off = PTP_GMAC4_OFFSET,
|
||||
.mmc_off = MMC_GMAC4_OFFSET,
|
||||
.est_off = EST_GMAC4_OFFSET,
|
||||
},
|
||||
.desc = &dwmac4_desc_ops,
|
||||
.dma = &dwmac410_dma_ops,
|
||||
.mac = &dwmac510_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = &dwmac4_ring_mode_ops,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
.quirks = NULL,
|
||||
}, {
|
||||
.gmac = false,
|
||||
.gmac4 = false,
|
||||
.xgmac = true,
|
||||
.min_id = DWXGMAC_CORE_2_10,
|
||||
.dev_id = DWXGMAC_ID,
|
||||
.regs = {
|
||||
.ptp_off = PTP_XGMAC_OFFSET,
|
||||
.mmc_off = MMC_XGMAC_OFFSET,
|
||||
.est_off = EST_XGMAC_OFFSET,
|
||||
},
|
||||
.desc = &dwxgmac210_desc_ops,
|
||||
.dma = &dwxgmac210_dma_ops,
|
||||
.mac = &dwxgmac210_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = &dwxgmac_tc_ops,
|
||||
.mmc = &dwxgmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwxgmac2_setup,
|
||||
.quirks = NULL,
|
||||
}, {
|
||||
.gmac = false,
|
||||
.gmac4 = false,
|
||||
.xgmac = true,
|
||||
.min_id = DWXLGMAC_CORE_2_00,
|
||||
.dev_id = DWXLGMAC_ID,
|
||||
.regs = {
|
||||
.ptp_off = PTP_XGMAC_OFFSET,
|
||||
.mmc_off = MMC_XGMAC_OFFSET,
|
||||
.est_off = EST_XGMAC_OFFSET,
|
||||
},
|
||||
.desc = &dwxgmac210_desc_ops,
|
||||
.dma = &dwxgmac210_dma_ops,
|
||||
.mac = &dwxlgmac2_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = &dwxgmac_tc_ops,
|
||||
.mmc = &dwxgmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwxlgmac2_setup,
|
||||
.quirks = stmmac_dwxlgmac_quirks,
|
||||
},
|
||||
};
|
||||
|
||||
int stmmac_hwif_init(struct stmmac_priv *priv)
|
||||
{
|
||||
bool needs_xgmac = priv->plat->has_xgmac;
|
||||
bool needs_gmac4 = priv->plat->has_gmac4;
|
||||
bool needs_gmac = priv->plat->has_gmac;
|
||||
const struct stmmac_hwif_entry *entry;
|
||||
struct mac_device_info *mac;
|
||||
bool needs_setup = true;
|
||||
u32 id, dev_id = 0;
|
||||
int i, ret;
|
||||
|
||||
if (needs_gmac) {
|
||||
id = stmmac_get_id(priv, GMAC_VERSION);
|
||||
} else if (needs_gmac4 || needs_xgmac) {
|
||||
id = stmmac_get_id(priv, GMAC4_VERSION);
|
||||
if (needs_xgmac)
|
||||
dev_id = stmmac_get_dev_id(priv, GMAC4_VERSION);
|
||||
} else {
|
||||
id = 0;
|
||||
}
|
||||
|
||||
/* Save ID for later use */
|
||||
priv->synopsys_id = id;
|
||||
|
||||
/* Lets assume some safe values first */
|
||||
priv->ptpaddr = priv->ioaddr +
|
||||
(needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET);
|
||||
priv->mmcaddr = priv->ioaddr +
|
||||
(needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET);
|
||||
if (needs_gmac4)
|
||||
priv->estaddr = priv->ioaddr + EST_GMAC4_OFFSET;
|
||||
else if (needs_xgmac)
|
||||
priv->estaddr = priv->ioaddr + EST_XGMAC_OFFSET;
|
||||
|
||||
/* Check for HW specific setup first */
|
||||
if (priv->plat->setup) {
|
||||
mac = priv->plat->setup(priv);
|
||||
needs_setup = false;
|
||||
} else {
|
||||
mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);
|
||||
}
|
||||
|
||||
if (!mac)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Fallback to generic HW */
|
||||
for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) {
|
||||
entry = &stmmac_hw[i];
|
||||
|
||||
if (needs_gmac ^ entry->gmac)
|
||||
continue;
|
||||
if (needs_gmac4 ^ entry->gmac4)
|
||||
continue;
|
||||
if (needs_xgmac ^ entry->xgmac)
|
||||
continue;
|
||||
/* Use synopsys_id var because some setups can override this */
|
||||
if (priv->synopsys_id < entry->min_id)
|
||||
continue;
|
||||
if (needs_xgmac && (dev_id ^ entry->dev_id))
|
||||
continue;
|
||||
|
||||
/* Only use generic HW helpers if needed */
|
||||
mac->desc = mac->desc ? : entry->desc;
|
||||
mac->dma = mac->dma ? : entry->dma;
|
||||
mac->mac = mac->mac ? : entry->mac;
|
||||
mac->ptp = mac->ptp ? : entry->hwtimestamp;
|
||||
mac->mode = mac->mode ? : entry->mode;
|
||||
mac->tc = mac->tc ? : entry->tc;
|
||||
mac->mmc = mac->mmc ? : entry->mmc;
|
||||
mac->est = mac->est ? : entry->est;
|
||||
|
||||
priv->hw = mac;
|
||||
priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
|
||||
priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
|
||||
if (entry->est)
|
||||
priv->estaddr = priv->ioaddr + entry->regs.est_off;
|
||||
|
||||
/* Entry found */
|
||||
if (needs_setup) {
|
||||
ret = entry->setup(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Save quirks, if needed for posterior use */
|
||||
priv->hwif_quirks = entry->quirks;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(priv->device, "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n",
|
||||
id, needs_gmac, needs_gmac4);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -0,0 +1,712 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
|
||||
// Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
|
||||
// stmmac HW Interface Callbacks
|
||||
|
||||
#ifndef __STMMAC_HWIF_H__
|
||||
#define __STMMAC_HWIF_H__
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/stmmac.h>
|
||||
#include <net/pkt_cls.h>
|
||||
|
||||
#define stmmac_do_void_callback(__priv, __module, __cname, __arg0, __args...) \
|
||||
({ \
|
||||
int __result = -EINVAL; \
|
||||
if ((__priv)->hw->__module && (__priv)->hw->__module->__cname) { \
|
||||
(__priv)->hw->__module->__cname((__arg0), ##__args); \
|
||||
__result = 0; \
|
||||
} \
|
||||
__result; \
|
||||
})
|
||||
#define stmmac_do_callback(__priv, __module, __cname, __arg0, __args...) \
|
||||
({ \
|
||||
int __result = -EINVAL; \
|
||||
if ((__priv)->hw->__module && (__priv)->hw->__module->__cname) \
|
||||
__result = (__priv)->hw->__module->__cname((__arg0), ##__args); \
|
||||
__result; \
|
||||
})
|
||||
|
||||
struct stmmac_extra_stats;
|
||||
struct stmmac_priv;
|
||||
struct stmmac_safety_stats;
|
||||
struct stmmac_fpe_cfg;
|
||||
enum stmmac_mpacket_type;
|
||||
struct dma_desc;
|
||||
struct dma_extended_desc;
|
||||
struct dma_edesc;
|
||||
|
||||
/* Descriptors helpers */
|
||||
struct stmmac_desc_ops {
|
||||
/* DMA RX descriptor ring initialization */
|
||||
void (*init_rx_desc)(struct dma_desc *p, int disable_rx_ic, int mode,
|
||||
int end, int bfsize);
|
||||
/* DMA TX descriptor ring initialization */
|
||||
void (*init_tx_desc)(struct dma_desc *p, int mode, int end);
|
||||
/* Invoked by the xmit function to prepare the tx descriptor */
|
||||
void (*prepare_tx_desc)(struct dma_desc *p, int is_fs, int len,
|
||||
bool csum_flag, int mode, bool tx_own, bool ls,
|
||||
unsigned int tot_pkt_len);
|
||||
void (*prepare_tso_tx_desc)(struct dma_desc *p, int is_fs, int len1,
|
||||
int len2, bool tx_own, bool ls, unsigned int tcphdrlen,
|
||||
unsigned int tcppayloadlen);
|
||||
/* Set/get the owner of the descriptor */
|
||||
void (*set_tx_owner)(struct dma_desc *p);
|
||||
int (*get_tx_owner)(struct dma_desc *p);
|
||||
/* Clean the tx descriptor as soon as the tx irq is received */
|
||||
void (*release_tx_desc)(struct dma_desc *p, int mode);
|
||||
/* Clear interrupt on tx frame completion. When this bit is
|
||||
* set an interrupt happens as soon as the frame is transmitted */
|
||||
void (*set_tx_ic)(struct dma_desc *p);
|
||||
/* Last tx segment reports the transmit status */
|
||||
int (*get_tx_ls)(struct dma_desc *p);
|
||||
/* Get the tag of the descriptor */
|
||||
u16 (*get_rx_vlan_tci)(struct dma_desc *p);
|
||||
/* Get the valid status of descriptor */
|
||||
bool (*get_rx_vlan_valid)(struct dma_desc *p);
|
||||
/* Return the transmit status looking at the TDES1 */
|
||||
int (*tx_status)(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p, void __iomem *ioaddr);
|
||||
/* Get the buffer size from the descriptor */
|
||||
int (*get_tx_len)(struct dma_desc *p);
|
||||
/* Handle extra events on specific interrupts hw dependent */
|
||||
void (*set_rx_owner)(struct dma_desc *p, int disable_rx_ic);
|
||||
/* Get the receive frame size */
|
||||
int (*get_rx_frame_len)(struct dma_desc *p, int rx_coe_type);
|
||||
/* Return the reception status looking at the RDES1 */
|
||||
int (*rx_status)(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p);
|
||||
void (*rx_extended_status)(struct stmmac_extra_stats *x,
|
||||
struct dma_extended_desc *p);
|
||||
/* Set tx timestamp enable bit */
|
||||
void (*enable_tx_timestamp) (struct dma_desc *p);
|
||||
/* get tx timestamp status */
|
||||
int (*get_tx_timestamp_status) (struct dma_desc *p);
|
||||
/* get timestamp value */
|
||||
void (*get_timestamp)(void *desc, u32 ats, u64 *ts);
|
||||
/* get rx timestamp status */
|
||||
int (*get_rx_timestamp_status)(void *desc, void *next_desc, u32 ats);
|
||||
/* Display ring */
|
||||
void (*display_ring)(void *head, unsigned int size, bool rx,
|
||||
dma_addr_t dma_rx_phy, unsigned int desc_size);
|
||||
/* set MSS via context descriptor */
|
||||
void (*set_mss)(struct dma_desc *p, unsigned int mss);
|
||||
/* set descriptor skbuff address */
|
||||
void (*set_addr)(struct dma_desc *p, dma_addr_t addr);
|
||||
/* clear descriptor */
|
||||
void (*clear)(struct dma_desc *p);
|
||||
/* RSS */
|
||||
int (*get_rx_hash)(struct dma_desc *p, u32 *hash,
|
||||
enum pkt_hash_types *type);
|
||||
void (*get_rx_header_len)(struct dma_desc *p, unsigned int *len);
|
||||
void (*set_sec_addr)(struct dma_desc *p, dma_addr_t addr, bool buf2_valid);
|
||||
void (*set_sarc)(struct dma_desc *p, u32 sarc_type);
|
||||
void (*set_vlan_tag)(struct dma_desc *p, u16 tag, u16 inner_tag,
|
||||
u32 inner_type);
|
||||
void (*set_vlan)(struct dma_desc *p, u32 type);
|
||||
void (*set_tbs)(struct dma_edesc *p, u32 sec, u32 nsec);
|
||||
};
|
||||
|
||||
#define stmmac_init_rx_desc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, init_rx_desc, __args)
|
||||
#define stmmac_init_tx_desc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, init_tx_desc, __args)
|
||||
#define stmmac_prepare_tx_desc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, prepare_tx_desc, __args)
|
||||
#define stmmac_prepare_tso_tx_desc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, prepare_tso_tx_desc, __args)
|
||||
#define stmmac_set_tx_owner(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_tx_owner, __args)
|
||||
#define stmmac_get_tx_owner(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_tx_owner, __args)
|
||||
#define stmmac_release_tx_desc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, release_tx_desc, __args)
|
||||
#define stmmac_set_tx_ic(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_tx_ic, __args)
|
||||
#define stmmac_get_tx_ls(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_tx_ls, __args)
|
||||
#define stmmac_get_rx_vlan_tci(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_rx_vlan_tci, __args)
|
||||
#define stmmac_get_rx_vlan_valid(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_rx_vlan_valid, __args)
|
||||
#define stmmac_tx_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, tx_status, __args)
|
||||
#define stmmac_get_tx_len(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_tx_len, __args)
|
||||
#define stmmac_set_rx_owner(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_rx_owner, __args)
|
||||
#define stmmac_get_rx_frame_len(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_rx_frame_len, __args)
|
||||
#define stmmac_rx_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, rx_status, __args)
|
||||
#define stmmac_rx_extended_status(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, rx_extended_status, __args)
|
||||
#define stmmac_enable_tx_timestamp(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, enable_tx_timestamp, __args)
|
||||
#define stmmac_get_tx_timestamp_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_tx_timestamp_status, __args)
|
||||
#define stmmac_get_timestamp(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, get_timestamp, __args)
|
||||
#define stmmac_get_rx_timestamp_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_rx_timestamp_status, __args)
|
||||
#define stmmac_display_ring(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, display_ring, __args)
|
||||
#define stmmac_set_mss(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_mss, __args)
|
||||
#define stmmac_set_desc_addr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_addr, __args)
|
||||
#define stmmac_clear_desc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, clear, __args)
|
||||
#define stmmac_get_rx_hash(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, desc, get_rx_hash, __args)
|
||||
#define stmmac_get_rx_header_len(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, get_rx_header_len, __args)
|
||||
#define stmmac_set_desc_sec_addr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_sec_addr, __args)
|
||||
#define stmmac_set_desc_sarc(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_sarc, __args)
|
||||
#define stmmac_set_desc_vlan_tag(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_vlan_tag, __args)
|
||||
#define stmmac_set_desc_vlan(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_vlan, __args)
|
||||
#define stmmac_set_desc_tbs(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, desc, set_tbs, __args)
|
||||
|
||||
struct stmmac_dma_cfg;
|
||||
struct dma_features;
|
||||
|
||||
/* Specific DMA helpers */
|
||||
struct stmmac_dma_ops {
|
||||
/* DMA core initialization */
|
||||
int (*reset)(void __iomem *ioaddr);
|
||||
void (*init)(void __iomem *ioaddr, struct stmmac_dma_cfg *dma_cfg);
|
||||
void (*init_chan)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg, u32 chan);
|
||||
void (*init_rx_chan)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t phy, u32 chan);
|
||||
void (*init_tx_chan)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_dma_cfg *dma_cfg,
|
||||
dma_addr_t phy, u32 chan);
|
||||
/* Configure the AXI Bus Mode Register */
|
||||
void (*axi)(void __iomem *ioaddr, struct stmmac_axi *axi);
|
||||
/* Dump DMA registers */
|
||||
void (*dump_regs)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 *reg_space);
|
||||
void (*dma_rx_mode)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int mode, u32 channel,
|
||||
int fifosz, u8 qmode);
|
||||
void (*dma_tx_mode)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int mode, u32 channel, int fifosz, u8 qmode);
|
||||
/* To track extra statistic (if supported) */
|
||||
void (*dma_diagnostic_fr)(struct stmmac_extra_stats *x,
|
||||
void __iomem *ioaddr);
|
||||
void (*enable_dma_transmission)(void __iomem *ioaddr, u32 chan);
|
||||
void (*enable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void (*disable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan, bool rx, bool tx);
|
||||
void (*start_tx)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void (*stop_tx)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void (*start_rx)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
void (*stop_rx)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 chan);
|
||||
int (*dma_interrupt)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 chan, u32 dir);
|
||||
/* If supported then get the optional core features */
|
||||
int (*get_hw_feature)(void __iomem *ioaddr,
|
||||
struct dma_features *dma_cap);
|
||||
/* Program the HW RX Watchdog */
|
||||
void (*rx_watchdog)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 riwt, u32 queue);
|
||||
void (*set_tx_ring_len)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 len, u32 chan);
|
||||
void (*set_rx_ring_len)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 len, u32 chan);
|
||||
void (*set_rx_tail_ptr)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 tail_ptr, u32 chan);
|
||||
void (*set_tx_tail_ptr)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 tail_ptr, u32 chan);
|
||||
void (*enable_tso)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan);
|
||||
void (*qmode)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
u32 channel, u8 qmode);
|
||||
void (*set_bfsize)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
int bfsize, u32 chan);
|
||||
void (*enable_sph)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan);
|
||||
int (*enable_tbs)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
bool en, u32 chan);
|
||||
};
|
||||
|
||||
#define stmmac_dma_init(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, init, __args)
|
||||
#define stmmac_init_chan(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, init_chan, __priv, __args)
|
||||
#define stmmac_init_rx_chan(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, init_rx_chan, __priv, __args)
|
||||
#define stmmac_init_tx_chan(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, init_tx_chan, __priv, __args)
|
||||
#define stmmac_axi(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, axi, __args)
|
||||
#define stmmac_dump_dma_regs(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, dump_regs, __priv, __args)
|
||||
#define stmmac_dma_rx_mode(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, dma_rx_mode, __priv, __args)
|
||||
#define stmmac_dma_tx_mode(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, dma_tx_mode, __priv, __args)
|
||||
#define stmmac_dma_diagnostic_fr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, dma_diagnostic_fr, __args)
|
||||
#define stmmac_enable_dma_transmission(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, enable_dma_transmission, __args)
|
||||
#define stmmac_enable_dma_irq(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, enable_dma_irq, __priv, __args)
|
||||
#define stmmac_disable_dma_irq(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, disable_dma_irq, __priv, __args)
|
||||
#define stmmac_start_tx(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, start_tx, __priv, __args)
|
||||
#define stmmac_stop_tx(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, stop_tx, __priv, __args)
|
||||
#define stmmac_start_rx(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, start_rx, __priv, __args)
|
||||
#define stmmac_stop_rx(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, stop_rx, __priv, __args)
|
||||
#define stmmac_dma_interrupt_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, dma, dma_interrupt, __priv, __args)
|
||||
#define stmmac_get_hw_feature(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, dma, get_hw_feature, __args)
|
||||
#define stmmac_rx_watchdog(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, rx_watchdog, __priv, __args)
|
||||
#define stmmac_set_tx_ring_len(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, set_tx_ring_len, __priv, __args)
|
||||
#define stmmac_set_rx_ring_len(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, set_rx_ring_len, __priv, __args)
|
||||
#define stmmac_set_rx_tail_ptr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, set_rx_tail_ptr, __priv, __args)
|
||||
#define stmmac_set_tx_tail_ptr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, set_tx_tail_ptr, __priv, __args)
|
||||
#define stmmac_enable_tso(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, enable_tso, __priv, __args)
|
||||
#define stmmac_dma_qmode(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, qmode, __priv, __args)
|
||||
#define stmmac_set_dma_bfsize(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, set_bfsize, __priv, __args)
|
||||
#define stmmac_enable_sph(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, dma, enable_sph, __priv, __args)
|
||||
#define stmmac_enable_tbs(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, dma, enable_tbs, __priv, __args)
|
||||
|
||||
struct mac_device_info;
|
||||
struct net_device;
|
||||
struct rgmii_adv;
|
||||
struct stmmac_tc_entry;
|
||||
struct stmmac_pps_cfg;
|
||||
struct stmmac_rss;
|
||||
struct stmmac_est;
|
||||
|
||||
/* Helpers to program the MAC core */
|
||||
struct stmmac_ops {
|
||||
/* MAC core initialization */
|
||||
void (*core_init)(struct mac_device_info *hw, struct net_device *dev);
|
||||
/* Update MAC capabilities */
|
||||
void (*update_caps)(struct stmmac_priv *priv);
|
||||
/* Enable the MAC RX/TX */
|
||||
void (*set_mac)(void __iomem *ioaddr, bool enable);
|
||||
/* Enable and verify that the IPC module is supported */
|
||||
int (*rx_ipc)(struct mac_device_info *hw);
|
||||
/* Enable RX Queues */
|
||||
void (*rx_queue_enable)(struct mac_device_info *hw, u8 mode, u32 queue);
|
||||
/* RX Queues Priority */
|
||||
void (*rx_queue_prio)(struct mac_device_info *hw, u32 prio, u32 queue);
|
||||
/* TX Queues Priority */
|
||||
void (*tx_queue_prio)(struct mac_device_info *hw, u32 prio, u32 queue);
|
||||
/* RX Queues Routing */
|
||||
void (*rx_queue_routing)(struct mac_device_info *hw, u8 packet,
|
||||
u32 queue);
|
||||
/* Program RX Algorithms */
|
||||
void (*prog_mtl_rx_algorithms)(struct mac_device_info *hw, u32 rx_alg);
|
||||
/* Program TX Algorithms */
|
||||
void (*prog_mtl_tx_algorithms)(struct mac_device_info *hw, u32 tx_alg);
|
||||
/* Set MTL TX queues weight */
|
||||
void (*set_mtl_tx_queue_weight)(struct stmmac_priv *priv,
|
||||
struct mac_device_info *hw,
|
||||
u32 weight, u32 queue);
|
||||
/* RX MTL queue to RX dma mapping */
|
||||
void (*map_mtl_to_dma)(struct mac_device_info *hw, u32 queue, u32 chan);
|
||||
/* Configure AV Algorithm */
|
||||
void (*config_cbs)(struct stmmac_priv *priv, struct mac_device_info *hw,
|
||||
u32 send_slope, u32 idle_slope, u32 high_credit,
|
||||
u32 low_credit, u32 queue);
|
||||
/* Dump MAC registers */
|
||||
void (*dump_regs)(struct mac_device_info *hw, u32 *reg_space);
|
||||
/* Handle extra events on specific interrupts hw dependent */
|
||||
int (*host_irq_status)(struct mac_device_info *hw,
|
||||
struct stmmac_extra_stats *x);
|
||||
/* Handle MTL interrupts */
|
||||
int (*host_mtl_irq_status)(struct stmmac_priv *priv,
|
||||
struct mac_device_info *hw, u32 chan);
|
||||
/* Multicast filter setting */
|
||||
void (*set_filter)(struct mac_device_info *hw, struct net_device *dev);
|
||||
/* Flow control setting */
|
||||
void (*flow_ctrl)(struct mac_device_info *hw, unsigned int duplex,
|
||||
unsigned int fc, unsigned int pause_time, u32 tx_cnt);
|
||||
/* Set power management mode (e.g. magic frame) */
|
||||
void (*pmt)(struct mac_device_info *hw, unsigned long mode);
|
||||
/* Set/Get Unicast MAC addresses */
|
||||
void (*set_umac_addr)(struct mac_device_info *hw,
|
||||
const unsigned char *addr,
|
||||
unsigned int reg_n);
|
||||
void (*get_umac_addr)(struct mac_device_info *hw, unsigned char *addr,
|
||||
unsigned int reg_n);
|
||||
void (*set_eee_mode)(struct mac_device_info *hw,
|
||||
bool en_tx_lpi_clockgating);
|
||||
void (*reset_eee_mode)(struct mac_device_info *hw);
|
||||
void (*set_eee_lpi_entry_timer)(struct mac_device_info *hw, int et);
|
||||
void (*set_eee_timer)(struct mac_device_info *hw, int ls, int tw);
|
||||
void (*set_eee_pls)(struct mac_device_info *hw, int link);
|
||||
void (*debug)(struct stmmac_priv *priv, void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x, u32 rx_queues,
|
||||
u32 tx_queues);
|
||||
/* PCS calls */
|
||||
void (*pcs_ctrl_ane)(void __iomem *ioaddr, bool ane, bool srgmi_ral,
|
||||
bool loopback);
|
||||
void (*pcs_get_adv_lp)(void __iomem *ioaddr, struct rgmii_adv *adv);
|
||||
/* Safety Features */
|
||||
int (*safety_feat_config)(void __iomem *ioaddr, unsigned int asp,
|
||||
struct stmmac_safety_feature_cfg *safety_cfg);
|
||||
int (*safety_feat_irq_status)(struct net_device *ndev,
|
||||
void __iomem *ioaddr, unsigned int asp,
|
||||
struct stmmac_safety_stats *stats);
|
||||
int (*safety_feat_dump)(struct stmmac_safety_stats *stats,
|
||||
int index, unsigned long *count, const char **desc);
|
||||
/* Flexible RX Parser */
|
||||
int (*rxp_config)(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
|
||||
unsigned int count);
|
||||
/* Flexible PPS */
|
||||
int (*flex_pps_config)(void __iomem *ioaddr, int index,
|
||||
struct stmmac_pps_cfg *cfg, bool enable,
|
||||
u32 sub_second_inc, u32 systime_flags);
|
||||
/* Loopback for selftests */
|
||||
void (*set_mac_loopback)(void __iomem *ioaddr, bool enable);
|
||||
/* RSS */
|
||||
int (*rss_configure)(struct mac_device_info *hw,
|
||||
struct stmmac_rss *cfg, u32 num_rxq);
|
||||
/* VLAN */
|
||||
void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash,
|
||||
u16 perfect_match, bool is_double);
|
||||
void (*enable_vlan)(struct mac_device_info *hw, u32 type);
|
||||
void (*rx_hw_vlan)(struct mac_device_info *hw, struct dma_desc *rx_desc,
|
||||
struct sk_buff *skb);
|
||||
void (*set_hw_vlan_mode)(struct mac_device_info *hw);
|
||||
int (*add_hw_vlan_rx_fltr)(struct net_device *dev,
|
||||
struct mac_device_info *hw,
|
||||
__be16 proto, u16 vid);
|
||||
int (*del_hw_vlan_rx_fltr)(struct net_device *dev,
|
||||
struct mac_device_info *hw,
|
||||
__be16 proto, u16 vid);
|
||||
void (*restore_hw_vlan_rx_fltr)(struct net_device *dev,
|
||||
struct mac_device_info *hw);
|
||||
/* TX Timestamp */
|
||||
int (*get_mac_tx_timestamp)(struct mac_device_info *hw, u64 *ts);
|
||||
/* Source Address Insertion / Replacement */
|
||||
void (*sarc_configure)(void __iomem *ioaddr, int val);
|
||||
/* Filtering */
|
||||
int (*config_l3_filter)(struct mac_device_info *hw, u32 filter_no,
|
||||
bool en, bool ipv6, bool sa, bool inv,
|
||||
u32 match);
|
||||
int (*config_l4_filter)(struct mac_device_info *hw, u32 filter_no,
|
||||
bool en, bool udp, bool sa, bool inv,
|
||||
u32 match);
|
||||
void (*set_arp_offload)(struct mac_device_info *hw, bool en, u32 addr);
|
||||
void (*fpe_configure)(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
||||
u32 num_txq, u32 num_rxq,
|
||||
bool tx_enable, bool pmac_enable);
|
||||
void (*fpe_send_mpacket)(void __iomem *ioaddr,
|
||||
struct stmmac_fpe_cfg *cfg,
|
||||
enum stmmac_mpacket_type type);
|
||||
int (*fpe_irq_status)(void __iomem *ioaddr, struct net_device *dev);
|
||||
int (*fpe_get_add_frag_size)(const void __iomem *ioaddr);
|
||||
void (*fpe_set_add_frag_size)(void __iomem *ioaddr, u32 add_frag_size);
|
||||
int (*fpe_map_preemption_class)(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack,
|
||||
u32 pclass);
|
||||
};
|
||||
|
||||
#define stmmac_core_init(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, core_init, __args)
|
||||
#define stmmac_mac_update_caps(__priv) \
|
||||
stmmac_do_void_callback(__priv, mac, update_caps, __priv)
|
||||
#define stmmac_mac_set(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_mac, __args)
|
||||
#define stmmac_rx_ipc(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, rx_ipc, __args)
|
||||
#define stmmac_rx_queue_enable(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, rx_queue_enable, __args)
|
||||
#define stmmac_rx_queue_prio(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, rx_queue_prio, __args)
|
||||
#define stmmac_tx_queue_prio(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, tx_queue_prio, __args)
|
||||
#define stmmac_rx_queue_routing(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, rx_queue_routing, __args)
|
||||
#define stmmac_prog_mtl_rx_algorithms(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, prog_mtl_rx_algorithms, __args)
|
||||
#define stmmac_prog_mtl_tx_algorithms(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, prog_mtl_tx_algorithms, __args)
|
||||
#define stmmac_set_mtl_tx_queue_weight(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_mtl_tx_queue_weight, __priv, __args)
|
||||
#define stmmac_map_mtl_to_dma(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, map_mtl_to_dma, __args)
|
||||
#define stmmac_config_cbs(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, config_cbs, __priv, __args)
|
||||
#define stmmac_dump_mac_regs(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, dump_regs, __args)
|
||||
#define stmmac_host_irq_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, host_irq_status, __args)
|
||||
#define stmmac_host_mtl_irq_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, host_mtl_irq_status, __priv, __args)
|
||||
#define stmmac_set_filter(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_filter, __args)
|
||||
#define stmmac_flow_ctrl(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, flow_ctrl, __args)
|
||||
#define stmmac_pmt(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, pmt, __args)
|
||||
#define stmmac_set_umac_addr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_umac_addr, __args)
|
||||
#define stmmac_get_umac_addr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, get_umac_addr, __args)
|
||||
#define stmmac_set_eee_mode(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_eee_mode, __args)
|
||||
#define stmmac_reset_eee_mode(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, reset_eee_mode, __args)
|
||||
#define stmmac_set_eee_lpi_timer(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_eee_lpi_entry_timer, __args)
|
||||
#define stmmac_set_eee_timer(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_eee_timer, __args)
|
||||
#define stmmac_set_eee_pls(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_eee_pls, __args)
|
||||
#define stmmac_mac_debug(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, debug, __priv, __args)
|
||||
#define stmmac_pcs_ctrl_ane(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, pcs_ctrl_ane, __args)
|
||||
#define stmmac_pcs_get_adv_lp(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, pcs_get_adv_lp, __args)
|
||||
#define stmmac_safety_feat_config(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, safety_feat_config, __args)
|
||||
#define stmmac_safety_feat_irq_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, safety_feat_irq_status, __args)
|
||||
#define stmmac_safety_feat_dump(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, safety_feat_dump, __args)
|
||||
#define stmmac_rxp_config(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, rxp_config, __args)
|
||||
#define stmmac_flex_pps_config(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, flex_pps_config, __args)
|
||||
#define stmmac_set_mac_loopback(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_mac_loopback, __args)
|
||||
#define stmmac_rss_configure(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, rss_configure, __args)
|
||||
#define stmmac_update_vlan_hash(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, update_vlan_hash, __args)
|
||||
#define stmmac_enable_vlan(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, enable_vlan, __args)
|
||||
#define stmmac_rx_hw_vlan(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, rx_hw_vlan, __args)
|
||||
#define stmmac_set_hw_vlan_mode(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_hw_vlan_mode, __args)
|
||||
#define stmmac_add_hw_vlan_rx_fltr(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, add_hw_vlan_rx_fltr, __args)
|
||||
#define stmmac_del_hw_vlan_rx_fltr(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, del_hw_vlan_rx_fltr, __args)
|
||||
#define stmmac_restore_hw_vlan_rx_fltr(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, restore_hw_vlan_rx_fltr, __args)
|
||||
#define stmmac_get_mac_tx_timestamp(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, get_mac_tx_timestamp, __args)
|
||||
#define stmmac_sarc_configure(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, sarc_configure, __args)
|
||||
#define stmmac_config_l3_filter(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, config_l3_filter, __args)
|
||||
#define stmmac_config_l4_filter(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, config_l4_filter, __args)
|
||||
#define stmmac_set_arp_offload(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_arp_offload, __args)
|
||||
#define stmmac_fpe_configure(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_configure, __args)
|
||||
#define stmmac_fpe_send_mpacket(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_send_mpacket, __args)
|
||||
#define stmmac_fpe_irq_status(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, fpe_irq_status, __args)
|
||||
#define stmmac_fpe_get_add_frag_size(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mac, fpe_get_add_frag_size, __args)
|
||||
#define stmmac_fpe_set_add_frag_size(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_set_add_frag_size, __args)
|
||||
#define stmmac_fpe_map_preemption_class(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_map_preemption_class, __args)
|
||||
|
||||
/* PTP and HW Timer helpers */
|
||||
struct stmmac_hwtimestamp {
|
||||
void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
|
||||
void (*config_sub_second_increment)(void __iomem *ioaddr, u32 ptp_clock,
|
||||
int gmac4, u32 *ssinc);
|
||||
int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
|
||||
int (*config_addend) (void __iomem *ioaddr, u32 addend);
|
||||
int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec,
|
||||
int add_sub, int gmac4);
|
||||
void (*get_systime) (void __iomem *ioaddr, u64 *systime);
|
||||
void (*get_ptptime)(void __iomem *ioaddr, u64 *ptp_time);
|
||||
void (*timestamp_interrupt)(struct stmmac_priv *priv);
|
||||
void (*hwtstamp_correct_latency)(struct stmmac_priv *priv);
|
||||
};
|
||||
|
||||
#define stmmac_config_hw_tstamping(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, config_hw_tstamping, __args)
|
||||
#define stmmac_config_sub_second_increment(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, config_sub_second_increment, __args)
|
||||
#define stmmac_init_systime(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, ptp, init_systime, __args)
|
||||
#define stmmac_config_addend(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, ptp, config_addend, __args)
|
||||
#define stmmac_adjust_systime(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, ptp, adjust_systime, __args)
|
||||
#define stmmac_get_systime(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, get_systime, __args)
|
||||
#define stmmac_get_ptptime(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, get_ptptime, __args)
|
||||
#define stmmac_timestamp_interrupt(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, timestamp_interrupt, __args)
|
||||
#define stmmac_hwtstamp_correct_latency(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, hwtstamp_correct_latency, __args)
|
||||
|
||||
struct stmmac_tx_queue;
|
||||
struct stmmac_rx_queue;
|
||||
|
||||
/* Helpers to manage the descriptors for chain and ring modes */
|
||||
struct stmmac_mode_ops {
|
||||
void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,
|
||||
unsigned int extend_desc);
|
||||
unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
|
||||
int (*jumbo_frm)(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
|
||||
int csum);
|
||||
int (*set_16kib_bfsize)(int mtu);
|
||||
void (*init_desc3)(struct dma_desc *p);
|
||||
void (*refill_desc3)(struct stmmac_rx_queue *rx_q, struct dma_desc *p);
|
||||
void (*clean_desc3)(struct stmmac_tx_queue *tx_q, struct dma_desc *p);
|
||||
};
|
||||
|
||||
#define stmmac_mode_init(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mode, init, __args)
|
||||
#define stmmac_is_jumbo_frm(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mode, is_jumbo_frm, __args)
|
||||
#define stmmac_jumbo_frm(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mode, jumbo_frm, __args)
|
||||
#define stmmac_set_16kib_bfsize(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, mode, set_16kib_bfsize, __args)
|
||||
#define stmmac_init_desc3(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mode, init_desc3, __args)
|
||||
#define stmmac_refill_desc3(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mode, refill_desc3, __args)
|
||||
#define stmmac_clean_desc3(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mode, clean_desc3, __args)
|
||||
|
||||
struct tc_cls_u32_offload;
|
||||
struct tc_cbs_qopt_offload;
|
||||
struct flow_cls_offload;
|
||||
struct tc_taprio_qopt_offload;
|
||||
struct tc_etf_qopt_offload;
|
||||
struct tc_query_caps_base;
|
||||
|
||||
struct stmmac_tc_ops {
|
||||
int (*init)(struct stmmac_priv *priv);
|
||||
int (*setup_cls_u32)(struct stmmac_priv *priv,
|
||||
struct tc_cls_u32_offload *cls);
|
||||
int (*setup_cbs)(struct stmmac_priv *priv,
|
||||
struct tc_cbs_qopt_offload *qopt);
|
||||
int (*setup_cls)(struct stmmac_priv *priv,
|
||||
struct flow_cls_offload *cls);
|
||||
int (*setup_taprio)(struct stmmac_priv *priv,
|
||||
struct tc_taprio_qopt_offload *qopt);
|
||||
int (*setup_etf)(struct stmmac_priv *priv,
|
||||
struct tc_etf_qopt_offload *qopt);
|
||||
int (*query_caps)(struct stmmac_priv *priv,
|
||||
struct tc_query_caps_base *base);
|
||||
int (*setup_mqprio)(struct stmmac_priv *priv,
|
||||
struct tc_mqprio_qopt_offload *qopt);
|
||||
};
|
||||
|
||||
#define stmmac_tc_init(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, init, __args)
|
||||
#define stmmac_tc_setup_cls_u32(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_cls_u32, __args)
|
||||
#define stmmac_tc_setup_cbs(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_cbs, __args)
|
||||
#define stmmac_tc_setup_cls(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_cls, __args)
|
||||
#define stmmac_tc_setup_taprio(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_taprio, __args)
|
||||
#define stmmac_tc_setup_etf(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_etf, __args)
|
||||
#define stmmac_tc_query_caps(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, query_caps, __args)
|
||||
#define stmmac_tc_setup_mqprio(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_mqprio, __args)
|
||||
|
||||
struct stmmac_counters;
|
||||
|
||||
struct stmmac_mmc_ops {
|
||||
void (*ctrl)(void __iomem *ioaddr, unsigned int mode);
|
||||
void (*intr_all_mask)(void __iomem *ioaddr);
|
||||
void (*read)(void __iomem *ioaddr, struct stmmac_counters *mmc);
|
||||
};
|
||||
|
||||
#define stmmac_mmc_ctrl(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mmc, ctrl, __args)
|
||||
#define stmmac_mmc_intr_all_mask(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mmc, intr_all_mask, __args)
|
||||
#define stmmac_mmc_read(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mmc, read, __args)
|
||||
|
||||
struct stmmac_est_ops {
|
||||
int (*configure)(struct stmmac_priv *priv, struct stmmac_est *cfg,
|
||||
unsigned int ptp_rate);
|
||||
void (*irq_status)(struct stmmac_priv *priv, struct net_device *dev,
|
||||
struct stmmac_extra_stats *x, u32 txqcnt);
|
||||
};
|
||||
|
||||
#define stmmac_est_configure(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, est, configure, __args)
|
||||
#define stmmac_est_irq_status(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, est, irq_status, __args)
|
||||
|
||||
struct stmmac_regs_off {
|
||||
u32 ptp_off;
|
||||
u32 mmc_off;
|
||||
u32 est_off;
|
||||
};
|
||||
|
||||
extern const struct stmmac_ops dwmac100_ops;
|
||||
extern const struct stmmac_dma_ops dwmac100_dma_ops;
|
||||
extern const struct stmmac_ops dwmac1000_ops;
|
||||
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
|
||||
extern const struct stmmac_ops dwmac4_ops;
|
||||
extern const struct stmmac_dma_ops dwmac4_dma_ops;
|
||||
extern const struct stmmac_ops dwmac410_ops;
|
||||
extern const struct stmmac_dma_ops dwmac410_dma_ops;
|
||||
extern const struct stmmac_ops dwmac510_ops;
|
||||
extern const struct stmmac_tc_ops dwmac4_tc_ops;
|
||||
extern const struct stmmac_tc_ops dwmac510_tc_ops;
|
||||
extern const struct stmmac_tc_ops dwxgmac_tc_ops;
|
||||
extern const struct stmmac_ops dwxgmac210_ops;
|
||||
extern const struct stmmac_ops dwxlgmac2_ops;
|
||||
extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
|
||||
extern const struct stmmac_desc_ops dwxgmac210_desc_ops;
|
||||
extern const struct stmmac_mmc_ops dwmac_mmc_ops;
|
||||
extern const struct stmmac_mmc_ops dwxgmac_mmc_ops;
|
||||
extern const struct stmmac_est_ops dwmac510_est_ops;
|
||||
|
||||
#define GMAC_VERSION 0x00000020 /* GMAC CORE Version */
|
||||
#define GMAC4_VERSION 0x00000110 /* GMAC4+ CORE Version */
|
||||
|
||||
int stmmac_reset(struct stmmac_priv *priv, void __iomem *ioaddr);
|
||||
int stmmac_hwif_init(struct stmmac_priv *priv);
|
||||
|
||||
#endif /* __STMMAC_HWIF_H__ */
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
MMC Header file
|
||||
|
||||
Copyright (C) 2011 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __MMC_H__
|
||||
#define __MMC_H__
|
||||
|
||||
/* MMC control register */
|
||||
/* When set, all counter are reset */
|
||||
#define MMC_CNTRL_COUNTER_RESET 0x1
|
||||
/* When set, do not roll over zero after reaching the max value*/
|
||||
#define MMC_CNTRL_COUNTER_STOP_ROLLOVER 0x2
|
||||
#define MMC_CNTRL_RESET_ON_READ 0x4 /* Reset after reading */
|
||||
#define MMC_CNTRL_COUNTER_FREEZER 0x8 /* Freeze counter values to the
|
||||
* current value.*/
|
||||
#define MMC_CNTRL_PRESET 0x10
|
||||
#define MMC_CNTRL_FULL_HALF_PRESET 0x20
|
||||
|
||||
#define MMC_GMAC4_OFFSET 0x700
|
||||
#define MMC_GMAC3_X_OFFSET 0x100
|
||||
#define MMC_XGMAC_OFFSET 0x800
|
||||
|
||||
struct stmmac_counters {
|
||||
unsigned int mmc_tx_octetcount_gb;
|
||||
unsigned int mmc_tx_framecount_gb;
|
||||
unsigned int mmc_tx_broadcastframe_g;
|
||||
unsigned int mmc_tx_multicastframe_g;
|
||||
unsigned int mmc_tx_64_octets_gb;
|
||||
unsigned int mmc_tx_65_to_127_octets_gb;
|
||||
unsigned int mmc_tx_128_to_255_octets_gb;
|
||||
unsigned int mmc_tx_256_to_511_octets_gb;
|
||||
unsigned int mmc_tx_512_to_1023_octets_gb;
|
||||
unsigned int mmc_tx_1024_to_max_octets_gb;
|
||||
unsigned int mmc_tx_unicast_gb;
|
||||
unsigned int mmc_tx_multicast_gb;
|
||||
unsigned int mmc_tx_broadcast_gb;
|
||||
unsigned int mmc_tx_underflow_error;
|
||||
unsigned int mmc_tx_singlecol_g;
|
||||
unsigned int mmc_tx_multicol_g;
|
||||
unsigned int mmc_tx_deferred;
|
||||
unsigned int mmc_tx_latecol;
|
||||
unsigned int mmc_tx_exesscol;
|
||||
unsigned int mmc_tx_carrier_error;
|
||||
unsigned int mmc_tx_octetcount_g;
|
||||
unsigned int mmc_tx_framecount_g;
|
||||
unsigned int mmc_tx_excessdef;
|
||||
unsigned int mmc_tx_pause_frame;
|
||||
unsigned int mmc_tx_vlan_frame_g;
|
||||
unsigned int mmc_tx_oversize_g;
|
||||
unsigned int mmc_tx_lpi_usec;
|
||||
unsigned int mmc_tx_lpi_tran;
|
||||
|
||||
/* MMC RX counter registers */
|
||||
unsigned int mmc_rx_framecount_gb;
|
||||
unsigned int mmc_rx_octetcount_gb;
|
||||
unsigned int mmc_rx_octetcount_g;
|
||||
unsigned int mmc_rx_broadcastframe_g;
|
||||
unsigned int mmc_rx_multicastframe_g;
|
||||
unsigned int mmc_rx_crc_error;
|
||||
unsigned int mmc_rx_align_error;
|
||||
unsigned int mmc_rx_run_error;
|
||||
unsigned int mmc_rx_jabber_error;
|
||||
unsigned int mmc_rx_undersize_g;
|
||||
unsigned int mmc_rx_oversize_g;
|
||||
unsigned int mmc_rx_64_octets_gb;
|
||||
unsigned int mmc_rx_65_to_127_octets_gb;
|
||||
unsigned int mmc_rx_128_to_255_octets_gb;
|
||||
unsigned int mmc_rx_256_to_511_octets_gb;
|
||||
unsigned int mmc_rx_512_to_1023_octets_gb;
|
||||
unsigned int mmc_rx_1024_to_max_octets_gb;
|
||||
unsigned int mmc_rx_unicast_g;
|
||||
unsigned int mmc_rx_length_error;
|
||||
unsigned int mmc_rx_autofrangetype;
|
||||
unsigned int mmc_rx_pause_frames;
|
||||
unsigned int mmc_rx_fifo_overflow;
|
||||
unsigned int mmc_rx_vlan_frames_gb;
|
||||
unsigned int mmc_rx_watchdog_error;
|
||||
unsigned int mmc_rx_error;
|
||||
unsigned int mmc_rx_lpi_usec;
|
||||
unsigned int mmc_rx_lpi_tran;
|
||||
unsigned int mmc_rx_discard_frames_gb;
|
||||
unsigned int mmc_rx_discard_octets_gb;
|
||||
unsigned int mmc_rx_align_err_frames;
|
||||
|
||||
/* IPv4 */
|
||||
unsigned int mmc_rx_ipv4_gd;
|
||||
unsigned int mmc_rx_ipv4_hderr;
|
||||
unsigned int mmc_rx_ipv4_nopay;
|
||||
unsigned int mmc_rx_ipv4_frag;
|
||||
unsigned int mmc_rx_ipv4_udsbl;
|
||||
|
||||
unsigned int mmc_rx_ipv4_gd_octets;
|
||||
unsigned int mmc_rx_ipv4_hderr_octets;
|
||||
unsigned int mmc_rx_ipv4_nopay_octets;
|
||||
unsigned int mmc_rx_ipv4_frag_octets;
|
||||
unsigned int mmc_rx_ipv4_udsbl_octets;
|
||||
|
||||
/* IPV6 */
|
||||
unsigned int mmc_rx_ipv6_gd_octets;
|
||||
unsigned int mmc_rx_ipv6_hderr_octets;
|
||||
unsigned int mmc_rx_ipv6_nopay_octets;
|
||||
|
||||
unsigned int mmc_rx_ipv6_gd;
|
||||
unsigned int mmc_rx_ipv6_hderr;
|
||||
unsigned int mmc_rx_ipv6_nopay;
|
||||
|
||||
/* Protocols */
|
||||
unsigned int mmc_rx_udp_gd;
|
||||
unsigned int mmc_rx_udp_err;
|
||||
unsigned int mmc_rx_tcp_gd;
|
||||
unsigned int mmc_rx_tcp_err;
|
||||
unsigned int mmc_rx_icmp_gd;
|
||||
unsigned int mmc_rx_icmp_err;
|
||||
|
||||
unsigned int mmc_rx_udp_gd_octets;
|
||||
unsigned int mmc_rx_udp_err_octets;
|
||||
unsigned int mmc_rx_tcp_gd_octets;
|
||||
unsigned int mmc_rx_tcp_err_octets;
|
||||
unsigned int mmc_rx_icmp_gd_octets;
|
||||
unsigned int mmc_rx_icmp_err_octets;
|
||||
|
||||
/* Stream-Gate Filter */
|
||||
unsigned int mmc_sgf_pass_fragment_cntr;
|
||||
unsigned int mmc_sgf_fail_fragment_cntr;
|
||||
|
||||
/* FPE */
|
||||
unsigned int mmc_tx_fpe_fragment_cntr;
|
||||
unsigned int mmc_tx_hold_req_cntr;
|
||||
unsigned int mmc_tx_gate_overrun_cntr;
|
||||
unsigned int mmc_rx_packet_assembly_err_cntr;
|
||||
unsigned int mmc_rx_packet_smd_err_cntr;
|
||||
unsigned int mmc_rx_packet_assembly_ok_cntr;
|
||||
unsigned int mmc_rx_fpe_fragment_cntr;
|
||||
};
|
||||
|
||||
#endif /* __MMC_H__ */
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
MMC Header file
|
||||
|
||||
Copyright (C) 2011 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __MMC_H__
|
||||
#define __MMC_H__
|
||||
|
||||
/* MMC control register */
|
||||
/* When set, all counter are reset */
|
||||
#define MMC_CNTRL_COUNTER_RESET 0x1
|
||||
/* When set, do not roll over zero after reaching the max value*/
|
||||
#define MMC_CNTRL_COUNTER_STOP_ROLLOVER 0x2
|
||||
#define MMC_CNTRL_RESET_ON_READ 0x4 /* Reset after reading */
|
||||
#define MMC_CNTRL_COUNTER_FREEZER 0x8 /* Freeze counter values to the
|
||||
* current value.*/
|
||||
#define MMC_CNTRL_PRESET 0x10
|
||||
#define MMC_CNTRL_FULL_HALF_PRESET 0x20
|
||||
|
||||
#define MMC_GMAC4_OFFSET 0x700
|
||||
#define MMC_GMAC3_X_OFFSET 0x100
|
||||
#define MMC_XGMAC_OFFSET 0x800
|
||||
|
||||
struct stmmac_counters {
|
||||
unsigned int mmc_tx_octetcount_gb;
|
||||
unsigned int mmc_tx_framecount_gb;
|
||||
unsigned int mmc_tx_broadcastframe_g;
|
||||
unsigned int mmc_tx_multicastframe_g;
|
||||
unsigned int mmc_tx_64_octets_gb;
|
||||
unsigned int mmc_tx_65_to_127_octets_gb;
|
||||
unsigned int mmc_tx_128_to_255_octets_gb;
|
||||
unsigned int mmc_tx_256_to_511_octets_gb;
|
||||
unsigned int mmc_tx_512_to_1023_octets_gb;
|
||||
unsigned int mmc_tx_1024_to_max_octets_gb;
|
||||
unsigned int mmc_tx_unicast_gb;
|
||||
unsigned int mmc_tx_multicast_gb;
|
||||
unsigned int mmc_tx_broadcast_gb;
|
||||
unsigned int mmc_tx_underflow_error;
|
||||
unsigned int mmc_tx_singlecol_g;
|
||||
unsigned int mmc_tx_multicol_g;
|
||||
unsigned int mmc_tx_deferred;
|
||||
unsigned int mmc_tx_latecol;
|
||||
unsigned int mmc_tx_exesscol;
|
||||
unsigned int mmc_tx_carrier_error;
|
||||
unsigned int mmc_tx_octetcount_g;
|
||||
unsigned int mmc_tx_framecount_g;
|
||||
unsigned int mmc_tx_excessdef;
|
||||
unsigned int mmc_tx_pause_frame;
|
||||
unsigned int mmc_tx_vlan_frame_g;
|
||||
unsigned int mmc_tx_oversize_g;
|
||||
unsigned int mmc_tx_lpi_usec;
|
||||
unsigned int mmc_tx_lpi_tran;
|
||||
|
||||
/* MMC RX counter registers */
|
||||
unsigned int mmc_rx_framecount_gb;
|
||||
unsigned int mmc_rx_octetcount_gb;
|
||||
unsigned int mmc_rx_octetcount_g;
|
||||
unsigned int mmc_rx_broadcastframe_g;
|
||||
unsigned int mmc_rx_multicastframe_g;
|
||||
unsigned int mmc_rx_crc_error;
|
||||
unsigned int mmc_rx_align_error;
|
||||
unsigned int mmc_rx_run_error;
|
||||
unsigned int mmc_rx_jabber_error;
|
||||
unsigned int mmc_rx_undersize_g;
|
||||
unsigned int mmc_rx_oversize_g;
|
||||
unsigned int mmc_rx_64_octets_gb;
|
||||
unsigned int mmc_rx_65_to_127_octets_gb;
|
||||
unsigned int mmc_rx_128_to_255_octets_gb;
|
||||
unsigned int mmc_rx_256_to_511_octets_gb;
|
||||
unsigned int mmc_rx_512_to_1023_octets_gb;
|
||||
unsigned int mmc_rx_1024_to_max_octets_gb;
|
||||
unsigned int mmc_rx_unicast_g;
|
||||
unsigned int mmc_rx_length_error;
|
||||
unsigned int mmc_rx_autofrangetype;
|
||||
unsigned int mmc_rx_pause_frames;
|
||||
unsigned int mmc_rx_fifo_overflow;
|
||||
unsigned int mmc_rx_vlan_frames_gb;
|
||||
unsigned int mmc_rx_watchdog_error;
|
||||
unsigned int mmc_rx_error;
|
||||
unsigned int mmc_rx_lpi_usec;
|
||||
unsigned int mmc_rx_lpi_tran;
|
||||
unsigned int mmc_rx_discard_frames_gb;
|
||||
unsigned int mmc_rx_discard_octets_gb;
|
||||
unsigned int mmc_rx_align_err_frames;
|
||||
|
||||
/* IPv4 */
|
||||
unsigned int mmc_rx_ipv4_gd;
|
||||
unsigned int mmc_rx_ipv4_hderr;
|
||||
unsigned int mmc_rx_ipv4_nopay;
|
||||
unsigned int mmc_rx_ipv4_frag;
|
||||
unsigned int mmc_rx_ipv4_udsbl;
|
||||
|
||||
unsigned int mmc_rx_ipv4_gd_octets;
|
||||
unsigned int mmc_rx_ipv4_hderr_octets;
|
||||
unsigned int mmc_rx_ipv4_nopay_octets;
|
||||
unsigned int mmc_rx_ipv4_frag_octets;
|
||||
unsigned int mmc_rx_ipv4_udsbl_octets;
|
||||
|
||||
/* IPV6 */
|
||||
unsigned int mmc_rx_ipv6_gd_octets;
|
||||
unsigned int mmc_rx_ipv6_hderr_octets;
|
||||
unsigned int mmc_rx_ipv6_nopay_octets;
|
||||
|
||||
unsigned int mmc_rx_ipv6_gd;
|
||||
unsigned int mmc_rx_ipv6_hderr;
|
||||
unsigned int mmc_rx_ipv6_nopay;
|
||||
|
||||
/* Protocols */
|
||||
unsigned int mmc_rx_udp_gd;
|
||||
unsigned int mmc_rx_udp_err;
|
||||
unsigned int mmc_rx_tcp_gd;
|
||||
unsigned int mmc_rx_tcp_err;
|
||||
unsigned int mmc_rx_icmp_gd;
|
||||
unsigned int mmc_rx_icmp_err;
|
||||
|
||||
unsigned int mmc_rx_udp_gd_octets;
|
||||
unsigned int mmc_rx_udp_err_octets;
|
||||
unsigned int mmc_rx_tcp_gd_octets;
|
||||
unsigned int mmc_rx_tcp_err_octets;
|
||||
unsigned int mmc_rx_icmp_gd_octets;
|
||||
unsigned int mmc_rx_icmp_err_octets;
|
||||
|
||||
/* Stream-Gate Filter */
|
||||
unsigned int mmc_sgf_pass_fragment_cntr;
|
||||
unsigned int mmc_sgf_fail_fragment_cntr;
|
||||
|
||||
/* FPE */
|
||||
unsigned int mmc_tx_fpe_fragment_cntr;
|
||||
unsigned int mmc_tx_hold_req_cntr;
|
||||
unsigned int mmc_tx_gate_overrun_cntr;
|
||||
unsigned int mmc_rx_packet_assembly_err_cntr;
|
||||
unsigned int mmc_rx_packet_smd_err_cntr;
|
||||
unsigned int mmc_rx_packet_assembly_ok_cntr;
|
||||
unsigned int mmc_rx_fpe_fragment_cntr;
|
||||
};
|
||||
|
||||
#endif /* __MMC_H__ */
|
||||
|
|
@ -0,0 +1,606 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
DWMAC Management Counters
|
||||
|
||||
Copyright (C) 2011 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include "hwif-6.12-ethercat.h"
|
||||
#include "mmc-6.12-ethercat.h"
|
||||
|
||||
/* MAC Management Counters register offset */
|
||||
|
||||
#define MMC_CNTRL 0x00 /* MMC Control */
|
||||
#define MMC_RX_INTR 0x04 /* MMC RX Interrupt */
|
||||
#define MMC_TX_INTR 0x08 /* MMC TX Interrupt */
|
||||
#define MMC_RX_INTR_MASK 0x0c /* MMC Interrupt Mask */
|
||||
#define MMC_TX_INTR_MASK 0x10 /* MMC Interrupt Mask */
|
||||
#define MMC_DEFAULT_MASK 0xffffffff
|
||||
|
||||
/* MMC TX counter registers */
|
||||
|
||||
/* Note:
|
||||
* _GB register stands for good and bad frames
|
||||
* _G is for good only.
|
||||
*/
|
||||
#define MMC_TX_OCTETCOUNT_GB 0x14
|
||||
#define MMC_TX_FRAMECOUNT_GB 0x18
|
||||
#define MMC_TX_BROADCASTFRAME_G 0x1c
|
||||
#define MMC_TX_MULTICASTFRAME_G 0x20
|
||||
#define MMC_TX_64_OCTETS_GB 0x24
|
||||
#define MMC_TX_65_TO_127_OCTETS_GB 0x28
|
||||
#define MMC_TX_128_TO_255_OCTETS_GB 0x2c
|
||||
#define MMC_TX_256_TO_511_OCTETS_GB 0x30
|
||||
#define MMC_TX_512_TO_1023_OCTETS_GB 0x34
|
||||
#define MMC_TX_1024_TO_MAX_OCTETS_GB 0x38
|
||||
#define MMC_TX_UNICAST_GB 0x3c
|
||||
#define MMC_TX_MULTICAST_GB 0x40
|
||||
#define MMC_TX_BROADCAST_GB 0x44
|
||||
#define MMC_TX_UNDERFLOW_ERROR 0x48
|
||||
#define MMC_TX_SINGLECOL_G 0x4c
|
||||
#define MMC_TX_MULTICOL_G 0x50
|
||||
#define MMC_TX_DEFERRED 0x54
|
||||
#define MMC_TX_LATECOL 0x58
|
||||
#define MMC_TX_EXESSCOL 0x5c
|
||||
#define MMC_TX_CARRIER_ERROR 0x60
|
||||
#define MMC_TX_OCTETCOUNT_G 0x64
|
||||
#define MMC_TX_FRAMECOUNT_G 0x68
|
||||
#define MMC_TX_EXCESSDEF 0x6c
|
||||
#define MMC_TX_PAUSE_FRAME 0x70
|
||||
#define MMC_TX_VLAN_FRAME_G 0x74
|
||||
#define MMC_TX_OVERSIZE_G 0x78
|
||||
|
||||
/* MMC RX counter registers */
|
||||
#define MMC_RX_FRAMECOUNT_GB 0x80
|
||||
#define MMC_RX_OCTETCOUNT_GB 0x84
|
||||
#define MMC_RX_OCTETCOUNT_G 0x88
|
||||
#define MMC_RX_BROADCASTFRAME_G 0x8c
|
||||
#define MMC_RX_MULTICASTFRAME_G 0x90
|
||||
#define MMC_RX_CRC_ERROR 0x94
|
||||
#define MMC_RX_ALIGN_ERROR 0x98
|
||||
#define MMC_RX_RUN_ERROR 0x9C
|
||||
#define MMC_RX_JABBER_ERROR 0xA0
|
||||
#define MMC_RX_UNDERSIZE_G 0xA4
|
||||
#define MMC_RX_OVERSIZE_G 0xA8
|
||||
#define MMC_RX_64_OCTETS_GB 0xAC
|
||||
#define MMC_RX_65_TO_127_OCTETS_GB 0xb0
|
||||
#define MMC_RX_128_TO_255_OCTETS_GB 0xb4
|
||||
#define MMC_RX_256_TO_511_OCTETS_GB 0xb8
|
||||
#define MMC_RX_512_TO_1023_OCTETS_GB 0xbc
|
||||
#define MMC_RX_1024_TO_MAX_OCTETS_GB 0xc0
|
||||
#define MMC_RX_UNICAST_G 0xc4
|
||||
#define MMC_RX_LENGTH_ERROR 0xc8
|
||||
#define MMC_RX_AUTOFRANGETYPE 0xcc
|
||||
#define MMC_RX_PAUSE_FRAMES 0xd0
|
||||
#define MMC_RX_FIFO_OVERFLOW 0xd4
|
||||
#define MMC_RX_VLAN_FRAMES_GB 0xd8
|
||||
#define MMC_RX_WATCHDOG_ERROR 0xdc
|
||||
#define MMC_RX_ERROR 0xe0
|
||||
|
||||
#define MMC_TX_LPI_USEC 0xec
|
||||
#define MMC_TX_LPI_TRAN 0xf0
|
||||
#define MMC_RX_LPI_USEC 0xf4
|
||||
#define MMC_RX_LPI_TRAN 0xf8
|
||||
|
||||
/* IPC*/
|
||||
#define MMC_RX_IPC_INTR_MASK 0x100
|
||||
#define MMC_RX_IPC_INTR 0x108
|
||||
/* IPv4*/
|
||||
#define MMC_RX_IPV4_GD 0x110
|
||||
#define MMC_RX_IPV4_HDERR 0x114
|
||||
#define MMC_RX_IPV4_NOPAY 0x118
|
||||
#define MMC_RX_IPV4_FRAG 0x11C
|
||||
#define MMC_RX_IPV4_UDSBL 0x120
|
||||
|
||||
#define MMC_RX_IPV4_GD_OCTETS 0x150
|
||||
#define MMC_RX_IPV4_HDERR_OCTETS 0x154
|
||||
#define MMC_RX_IPV4_NOPAY_OCTETS 0x158
|
||||
#define MMC_RX_IPV4_FRAG_OCTETS 0x15c
|
||||
#define MMC_RX_IPV4_UDSBL_OCTETS 0x160
|
||||
|
||||
/* IPV6*/
|
||||
#define MMC_RX_IPV6_GD_OCTETS 0x164
|
||||
#define MMC_RX_IPV6_HDERR_OCTETS 0x168
|
||||
#define MMC_RX_IPV6_NOPAY_OCTETS 0x16c
|
||||
|
||||
#define MMC_RX_IPV6_GD 0x124
|
||||
#define MMC_RX_IPV6_HDERR 0x128
|
||||
#define MMC_RX_IPV6_NOPAY 0x12c
|
||||
|
||||
/* Protocols*/
|
||||
#define MMC_RX_UDP_GD 0x130
|
||||
#define MMC_RX_UDP_ERR 0x134
|
||||
#define MMC_RX_TCP_GD 0x138
|
||||
#define MMC_RX_TCP_ERR 0x13c
|
||||
#define MMC_RX_ICMP_GD 0x140
|
||||
#define MMC_RX_ICMP_ERR 0x144
|
||||
|
||||
#define MMC_RX_UDP_GD_OCTETS 0x170
|
||||
#define MMC_RX_UDP_ERR_OCTETS 0x174
|
||||
#define MMC_RX_TCP_GD_OCTETS 0x178
|
||||
#define MMC_RX_TCP_ERR_OCTETS 0x17c
|
||||
#define MMC_RX_ICMP_GD_OCTETS 0x180
|
||||
#define MMC_RX_ICMP_ERR_OCTETS 0x184
|
||||
|
||||
#define MMC_TX_FPE_FRAG 0x1a8
|
||||
#define MMC_TX_HOLD_REQ 0x1ac
|
||||
#define MMC_RX_PKT_ASSEMBLY_ERR 0x1c8
|
||||
#define MMC_RX_PKT_SMD_ERR 0x1cc
|
||||
#define MMC_RX_PKT_ASSEMBLY_OK 0x1d0
|
||||
#define MMC_RX_FPE_FRAG 0x1d4
|
||||
|
||||
/* XGMAC MMC Registers */
|
||||
#define MMC_XGMAC_TX_OCTET_GB 0x14
|
||||
#define MMC_XGMAC_TX_PKT_GB 0x1c
|
||||
#define MMC_XGMAC_TX_BROAD_PKT_G 0x24
|
||||
#define MMC_XGMAC_TX_MULTI_PKT_G 0x2c
|
||||
#define MMC_XGMAC_TX_64OCT_GB 0x34
|
||||
#define MMC_XGMAC_TX_65OCT_GB 0x3c
|
||||
#define MMC_XGMAC_TX_128OCT_GB 0x44
|
||||
#define MMC_XGMAC_TX_256OCT_GB 0x4c
|
||||
#define MMC_XGMAC_TX_512OCT_GB 0x54
|
||||
#define MMC_XGMAC_TX_1024OCT_GB 0x5c
|
||||
#define MMC_XGMAC_TX_UNI_PKT_GB 0x64
|
||||
#define MMC_XGMAC_TX_MULTI_PKT_GB 0x6c
|
||||
#define MMC_XGMAC_TX_BROAD_PKT_GB 0x74
|
||||
#define MMC_XGMAC_TX_UNDER 0x7c
|
||||
#define MMC_XGMAC_TX_OCTET_G 0x84
|
||||
#define MMC_XGMAC_TX_PKT_G 0x8c
|
||||
#define MMC_XGMAC_TX_PAUSE 0x94
|
||||
#define MMC_XGMAC_TX_VLAN_PKT_G 0x9c
|
||||
#define MMC_XGMAC_TX_LPI_USEC 0xa4
|
||||
#define MMC_XGMAC_TX_LPI_TRAN 0xa8
|
||||
|
||||
#define MMC_XGMAC_RX_PKT_GB 0x100
|
||||
#define MMC_XGMAC_RX_OCTET_GB 0x108
|
||||
#define MMC_XGMAC_RX_OCTET_G 0x110
|
||||
#define MMC_XGMAC_RX_BROAD_PKT_G 0x118
|
||||
#define MMC_XGMAC_RX_MULTI_PKT_G 0x120
|
||||
#define MMC_XGMAC_RX_CRC_ERR 0x128
|
||||
#define MMC_XGMAC_RX_RUNT_ERR 0x130
|
||||
#define MMC_XGMAC_RX_JABBER_ERR 0x134
|
||||
#define MMC_XGMAC_RX_UNDER 0x138
|
||||
#define MMC_XGMAC_RX_OVER 0x13c
|
||||
#define MMC_XGMAC_RX_64OCT_GB 0x140
|
||||
#define MMC_XGMAC_RX_65OCT_GB 0x148
|
||||
#define MMC_XGMAC_RX_128OCT_GB 0x150
|
||||
#define MMC_XGMAC_RX_256OCT_GB 0x158
|
||||
#define MMC_XGMAC_RX_512OCT_GB 0x160
|
||||
#define MMC_XGMAC_RX_1024OCT_GB 0x168
|
||||
#define MMC_XGMAC_RX_UNI_PKT_G 0x170
|
||||
#define MMC_XGMAC_RX_LENGTH_ERR 0x178
|
||||
#define MMC_XGMAC_RX_RANGE 0x180
|
||||
#define MMC_XGMAC_RX_PAUSE 0x188
|
||||
#define MMC_XGMAC_RX_FIFOOVER_PKT 0x190
|
||||
#define MMC_XGMAC_RX_VLAN_PKT_GB 0x198
|
||||
#define MMC_XGMAC_RX_WATCHDOG_ERR 0x1a0
|
||||
#define MMC_XGMAC_RX_LPI_USEC 0x1a4
|
||||
#define MMC_XGMAC_RX_LPI_TRAN 0x1a8
|
||||
#define MMC_XGMAC_RX_DISCARD_PKT_GB 0x1ac
|
||||
#define MMC_XGMAC_RX_DISCARD_OCT_GB 0x1b4
|
||||
#define MMC_XGMAC_RX_ALIGN_ERR_PKT 0x1bc
|
||||
|
||||
#define MMC_XGMAC_SGF_PASS_PKT 0x1f0
|
||||
#define MMC_XGMAC_SGF_FAIL_PKT 0x1f4
|
||||
#define MMC_XGMAC_TX_FPE_INTR_MASK 0x204
|
||||
#define MMC_XGMAC_TX_FPE_FRAG 0x208
|
||||
#define MMC_XGMAC_TX_HOLD_REQ 0x20c
|
||||
#define MMC_XGMAC_TX_GATE_OVERRUN 0x210
|
||||
#define MMC_XGMAC_RX_FPE_INTR_MASK 0x224
|
||||
#define MMC_XGMAC_RX_PKT_ASSEMBLY_ERR 0x228
|
||||
#define MMC_XGMAC_RX_PKT_SMD_ERR 0x22c
|
||||
#define MMC_XGMAC_RX_PKT_ASSEMBLY_OK 0x230
|
||||
#define MMC_XGMAC_RX_FPE_FRAG 0x234
|
||||
#define MMC_XGMAC_RX_IPC_INTR_MASK 0x25c
|
||||
|
||||
#define MMC_XGMAC_RX_IPV4_GD 0x264
|
||||
#define MMC_XGMAC_RX_IPV4_HDERR 0x26c
|
||||
#define MMC_XGMAC_RX_IPV4_NOPAY 0x274
|
||||
#define MMC_XGMAC_RX_IPV4_FRAG 0x27c
|
||||
#define MMC_XGMAC_RX_IPV4_UDSBL 0x284
|
||||
|
||||
#define MMC_XGMAC_RX_IPV6_GD 0x28c
|
||||
#define MMC_XGMAC_RX_IPV6_HDERR 0x294
|
||||
#define MMC_XGMAC_RX_IPV6_NOPAY 0x29c
|
||||
|
||||
#define MMC_XGMAC_RX_UDP_GD 0x2a4
|
||||
#define MMC_XGMAC_RX_UDP_ERR 0x2ac
|
||||
#define MMC_XGMAC_RX_TCP_GD 0x2b4
|
||||
#define MMC_XGMAC_RX_TCP_ERR 0x2bc
|
||||
#define MMC_XGMAC_RX_ICMP_GD 0x2c4
|
||||
#define MMC_XGMAC_RX_ICMP_ERR 0x2cc
|
||||
|
||||
#define MMC_XGMAC_RX_IPV4_GD_OCTETS 0x2d4
|
||||
#define MMC_XGMAC_RX_IPV4_HDERR_OCTETS 0x2dc
|
||||
#define MMC_XGMAC_RX_IPV4_NOPAY_OCTETS 0x2e4
|
||||
#define MMC_XGMAC_RX_IPV4_FRAG_OCTETS 0x2ec
|
||||
#define MMC_XGMAC_RX_IPV4_UDSBL_OCTETS 0x2f4
|
||||
|
||||
#define MMC_XGMAC_RX_IPV6_GD_OCTETS 0x2fc
|
||||
#define MMC_XGMAC_RX_IPV6_HDERR_OCTETS 0x304
|
||||
#define MMC_XGMAC_RX_IPV6_NOPAY_OCTETS 0x30c
|
||||
|
||||
#define MMC_XGMAC_RX_UDP_GD_OCTETS 0x314
|
||||
#define MMC_XGMAC_RX_UDP_ERR_OCTETS 0x31c
|
||||
#define MMC_XGMAC_RX_TCP_GD_OCTETS 0x324
|
||||
#define MMC_XGMAC_RX_TCP_ERR_OCTETS 0x32c
|
||||
#define MMC_XGMAC_RX_ICMP_GD_OCTETS 0x334
|
||||
#define MMC_XGMAC_RX_ICMP_ERR_OCTETS 0x33c
|
||||
|
||||
static void dwmac_mmc_ctrl(void __iomem *mmcaddr, unsigned int mode)
|
||||
{
|
||||
u32 value = readl(mmcaddr + MMC_CNTRL);
|
||||
|
||||
value |= (mode & 0x3F);
|
||||
|
||||
writel(value, mmcaddr + MMC_CNTRL);
|
||||
|
||||
pr_debug("stmmac: MMC ctrl register (offset 0x%x): 0x%08x\n",
|
||||
MMC_CNTRL, value);
|
||||
}
|
||||
|
||||
/* To mask all interrupts.*/
|
||||
static void dwmac_mmc_intr_all_mask(void __iomem *mmcaddr)
|
||||
{
|
||||
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_RX_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_TX_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_RX_IPC_INTR_MASK);
|
||||
}
|
||||
|
||||
/* This reads the MAC core counters (if actaully supported).
|
||||
* by default the MMC core is programmed to reset each
|
||||
* counter after a read. So all the field of the mmc struct
|
||||
* have to be incremented.
|
||||
*/
|
||||
static void dwmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc)
|
||||
{
|
||||
mmc->mmc_tx_octetcount_gb += readl(mmcaddr + MMC_TX_OCTETCOUNT_GB);
|
||||
mmc->mmc_tx_framecount_gb += readl(mmcaddr + MMC_TX_FRAMECOUNT_GB);
|
||||
mmc->mmc_tx_broadcastframe_g += readl(mmcaddr +
|
||||
MMC_TX_BROADCASTFRAME_G);
|
||||
mmc->mmc_tx_multicastframe_g += readl(mmcaddr +
|
||||
MMC_TX_MULTICASTFRAME_G);
|
||||
mmc->mmc_tx_64_octets_gb += readl(mmcaddr + MMC_TX_64_OCTETS_GB);
|
||||
mmc->mmc_tx_65_to_127_octets_gb +=
|
||||
readl(mmcaddr + MMC_TX_65_TO_127_OCTETS_GB);
|
||||
mmc->mmc_tx_128_to_255_octets_gb +=
|
||||
readl(mmcaddr + MMC_TX_128_TO_255_OCTETS_GB);
|
||||
mmc->mmc_tx_256_to_511_octets_gb +=
|
||||
readl(mmcaddr + MMC_TX_256_TO_511_OCTETS_GB);
|
||||
mmc->mmc_tx_512_to_1023_octets_gb +=
|
||||
readl(mmcaddr + MMC_TX_512_TO_1023_OCTETS_GB);
|
||||
mmc->mmc_tx_1024_to_max_octets_gb +=
|
||||
readl(mmcaddr + MMC_TX_1024_TO_MAX_OCTETS_GB);
|
||||
mmc->mmc_tx_unicast_gb += readl(mmcaddr + MMC_TX_UNICAST_GB);
|
||||
mmc->mmc_tx_multicast_gb += readl(mmcaddr + MMC_TX_MULTICAST_GB);
|
||||
mmc->mmc_tx_broadcast_gb += readl(mmcaddr + MMC_TX_BROADCAST_GB);
|
||||
mmc->mmc_tx_underflow_error += readl(mmcaddr + MMC_TX_UNDERFLOW_ERROR);
|
||||
mmc->mmc_tx_singlecol_g += readl(mmcaddr + MMC_TX_SINGLECOL_G);
|
||||
mmc->mmc_tx_multicol_g += readl(mmcaddr + MMC_TX_MULTICOL_G);
|
||||
mmc->mmc_tx_deferred += readl(mmcaddr + MMC_TX_DEFERRED);
|
||||
mmc->mmc_tx_latecol += readl(mmcaddr + MMC_TX_LATECOL);
|
||||
mmc->mmc_tx_exesscol += readl(mmcaddr + MMC_TX_EXESSCOL);
|
||||
mmc->mmc_tx_carrier_error += readl(mmcaddr + MMC_TX_CARRIER_ERROR);
|
||||
mmc->mmc_tx_octetcount_g += readl(mmcaddr + MMC_TX_OCTETCOUNT_G);
|
||||
mmc->mmc_tx_framecount_g += readl(mmcaddr + MMC_TX_FRAMECOUNT_G);
|
||||
mmc->mmc_tx_excessdef += readl(mmcaddr + MMC_TX_EXCESSDEF);
|
||||
mmc->mmc_tx_pause_frame += readl(mmcaddr + MMC_TX_PAUSE_FRAME);
|
||||
mmc->mmc_tx_vlan_frame_g += readl(mmcaddr + MMC_TX_VLAN_FRAME_G);
|
||||
mmc->mmc_tx_oversize_g += readl(mmcaddr + MMC_TX_OVERSIZE_G);
|
||||
mmc->mmc_tx_lpi_usec += readl(mmcaddr + MMC_TX_LPI_USEC);
|
||||
mmc->mmc_tx_lpi_tran += readl(mmcaddr + MMC_TX_LPI_TRAN);
|
||||
|
||||
/* MMC RX counter registers */
|
||||
mmc->mmc_rx_framecount_gb += readl(mmcaddr + MMC_RX_FRAMECOUNT_GB);
|
||||
mmc->mmc_rx_octetcount_gb += readl(mmcaddr + MMC_RX_OCTETCOUNT_GB);
|
||||
mmc->mmc_rx_octetcount_g += readl(mmcaddr + MMC_RX_OCTETCOUNT_G);
|
||||
mmc->mmc_rx_broadcastframe_g += readl(mmcaddr +
|
||||
MMC_RX_BROADCASTFRAME_G);
|
||||
mmc->mmc_rx_multicastframe_g += readl(mmcaddr +
|
||||
MMC_RX_MULTICASTFRAME_G);
|
||||
mmc->mmc_rx_crc_error += readl(mmcaddr + MMC_RX_CRC_ERROR);
|
||||
mmc->mmc_rx_align_error += readl(mmcaddr + MMC_RX_ALIGN_ERROR);
|
||||
mmc->mmc_rx_run_error += readl(mmcaddr + MMC_RX_RUN_ERROR);
|
||||
mmc->mmc_rx_jabber_error += readl(mmcaddr + MMC_RX_JABBER_ERROR);
|
||||
mmc->mmc_rx_undersize_g += readl(mmcaddr + MMC_RX_UNDERSIZE_G);
|
||||
mmc->mmc_rx_oversize_g += readl(mmcaddr + MMC_RX_OVERSIZE_G);
|
||||
mmc->mmc_rx_64_octets_gb += readl(mmcaddr + MMC_RX_64_OCTETS_GB);
|
||||
mmc->mmc_rx_65_to_127_octets_gb +=
|
||||
readl(mmcaddr + MMC_RX_65_TO_127_OCTETS_GB);
|
||||
mmc->mmc_rx_128_to_255_octets_gb +=
|
||||
readl(mmcaddr + MMC_RX_128_TO_255_OCTETS_GB);
|
||||
mmc->mmc_rx_256_to_511_octets_gb +=
|
||||
readl(mmcaddr + MMC_RX_256_TO_511_OCTETS_GB);
|
||||
mmc->mmc_rx_512_to_1023_octets_gb +=
|
||||
readl(mmcaddr + MMC_RX_512_TO_1023_OCTETS_GB);
|
||||
mmc->mmc_rx_1024_to_max_octets_gb +=
|
||||
readl(mmcaddr + MMC_RX_1024_TO_MAX_OCTETS_GB);
|
||||
mmc->mmc_rx_unicast_g += readl(mmcaddr + MMC_RX_UNICAST_G);
|
||||
mmc->mmc_rx_length_error += readl(mmcaddr + MMC_RX_LENGTH_ERROR);
|
||||
mmc->mmc_rx_autofrangetype += readl(mmcaddr + MMC_RX_AUTOFRANGETYPE);
|
||||
mmc->mmc_rx_pause_frames += readl(mmcaddr + MMC_RX_PAUSE_FRAMES);
|
||||
mmc->mmc_rx_fifo_overflow += readl(mmcaddr + MMC_RX_FIFO_OVERFLOW);
|
||||
mmc->mmc_rx_vlan_frames_gb += readl(mmcaddr + MMC_RX_VLAN_FRAMES_GB);
|
||||
mmc->mmc_rx_watchdog_error += readl(mmcaddr + MMC_RX_WATCHDOG_ERROR);
|
||||
mmc->mmc_rx_error += readl(mmcaddr + MMC_RX_ERROR);
|
||||
mmc->mmc_rx_lpi_usec += readl(mmcaddr + MMC_RX_LPI_USEC);
|
||||
mmc->mmc_rx_lpi_tran += readl(mmcaddr + MMC_RX_LPI_TRAN);
|
||||
|
||||
/* IPv4 */
|
||||
mmc->mmc_rx_ipv4_gd += readl(mmcaddr + MMC_RX_IPV4_GD);
|
||||
mmc->mmc_rx_ipv4_hderr += readl(mmcaddr + MMC_RX_IPV4_HDERR);
|
||||
mmc->mmc_rx_ipv4_nopay += readl(mmcaddr + MMC_RX_IPV4_NOPAY);
|
||||
mmc->mmc_rx_ipv4_frag += readl(mmcaddr + MMC_RX_IPV4_FRAG);
|
||||
mmc->mmc_rx_ipv4_udsbl += readl(mmcaddr + MMC_RX_IPV4_UDSBL);
|
||||
|
||||
mmc->mmc_rx_ipv4_gd_octets += readl(mmcaddr + MMC_RX_IPV4_GD_OCTETS);
|
||||
mmc->mmc_rx_ipv4_hderr_octets +=
|
||||
readl(mmcaddr + MMC_RX_IPV4_HDERR_OCTETS);
|
||||
mmc->mmc_rx_ipv4_nopay_octets +=
|
||||
readl(mmcaddr + MMC_RX_IPV4_NOPAY_OCTETS);
|
||||
mmc->mmc_rx_ipv4_frag_octets += readl(mmcaddr +
|
||||
MMC_RX_IPV4_FRAG_OCTETS);
|
||||
mmc->mmc_rx_ipv4_udsbl_octets +=
|
||||
readl(mmcaddr + MMC_RX_IPV4_UDSBL_OCTETS);
|
||||
|
||||
/* IPV6 */
|
||||
mmc->mmc_rx_ipv6_gd_octets += readl(mmcaddr + MMC_RX_IPV6_GD_OCTETS);
|
||||
mmc->mmc_rx_ipv6_hderr_octets +=
|
||||
readl(mmcaddr + MMC_RX_IPV6_HDERR_OCTETS);
|
||||
mmc->mmc_rx_ipv6_nopay_octets +=
|
||||
readl(mmcaddr + MMC_RX_IPV6_NOPAY_OCTETS);
|
||||
|
||||
mmc->mmc_rx_ipv6_gd += readl(mmcaddr + MMC_RX_IPV6_GD);
|
||||
mmc->mmc_rx_ipv6_hderr += readl(mmcaddr + MMC_RX_IPV6_HDERR);
|
||||
mmc->mmc_rx_ipv6_nopay += readl(mmcaddr + MMC_RX_IPV6_NOPAY);
|
||||
|
||||
/* Protocols */
|
||||
mmc->mmc_rx_udp_gd += readl(mmcaddr + MMC_RX_UDP_GD);
|
||||
mmc->mmc_rx_udp_err += readl(mmcaddr + MMC_RX_UDP_ERR);
|
||||
mmc->mmc_rx_tcp_gd += readl(mmcaddr + MMC_RX_TCP_GD);
|
||||
mmc->mmc_rx_tcp_err += readl(mmcaddr + MMC_RX_TCP_ERR);
|
||||
mmc->mmc_rx_icmp_gd += readl(mmcaddr + MMC_RX_ICMP_GD);
|
||||
mmc->mmc_rx_icmp_err += readl(mmcaddr + MMC_RX_ICMP_ERR);
|
||||
|
||||
mmc->mmc_rx_udp_gd_octets += readl(mmcaddr + MMC_RX_UDP_GD_OCTETS);
|
||||
mmc->mmc_rx_udp_err_octets += readl(mmcaddr + MMC_RX_UDP_ERR_OCTETS);
|
||||
mmc->mmc_rx_tcp_gd_octets += readl(mmcaddr + MMC_RX_TCP_GD_OCTETS);
|
||||
mmc->mmc_rx_tcp_err_octets += readl(mmcaddr + MMC_RX_TCP_ERR_OCTETS);
|
||||
mmc->mmc_rx_icmp_gd_octets += readl(mmcaddr + MMC_RX_ICMP_GD_OCTETS);
|
||||
mmc->mmc_rx_icmp_err_octets += readl(mmcaddr + MMC_RX_ICMP_ERR_OCTETS);
|
||||
|
||||
mmc->mmc_tx_fpe_fragment_cntr += readl(mmcaddr + MMC_TX_FPE_FRAG);
|
||||
mmc->mmc_tx_hold_req_cntr += readl(mmcaddr + MMC_TX_HOLD_REQ);
|
||||
mmc->mmc_rx_packet_assembly_err_cntr +=
|
||||
readl(mmcaddr + MMC_RX_PKT_ASSEMBLY_ERR);
|
||||
mmc->mmc_rx_packet_smd_err_cntr += readl(mmcaddr + MMC_RX_PKT_SMD_ERR);
|
||||
mmc->mmc_rx_packet_assembly_ok_cntr +=
|
||||
readl(mmcaddr + MMC_RX_PKT_ASSEMBLY_OK);
|
||||
mmc->mmc_rx_fpe_fragment_cntr += readl(mmcaddr + MMC_RX_FPE_FRAG);
|
||||
}
|
||||
|
||||
const struct stmmac_mmc_ops dwmac_mmc_ops = {
|
||||
.ctrl = dwmac_mmc_ctrl,
|
||||
.intr_all_mask = dwmac_mmc_intr_all_mask,
|
||||
.read = dwmac_mmc_read,
|
||||
};
|
||||
|
||||
static void dwxgmac_mmc_ctrl(void __iomem *mmcaddr, unsigned int mode)
|
||||
{
|
||||
u32 value = readl(mmcaddr + MMC_CNTRL);
|
||||
|
||||
value |= (mode & 0x3F);
|
||||
|
||||
writel(value, mmcaddr + MMC_CNTRL);
|
||||
}
|
||||
|
||||
static void dwxgmac_mmc_intr_all_mask(void __iomem *mmcaddr)
|
||||
{
|
||||
writel(0x0, mmcaddr + MMC_RX_INTR_MASK);
|
||||
writel(0x0, mmcaddr + MMC_TX_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_XGMAC_TX_FPE_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_XGMAC_RX_FPE_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_XGMAC_RX_IPC_INTR_MASK);
|
||||
}
|
||||
|
||||
static void dwxgmac_read_mmc_reg(void __iomem *addr, u32 reg, u32 *dest)
|
||||
{
|
||||
u64 tmp = 0;
|
||||
|
||||
tmp += readl(addr + reg);
|
||||
tmp += ((u64 )readl(addr + reg + 0x4)) << 32;
|
||||
if (tmp > GENMASK(31, 0))
|
||||
*dest = ~0x0;
|
||||
else
|
||||
*dest = *dest + tmp;
|
||||
}
|
||||
|
||||
/* This reads the MAC core counters (if actaully supported).
|
||||
* by default the MMC core is programmed to reset each
|
||||
* counter after a read. So all the field of the mmc struct
|
||||
* have to be incremented.
|
||||
*/
|
||||
static void dwxgmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc)
|
||||
{
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_OCTET_GB,
|
||||
&mmc->mmc_tx_octetcount_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_PKT_GB,
|
||||
&mmc->mmc_tx_framecount_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_BROAD_PKT_G,
|
||||
&mmc->mmc_tx_broadcastframe_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_MULTI_PKT_G,
|
||||
&mmc->mmc_tx_multicastframe_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_64OCT_GB,
|
||||
&mmc->mmc_tx_64_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_65OCT_GB,
|
||||
&mmc->mmc_tx_65_to_127_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_128OCT_GB,
|
||||
&mmc->mmc_tx_128_to_255_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_256OCT_GB,
|
||||
&mmc->mmc_tx_256_to_511_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_512OCT_GB,
|
||||
&mmc->mmc_tx_512_to_1023_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_1024OCT_GB,
|
||||
&mmc->mmc_tx_1024_to_max_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_UNI_PKT_GB,
|
||||
&mmc->mmc_tx_unicast_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_MULTI_PKT_GB,
|
||||
&mmc->mmc_tx_multicast_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_BROAD_PKT_GB,
|
||||
&mmc->mmc_tx_broadcast_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_UNDER,
|
||||
&mmc->mmc_tx_underflow_error);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_OCTET_G,
|
||||
&mmc->mmc_tx_octetcount_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_PKT_G,
|
||||
&mmc->mmc_tx_framecount_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_PAUSE,
|
||||
&mmc->mmc_tx_pause_frame);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_VLAN_PKT_G,
|
||||
&mmc->mmc_tx_vlan_frame_g);
|
||||
mmc->mmc_tx_lpi_usec += readl(mmcaddr + MMC_XGMAC_TX_LPI_USEC);
|
||||
mmc->mmc_tx_lpi_tran += readl(mmcaddr + MMC_XGMAC_TX_LPI_TRAN);
|
||||
|
||||
/* MMC RX counter registers */
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_PKT_GB,
|
||||
&mmc->mmc_rx_framecount_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_OCTET_GB,
|
||||
&mmc->mmc_rx_octetcount_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_OCTET_G,
|
||||
&mmc->mmc_rx_octetcount_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_BROAD_PKT_G,
|
||||
&mmc->mmc_rx_broadcastframe_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_MULTI_PKT_G,
|
||||
&mmc->mmc_rx_multicastframe_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_CRC_ERR,
|
||||
&mmc->mmc_rx_crc_error);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_CRC_ERR,
|
||||
&mmc->mmc_rx_crc_error);
|
||||
mmc->mmc_rx_run_error += readl(mmcaddr + MMC_XGMAC_RX_RUNT_ERR);
|
||||
mmc->mmc_rx_jabber_error += readl(mmcaddr + MMC_XGMAC_RX_JABBER_ERR);
|
||||
mmc->mmc_rx_undersize_g += readl(mmcaddr + MMC_XGMAC_RX_UNDER);
|
||||
mmc->mmc_rx_oversize_g += readl(mmcaddr + MMC_XGMAC_RX_OVER);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_64OCT_GB,
|
||||
&mmc->mmc_rx_64_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_65OCT_GB,
|
||||
&mmc->mmc_rx_65_to_127_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_128OCT_GB,
|
||||
&mmc->mmc_rx_128_to_255_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_256OCT_GB,
|
||||
&mmc->mmc_rx_256_to_511_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_512OCT_GB,
|
||||
&mmc->mmc_rx_512_to_1023_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_1024OCT_GB,
|
||||
&mmc->mmc_rx_1024_to_max_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UNI_PKT_G,
|
||||
&mmc->mmc_rx_unicast_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_LENGTH_ERR,
|
||||
&mmc->mmc_rx_length_error);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_RANGE,
|
||||
&mmc->mmc_rx_autofrangetype);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_PAUSE,
|
||||
&mmc->mmc_rx_pause_frames);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_FIFOOVER_PKT,
|
||||
&mmc->mmc_rx_fifo_overflow);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_VLAN_PKT_GB,
|
||||
&mmc->mmc_rx_vlan_frames_gb);
|
||||
mmc->mmc_rx_watchdog_error += readl(mmcaddr + MMC_XGMAC_RX_WATCHDOG_ERR);
|
||||
mmc->mmc_rx_lpi_usec += readl(mmcaddr + MMC_XGMAC_RX_LPI_USEC);
|
||||
mmc->mmc_rx_lpi_tran += readl(mmcaddr + MMC_XGMAC_RX_LPI_TRAN);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_DISCARD_PKT_GB,
|
||||
&mmc->mmc_rx_discard_frames_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_DISCARD_OCT_GB,
|
||||
&mmc->mmc_rx_discard_octets_gb);
|
||||
mmc->mmc_rx_align_err_frames +=
|
||||
readl(mmcaddr + MMC_XGMAC_RX_ALIGN_ERR_PKT);
|
||||
|
||||
mmc->mmc_sgf_pass_fragment_cntr +=
|
||||
readl(mmcaddr + MMC_XGMAC_SGF_PASS_PKT);
|
||||
mmc->mmc_sgf_fail_fragment_cntr +=
|
||||
readl(mmcaddr + MMC_XGMAC_SGF_FAIL_PKT);
|
||||
mmc->mmc_tx_fpe_fragment_cntr += readl(mmcaddr + MMC_XGMAC_TX_FPE_FRAG);
|
||||
mmc->mmc_tx_hold_req_cntr += readl(mmcaddr + MMC_XGMAC_TX_HOLD_REQ);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_GATE_OVERRUN,
|
||||
&mmc->mmc_tx_gate_overrun_cntr);
|
||||
mmc->mmc_rx_packet_assembly_err_cntr +=
|
||||
readl(mmcaddr + MMC_XGMAC_RX_PKT_ASSEMBLY_ERR);
|
||||
mmc->mmc_rx_packet_smd_err_cntr +=
|
||||
readl(mmcaddr + MMC_XGMAC_RX_PKT_SMD_ERR);
|
||||
mmc->mmc_rx_packet_assembly_ok_cntr +=
|
||||
readl(mmcaddr + MMC_XGMAC_RX_PKT_ASSEMBLY_OK);
|
||||
mmc->mmc_rx_fpe_fragment_cntr +=
|
||||
readl(mmcaddr + MMC_XGMAC_RX_FPE_FRAG);
|
||||
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_GD,
|
||||
&mmc->mmc_rx_ipv4_gd);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_HDERR,
|
||||
&mmc->mmc_rx_ipv4_hderr);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_NOPAY,
|
||||
&mmc->mmc_rx_ipv4_nopay);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_FRAG,
|
||||
&mmc->mmc_rx_ipv4_frag);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_UDSBL,
|
||||
&mmc->mmc_rx_ipv4_udsbl);
|
||||
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_GD,
|
||||
&mmc->mmc_rx_ipv6_gd);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_HDERR,
|
||||
&mmc->mmc_rx_ipv6_hderr);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_NOPAY,
|
||||
&mmc->mmc_rx_ipv6_nopay);
|
||||
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UDP_GD,
|
||||
&mmc->mmc_rx_udp_gd);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UDP_ERR,
|
||||
&mmc->mmc_rx_udp_err);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_TCP_GD,
|
||||
&mmc->mmc_rx_tcp_gd);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_TCP_ERR,
|
||||
&mmc->mmc_rx_tcp_err);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_ICMP_GD,
|
||||
&mmc->mmc_rx_icmp_gd);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_ICMP_ERR,
|
||||
&mmc->mmc_rx_icmp_err);
|
||||
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_GD_OCTETS,
|
||||
&mmc->mmc_rx_ipv4_gd_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_HDERR_OCTETS,
|
||||
&mmc->mmc_rx_ipv4_hderr_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_NOPAY_OCTETS,
|
||||
&mmc->mmc_rx_ipv4_nopay_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_FRAG_OCTETS,
|
||||
&mmc->mmc_rx_ipv4_frag_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_UDSBL_OCTETS,
|
||||
&mmc->mmc_rx_ipv4_udsbl_octets);
|
||||
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_GD_OCTETS,
|
||||
&mmc->mmc_rx_ipv6_gd_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_HDERR_OCTETS,
|
||||
&mmc->mmc_rx_ipv6_hderr_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_NOPAY_OCTETS,
|
||||
&mmc->mmc_rx_ipv6_nopay_octets);
|
||||
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UDP_GD_OCTETS,
|
||||
&mmc->mmc_rx_udp_gd_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UDP_ERR_OCTETS,
|
||||
&mmc->mmc_rx_udp_err_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_TCP_GD_OCTETS,
|
||||
&mmc->mmc_rx_tcp_gd_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_TCP_ERR_OCTETS,
|
||||
&mmc->mmc_rx_tcp_err_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_ICMP_GD_OCTETS,
|
||||
&mmc->mmc_rx_icmp_gd_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_ICMP_ERR_OCTETS,
|
||||
&mmc->mmc_rx_icmp_err_octets);
|
||||
}
|
||||
|
||||
const struct stmmac_mmc_ops dwxgmac_mmc_ops = {
|
||||
.ctrl = dwxgmac_mmc_ctrl,
|
||||
.intr_all_mask = dwxgmac_mmc_intr_all_mask,
|
||||
.read = dwxgmac_mmc_read,
|
||||
};
|
||||
|
|
@ -0,0 +1,606 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
DWMAC Management Counters
|
||||
|
||||
Copyright (C) 2011 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include "hwif.h"
|
||||
#include "mmc.h"
|
||||
|
||||
/* MAC Management Counters register offset */
|
||||
|
||||
#define MMC_CNTRL 0x00 /* MMC Control */
|
||||
#define MMC_RX_INTR 0x04 /* MMC RX Interrupt */
|
||||
#define MMC_TX_INTR 0x08 /* MMC TX Interrupt */
|
||||
#define MMC_RX_INTR_MASK 0x0c /* MMC Interrupt Mask */
|
||||
#define MMC_TX_INTR_MASK 0x10 /* MMC Interrupt Mask */
|
||||
#define MMC_DEFAULT_MASK 0xffffffff
|
||||
|
||||
/* MMC TX counter registers */
|
||||
|
||||
/* Note:
|
||||
* _GB register stands for good and bad frames
|
||||
* _G is for good only.
|
||||
*/
|
||||
#define MMC_TX_OCTETCOUNT_GB 0x14
|
||||
#define MMC_TX_FRAMECOUNT_GB 0x18
|
||||
#define MMC_TX_BROADCASTFRAME_G 0x1c
|
||||
#define MMC_TX_MULTICASTFRAME_G 0x20
|
||||
#define MMC_TX_64_OCTETS_GB 0x24
|
||||
#define MMC_TX_65_TO_127_OCTETS_GB 0x28
|
||||
#define MMC_TX_128_TO_255_OCTETS_GB 0x2c
|
||||
#define MMC_TX_256_TO_511_OCTETS_GB 0x30
|
||||
#define MMC_TX_512_TO_1023_OCTETS_GB 0x34
|
||||
#define MMC_TX_1024_TO_MAX_OCTETS_GB 0x38
|
||||
#define MMC_TX_UNICAST_GB 0x3c
|
||||
#define MMC_TX_MULTICAST_GB 0x40
|
||||
#define MMC_TX_BROADCAST_GB 0x44
|
||||
#define MMC_TX_UNDERFLOW_ERROR 0x48
|
||||
#define MMC_TX_SINGLECOL_G 0x4c
|
||||
#define MMC_TX_MULTICOL_G 0x50
|
||||
#define MMC_TX_DEFERRED 0x54
|
||||
#define MMC_TX_LATECOL 0x58
|
||||
#define MMC_TX_EXESSCOL 0x5c
|
||||
#define MMC_TX_CARRIER_ERROR 0x60
|
||||
#define MMC_TX_OCTETCOUNT_G 0x64
|
||||
#define MMC_TX_FRAMECOUNT_G 0x68
|
||||
#define MMC_TX_EXCESSDEF 0x6c
|
||||
#define MMC_TX_PAUSE_FRAME 0x70
|
||||
#define MMC_TX_VLAN_FRAME_G 0x74
|
||||
#define MMC_TX_OVERSIZE_G 0x78
|
||||
|
||||
/* MMC RX counter registers */
|
||||
#define MMC_RX_FRAMECOUNT_GB 0x80
|
||||
#define MMC_RX_OCTETCOUNT_GB 0x84
|
||||
#define MMC_RX_OCTETCOUNT_G 0x88
|
||||
#define MMC_RX_BROADCASTFRAME_G 0x8c
|
||||
#define MMC_RX_MULTICASTFRAME_G 0x90
|
||||
#define MMC_RX_CRC_ERROR 0x94
|
||||
#define MMC_RX_ALIGN_ERROR 0x98
|
||||
#define MMC_RX_RUN_ERROR 0x9C
|
||||
#define MMC_RX_JABBER_ERROR 0xA0
|
||||
#define MMC_RX_UNDERSIZE_G 0xA4
|
||||
#define MMC_RX_OVERSIZE_G 0xA8
|
||||
#define MMC_RX_64_OCTETS_GB 0xAC
|
||||
#define MMC_RX_65_TO_127_OCTETS_GB 0xb0
|
||||
#define MMC_RX_128_TO_255_OCTETS_GB 0xb4
|
||||
#define MMC_RX_256_TO_511_OCTETS_GB 0xb8
|
||||
#define MMC_RX_512_TO_1023_OCTETS_GB 0xbc
|
||||
#define MMC_RX_1024_TO_MAX_OCTETS_GB 0xc0
|
||||
#define MMC_RX_UNICAST_G 0xc4
|
||||
#define MMC_RX_LENGTH_ERROR 0xc8
|
||||
#define MMC_RX_AUTOFRANGETYPE 0xcc
|
||||
#define MMC_RX_PAUSE_FRAMES 0xd0
|
||||
#define MMC_RX_FIFO_OVERFLOW 0xd4
|
||||
#define MMC_RX_VLAN_FRAMES_GB 0xd8
|
||||
#define MMC_RX_WATCHDOG_ERROR 0xdc
|
||||
#define MMC_RX_ERROR 0xe0
|
||||
|
||||
#define MMC_TX_LPI_USEC 0xec
|
||||
#define MMC_TX_LPI_TRAN 0xf0
|
||||
#define MMC_RX_LPI_USEC 0xf4
|
||||
#define MMC_RX_LPI_TRAN 0xf8
|
||||
|
||||
/* IPC*/
|
||||
#define MMC_RX_IPC_INTR_MASK 0x100
|
||||
#define MMC_RX_IPC_INTR 0x108
|
||||
/* IPv4*/
|
||||
#define MMC_RX_IPV4_GD 0x110
|
||||
#define MMC_RX_IPV4_HDERR 0x114
|
||||
#define MMC_RX_IPV4_NOPAY 0x118
|
||||
#define MMC_RX_IPV4_FRAG 0x11C
|
||||
#define MMC_RX_IPV4_UDSBL 0x120
|
||||
|
||||
#define MMC_RX_IPV4_GD_OCTETS 0x150
|
||||
#define MMC_RX_IPV4_HDERR_OCTETS 0x154
|
||||
#define MMC_RX_IPV4_NOPAY_OCTETS 0x158
|
||||
#define MMC_RX_IPV4_FRAG_OCTETS 0x15c
|
||||
#define MMC_RX_IPV4_UDSBL_OCTETS 0x160
|
||||
|
||||
/* IPV6*/
|
||||
#define MMC_RX_IPV6_GD_OCTETS 0x164
|
||||
#define MMC_RX_IPV6_HDERR_OCTETS 0x168
|
||||
#define MMC_RX_IPV6_NOPAY_OCTETS 0x16c
|
||||
|
||||
#define MMC_RX_IPV6_GD 0x124
|
||||
#define MMC_RX_IPV6_HDERR 0x128
|
||||
#define MMC_RX_IPV6_NOPAY 0x12c
|
||||
|
||||
/* Protocols*/
|
||||
#define MMC_RX_UDP_GD 0x130
|
||||
#define MMC_RX_UDP_ERR 0x134
|
||||
#define MMC_RX_TCP_GD 0x138
|
||||
#define MMC_RX_TCP_ERR 0x13c
|
||||
#define MMC_RX_ICMP_GD 0x140
|
||||
#define MMC_RX_ICMP_ERR 0x144
|
||||
|
||||
#define MMC_RX_UDP_GD_OCTETS 0x170
|
||||
#define MMC_RX_UDP_ERR_OCTETS 0x174
|
||||
#define MMC_RX_TCP_GD_OCTETS 0x178
|
||||
#define MMC_RX_TCP_ERR_OCTETS 0x17c
|
||||
#define MMC_RX_ICMP_GD_OCTETS 0x180
|
||||
#define MMC_RX_ICMP_ERR_OCTETS 0x184
|
||||
|
||||
#define MMC_TX_FPE_FRAG 0x1a8
|
||||
#define MMC_TX_HOLD_REQ 0x1ac
|
||||
#define MMC_RX_PKT_ASSEMBLY_ERR 0x1c8
|
||||
#define MMC_RX_PKT_SMD_ERR 0x1cc
|
||||
#define MMC_RX_PKT_ASSEMBLY_OK 0x1d0
|
||||
#define MMC_RX_FPE_FRAG 0x1d4
|
||||
|
||||
/* XGMAC MMC Registers */
|
||||
#define MMC_XGMAC_TX_OCTET_GB 0x14
|
||||
#define MMC_XGMAC_TX_PKT_GB 0x1c
|
||||
#define MMC_XGMAC_TX_BROAD_PKT_G 0x24
|
||||
#define MMC_XGMAC_TX_MULTI_PKT_G 0x2c
|
||||
#define MMC_XGMAC_TX_64OCT_GB 0x34
|
||||
#define MMC_XGMAC_TX_65OCT_GB 0x3c
|
||||
#define MMC_XGMAC_TX_128OCT_GB 0x44
|
||||
#define MMC_XGMAC_TX_256OCT_GB 0x4c
|
||||
#define MMC_XGMAC_TX_512OCT_GB 0x54
|
||||
#define MMC_XGMAC_TX_1024OCT_GB 0x5c
|
||||
#define MMC_XGMAC_TX_UNI_PKT_GB 0x64
|
||||
#define MMC_XGMAC_TX_MULTI_PKT_GB 0x6c
|
||||
#define MMC_XGMAC_TX_BROAD_PKT_GB 0x74
|
||||
#define MMC_XGMAC_TX_UNDER 0x7c
|
||||
#define MMC_XGMAC_TX_OCTET_G 0x84
|
||||
#define MMC_XGMAC_TX_PKT_G 0x8c
|
||||
#define MMC_XGMAC_TX_PAUSE 0x94
|
||||
#define MMC_XGMAC_TX_VLAN_PKT_G 0x9c
|
||||
#define MMC_XGMAC_TX_LPI_USEC 0xa4
|
||||
#define MMC_XGMAC_TX_LPI_TRAN 0xa8
|
||||
|
||||
#define MMC_XGMAC_RX_PKT_GB 0x100
|
||||
#define MMC_XGMAC_RX_OCTET_GB 0x108
|
||||
#define MMC_XGMAC_RX_OCTET_G 0x110
|
||||
#define MMC_XGMAC_RX_BROAD_PKT_G 0x118
|
||||
#define MMC_XGMAC_RX_MULTI_PKT_G 0x120
|
||||
#define MMC_XGMAC_RX_CRC_ERR 0x128
|
||||
#define MMC_XGMAC_RX_RUNT_ERR 0x130
|
||||
#define MMC_XGMAC_RX_JABBER_ERR 0x134
|
||||
#define MMC_XGMAC_RX_UNDER 0x138
|
||||
#define MMC_XGMAC_RX_OVER 0x13c
|
||||
#define MMC_XGMAC_RX_64OCT_GB 0x140
|
||||
#define MMC_XGMAC_RX_65OCT_GB 0x148
|
||||
#define MMC_XGMAC_RX_128OCT_GB 0x150
|
||||
#define MMC_XGMAC_RX_256OCT_GB 0x158
|
||||
#define MMC_XGMAC_RX_512OCT_GB 0x160
|
||||
#define MMC_XGMAC_RX_1024OCT_GB 0x168
|
||||
#define MMC_XGMAC_RX_UNI_PKT_G 0x170
|
||||
#define MMC_XGMAC_RX_LENGTH_ERR 0x178
|
||||
#define MMC_XGMAC_RX_RANGE 0x180
|
||||
#define MMC_XGMAC_RX_PAUSE 0x188
|
||||
#define MMC_XGMAC_RX_FIFOOVER_PKT 0x190
|
||||
#define MMC_XGMAC_RX_VLAN_PKT_GB 0x198
|
||||
#define MMC_XGMAC_RX_WATCHDOG_ERR 0x1a0
|
||||
#define MMC_XGMAC_RX_LPI_USEC 0x1a4
|
||||
#define MMC_XGMAC_RX_LPI_TRAN 0x1a8
|
||||
#define MMC_XGMAC_RX_DISCARD_PKT_GB 0x1ac
|
||||
#define MMC_XGMAC_RX_DISCARD_OCT_GB 0x1b4
|
||||
#define MMC_XGMAC_RX_ALIGN_ERR_PKT 0x1bc
|
||||
|
||||
#define MMC_XGMAC_SGF_PASS_PKT 0x1f0
|
||||
#define MMC_XGMAC_SGF_FAIL_PKT 0x1f4
|
||||
#define MMC_XGMAC_TX_FPE_INTR_MASK 0x204
|
||||
#define MMC_XGMAC_TX_FPE_FRAG 0x208
|
||||
#define MMC_XGMAC_TX_HOLD_REQ 0x20c
|
||||
#define MMC_XGMAC_TX_GATE_OVERRUN 0x210
|
||||
#define MMC_XGMAC_RX_FPE_INTR_MASK 0x224
|
||||
#define MMC_XGMAC_RX_PKT_ASSEMBLY_ERR 0x228
|
||||
#define MMC_XGMAC_RX_PKT_SMD_ERR 0x22c
|
||||
#define MMC_XGMAC_RX_PKT_ASSEMBLY_OK 0x230
|
||||
#define MMC_XGMAC_RX_FPE_FRAG 0x234
|
||||
#define MMC_XGMAC_RX_IPC_INTR_MASK 0x25c
|
||||
|
||||
#define MMC_XGMAC_RX_IPV4_GD 0x264
|
||||
#define MMC_XGMAC_RX_IPV4_HDERR 0x26c
|
||||
#define MMC_XGMAC_RX_IPV4_NOPAY 0x274
|
||||
#define MMC_XGMAC_RX_IPV4_FRAG 0x27c
|
||||
#define MMC_XGMAC_RX_IPV4_UDSBL 0x284
|
||||
|
||||
#define MMC_XGMAC_RX_IPV6_GD 0x28c
|
||||
#define MMC_XGMAC_RX_IPV6_HDERR 0x294
|
||||
#define MMC_XGMAC_RX_IPV6_NOPAY 0x29c
|
||||
|
||||
#define MMC_XGMAC_RX_UDP_GD 0x2a4
|
||||
#define MMC_XGMAC_RX_UDP_ERR 0x2ac
|
||||
#define MMC_XGMAC_RX_TCP_GD 0x2b4
|
||||
#define MMC_XGMAC_RX_TCP_ERR 0x2bc
|
||||
#define MMC_XGMAC_RX_ICMP_GD 0x2c4
|
||||
#define MMC_XGMAC_RX_ICMP_ERR 0x2cc
|
||||
|
||||
#define MMC_XGMAC_RX_IPV4_GD_OCTETS 0x2d4
|
||||
#define MMC_XGMAC_RX_IPV4_HDERR_OCTETS 0x2dc
|
||||
#define MMC_XGMAC_RX_IPV4_NOPAY_OCTETS 0x2e4
|
||||
#define MMC_XGMAC_RX_IPV4_FRAG_OCTETS 0x2ec
|
||||
#define MMC_XGMAC_RX_IPV4_UDSBL_OCTETS 0x2f4
|
||||
|
||||
#define MMC_XGMAC_RX_IPV6_GD_OCTETS 0x2fc
|
||||
#define MMC_XGMAC_RX_IPV6_HDERR_OCTETS 0x304
|
||||
#define MMC_XGMAC_RX_IPV6_NOPAY_OCTETS 0x30c
|
||||
|
||||
#define MMC_XGMAC_RX_UDP_GD_OCTETS 0x314
|
||||
#define MMC_XGMAC_RX_UDP_ERR_OCTETS 0x31c
|
||||
#define MMC_XGMAC_RX_TCP_GD_OCTETS 0x324
|
||||
#define MMC_XGMAC_RX_TCP_ERR_OCTETS 0x32c
|
||||
#define MMC_XGMAC_RX_ICMP_GD_OCTETS 0x334
|
||||
#define MMC_XGMAC_RX_ICMP_ERR_OCTETS 0x33c
|
||||
|
||||
static void dwmac_mmc_ctrl(void __iomem *mmcaddr, unsigned int mode)
|
||||
{
|
||||
u32 value = readl(mmcaddr + MMC_CNTRL);
|
||||
|
||||
value |= (mode & 0x3F);
|
||||
|
||||
writel(value, mmcaddr + MMC_CNTRL);
|
||||
|
||||
pr_debug("stmmac: MMC ctrl register (offset 0x%x): 0x%08x\n",
|
||||
MMC_CNTRL, value);
|
||||
}
|
||||
|
||||
/* To mask all interrupts.*/
|
||||
static void dwmac_mmc_intr_all_mask(void __iomem *mmcaddr)
|
||||
{
|
||||
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_RX_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_TX_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_RX_IPC_INTR_MASK);
|
||||
}
|
||||
|
||||
/* This reads the MAC core counters (if actaully supported).
|
||||
* by default the MMC core is programmed to reset each
|
||||
* counter after a read. So all the field of the mmc struct
|
||||
* have to be incremented.
|
||||
*/
|
||||
static void dwmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc)
|
||||
{
|
||||
mmc->mmc_tx_octetcount_gb += readl(mmcaddr + MMC_TX_OCTETCOUNT_GB);
|
||||
mmc->mmc_tx_framecount_gb += readl(mmcaddr + MMC_TX_FRAMECOUNT_GB);
|
||||
mmc->mmc_tx_broadcastframe_g += readl(mmcaddr +
|
||||
MMC_TX_BROADCASTFRAME_G);
|
||||
mmc->mmc_tx_multicastframe_g += readl(mmcaddr +
|
||||
MMC_TX_MULTICASTFRAME_G);
|
||||
mmc->mmc_tx_64_octets_gb += readl(mmcaddr + MMC_TX_64_OCTETS_GB);
|
||||
mmc->mmc_tx_65_to_127_octets_gb +=
|
||||
readl(mmcaddr + MMC_TX_65_TO_127_OCTETS_GB);
|
||||
mmc->mmc_tx_128_to_255_octets_gb +=
|
||||
readl(mmcaddr + MMC_TX_128_TO_255_OCTETS_GB);
|
||||
mmc->mmc_tx_256_to_511_octets_gb +=
|
||||
readl(mmcaddr + MMC_TX_256_TO_511_OCTETS_GB);
|
||||
mmc->mmc_tx_512_to_1023_octets_gb +=
|
||||
readl(mmcaddr + MMC_TX_512_TO_1023_OCTETS_GB);
|
||||
mmc->mmc_tx_1024_to_max_octets_gb +=
|
||||
readl(mmcaddr + MMC_TX_1024_TO_MAX_OCTETS_GB);
|
||||
mmc->mmc_tx_unicast_gb += readl(mmcaddr + MMC_TX_UNICAST_GB);
|
||||
mmc->mmc_tx_multicast_gb += readl(mmcaddr + MMC_TX_MULTICAST_GB);
|
||||
mmc->mmc_tx_broadcast_gb += readl(mmcaddr + MMC_TX_BROADCAST_GB);
|
||||
mmc->mmc_tx_underflow_error += readl(mmcaddr + MMC_TX_UNDERFLOW_ERROR);
|
||||
mmc->mmc_tx_singlecol_g += readl(mmcaddr + MMC_TX_SINGLECOL_G);
|
||||
mmc->mmc_tx_multicol_g += readl(mmcaddr + MMC_TX_MULTICOL_G);
|
||||
mmc->mmc_tx_deferred += readl(mmcaddr + MMC_TX_DEFERRED);
|
||||
mmc->mmc_tx_latecol += readl(mmcaddr + MMC_TX_LATECOL);
|
||||
mmc->mmc_tx_exesscol += readl(mmcaddr + MMC_TX_EXESSCOL);
|
||||
mmc->mmc_tx_carrier_error += readl(mmcaddr + MMC_TX_CARRIER_ERROR);
|
||||
mmc->mmc_tx_octetcount_g += readl(mmcaddr + MMC_TX_OCTETCOUNT_G);
|
||||
mmc->mmc_tx_framecount_g += readl(mmcaddr + MMC_TX_FRAMECOUNT_G);
|
||||
mmc->mmc_tx_excessdef += readl(mmcaddr + MMC_TX_EXCESSDEF);
|
||||
mmc->mmc_tx_pause_frame += readl(mmcaddr + MMC_TX_PAUSE_FRAME);
|
||||
mmc->mmc_tx_vlan_frame_g += readl(mmcaddr + MMC_TX_VLAN_FRAME_G);
|
||||
mmc->mmc_tx_oversize_g += readl(mmcaddr + MMC_TX_OVERSIZE_G);
|
||||
mmc->mmc_tx_lpi_usec += readl(mmcaddr + MMC_TX_LPI_USEC);
|
||||
mmc->mmc_tx_lpi_tran += readl(mmcaddr + MMC_TX_LPI_TRAN);
|
||||
|
||||
/* MMC RX counter registers */
|
||||
mmc->mmc_rx_framecount_gb += readl(mmcaddr + MMC_RX_FRAMECOUNT_GB);
|
||||
mmc->mmc_rx_octetcount_gb += readl(mmcaddr + MMC_RX_OCTETCOUNT_GB);
|
||||
mmc->mmc_rx_octetcount_g += readl(mmcaddr + MMC_RX_OCTETCOUNT_G);
|
||||
mmc->mmc_rx_broadcastframe_g += readl(mmcaddr +
|
||||
MMC_RX_BROADCASTFRAME_G);
|
||||
mmc->mmc_rx_multicastframe_g += readl(mmcaddr +
|
||||
MMC_RX_MULTICASTFRAME_G);
|
||||
mmc->mmc_rx_crc_error += readl(mmcaddr + MMC_RX_CRC_ERROR);
|
||||
mmc->mmc_rx_align_error += readl(mmcaddr + MMC_RX_ALIGN_ERROR);
|
||||
mmc->mmc_rx_run_error += readl(mmcaddr + MMC_RX_RUN_ERROR);
|
||||
mmc->mmc_rx_jabber_error += readl(mmcaddr + MMC_RX_JABBER_ERROR);
|
||||
mmc->mmc_rx_undersize_g += readl(mmcaddr + MMC_RX_UNDERSIZE_G);
|
||||
mmc->mmc_rx_oversize_g += readl(mmcaddr + MMC_RX_OVERSIZE_G);
|
||||
mmc->mmc_rx_64_octets_gb += readl(mmcaddr + MMC_RX_64_OCTETS_GB);
|
||||
mmc->mmc_rx_65_to_127_octets_gb +=
|
||||
readl(mmcaddr + MMC_RX_65_TO_127_OCTETS_GB);
|
||||
mmc->mmc_rx_128_to_255_octets_gb +=
|
||||
readl(mmcaddr + MMC_RX_128_TO_255_OCTETS_GB);
|
||||
mmc->mmc_rx_256_to_511_octets_gb +=
|
||||
readl(mmcaddr + MMC_RX_256_TO_511_OCTETS_GB);
|
||||
mmc->mmc_rx_512_to_1023_octets_gb +=
|
||||
readl(mmcaddr + MMC_RX_512_TO_1023_OCTETS_GB);
|
||||
mmc->mmc_rx_1024_to_max_octets_gb +=
|
||||
readl(mmcaddr + MMC_RX_1024_TO_MAX_OCTETS_GB);
|
||||
mmc->mmc_rx_unicast_g += readl(mmcaddr + MMC_RX_UNICAST_G);
|
||||
mmc->mmc_rx_length_error += readl(mmcaddr + MMC_RX_LENGTH_ERROR);
|
||||
mmc->mmc_rx_autofrangetype += readl(mmcaddr + MMC_RX_AUTOFRANGETYPE);
|
||||
mmc->mmc_rx_pause_frames += readl(mmcaddr + MMC_RX_PAUSE_FRAMES);
|
||||
mmc->mmc_rx_fifo_overflow += readl(mmcaddr + MMC_RX_FIFO_OVERFLOW);
|
||||
mmc->mmc_rx_vlan_frames_gb += readl(mmcaddr + MMC_RX_VLAN_FRAMES_GB);
|
||||
mmc->mmc_rx_watchdog_error += readl(mmcaddr + MMC_RX_WATCHDOG_ERROR);
|
||||
mmc->mmc_rx_error += readl(mmcaddr + MMC_RX_ERROR);
|
||||
mmc->mmc_rx_lpi_usec += readl(mmcaddr + MMC_RX_LPI_USEC);
|
||||
mmc->mmc_rx_lpi_tran += readl(mmcaddr + MMC_RX_LPI_TRAN);
|
||||
|
||||
/* IPv4 */
|
||||
mmc->mmc_rx_ipv4_gd += readl(mmcaddr + MMC_RX_IPV4_GD);
|
||||
mmc->mmc_rx_ipv4_hderr += readl(mmcaddr + MMC_RX_IPV4_HDERR);
|
||||
mmc->mmc_rx_ipv4_nopay += readl(mmcaddr + MMC_RX_IPV4_NOPAY);
|
||||
mmc->mmc_rx_ipv4_frag += readl(mmcaddr + MMC_RX_IPV4_FRAG);
|
||||
mmc->mmc_rx_ipv4_udsbl += readl(mmcaddr + MMC_RX_IPV4_UDSBL);
|
||||
|
||||
mmc->mmc_rx_ipv4_gd_octets += readl(mmcaddr + MMC_RX_IPV4_GD_OCTETS);
|
||||
mmc->mmc_rx_ipv4_hderr_octets +=
|
||||
readl(mmcaddr + MMC_RX_IPV4_HDERR_OCTETS);
|
||||
mmc->mmc_rx_ipv4_nopay_octets +=
|
||||
readl(mmcaddr + MMC_RX_IPV4_NOPAY_OCTETS);
|
||||
mmc->mmc_rx_ipv4_frag_octets += readl(mmcaddr +
|
||||
MMC_RX_IPV4_FRAG_OCTETS);
|
||||
mmc->mmc_rx_ipv4_udsbl_octets +=
|
||||
readl(mmcaddr + MMC_RX_IPV4_UDSBL_OCTETS);
|
||||
|
||||
/* IPV6 */
|
||||
mmc->mmc_rx_ipv6_gd_octets += readl(mmcaddr + MMC_RX_IPV6_GD_OCTETS);
|
||||
mmc->mmc_rx_ipv6_hderr_octets +=
|
||||
readl(mmcaddr + MMC_RX_IPV6_HDERR_OCTETS);
|
||||
mmc->mmc_rx_ipv6_nopay_octets +=
|
||||
readl(mmcaddr + MMC_RX_IPV6_NOPAY_OCTETS);
|
||||
|
||||
mmc->mmc_rx_ipv6_gd += readl(mmcaddr + MMC_RX_IPV6_GD);
|
||||
mmc->mmc_rx_ipv6_hderr += readl(mmcaddr + MMC_RX_IPV6_HDERR);
|
||||
mmc->mmc_rx_ipv6_nopay += readl(mmcaddr + MMC_RX_IPV6_NOPAY);
|
||||
|
||||
/* Protocols */
|
||||
mmc->mmc_rx_udp_gd += readl(mmcaddr + MMC_RX_UDP_GD);
|
||||
mmc->mmc_rx_udp_err += readl(mmcaddr + MMC_RX_UDP_ERR);
|
||||
mmc->mmc_rx_tcp_gd += readl(mmcaddr + MMC_RX_TCP_GD);
|
||||
mmc->mmc_rx_tcp_err += readl(mmcaddr + MMC_RX_TCP_ERR);
|
||||
mmc->mmc_rx_icmp_gd += readl(mmcaddr + MMC_RX_ICMP_GD);
|
||||
mmc->mmc_rx_icmp_err += readl(mmcaddr + MMC_RX_ICMP_ERR);
|
||||
|
||||
mmc->mmc_rx_udp_gd_octets += readl(mmcaddr + MMC_RX_UDP_GD_OCTETS);
|
||||
mmc->mmc_rx_udp_err_octets += readl(mmcaddr + MMC_RX_UDP_ERR_OCTETS);
|
||||
mmc->mmc_rx_tcp_gd_octets += readl(mmcaddr + MMC_RX_TCP_GD_OCTETS);
|
||||
mmc->mmc_rx_tcp_err_octets += readl(mmcaddr + MMC_RX_TCP_ERR_OCTETS);
|
||||
mmc->mmc_rx_icmp_gd_octets += readl(mmcaddr + MMC_RX_ICMP_GD_OCTETS);
|
||||
mmc->mmc_rx_icmp_err_octets += readl(mmcaddr + MMC_RX_ICMP_ERR_OCTETS);
|
||||
|
||||
mmc->mmc_tx_fpe_fragment_cntr += readl(mmcaddr + MMC_TX_FPE_FRAG);
|
||||
mmc->mmc_tx_hold_req_cntr += readl(mmcaddr + MMC_TX_HOLD_REQ);
|
||||
mmc->mmc_rx_packet_assembly_err_cntr +=
|
||||
readl(mmcaddr + MMC_RX_PKT_ASSEMBLY_ERR);
|
||||
mmc->mmc_rx_packet_smd_err_cntr += readl(mmcaddr + MMC_RX_PKT_SMD_ERR);
|
||||
mmc->mmc_rx_packet_assembly_ok_cntr +=
|
||||
readl(mmcaddr + MMC_RX_PKT_ASSEMBLY_OK);
|
||||
mmc->mmc_rx_fpe_fragment_cntr += readl(mmcaddr + MMC_RX_FPE_FRAG);
|
||||
}
|
||||
|
||||
const struct stmmac_mmc_ops dwmac_mmc_ops = {
|
||||
.ctrl = dwmac_mmc_ctrl,
|
||||
.intr_all_mask = dwmac_mmc_intr_all_mask,
|
||||
.read = dwmac_mmc_read,
|
||||
};
|
||||
|
||||
static void dwxgmac_mmc_ctrl(void __iomem *mmcaddr, unsigned int mode)
|
||||
{
|
||||
u32 value = readl(mmcaddr + MMC_CNTRL);
|
||||
|
||||
value |= (mode & 0x3F);
|
||||
|
||||
writel(value, mmcaddr + MMC_CNTRL);
|
||||
}
|
||||
|
||||
static void dwxgmac_mmc_intr_all_mask(void __iomem *mmcaddr)
|
||||
{
|
||||
writel(0x0, mmcaddr + MMC_RX_INTR_MASK);
|
||||
writel(0x0, mmcaddr + MMC_TX_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_XGMAC_TX_FPE_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_XGMAC_RX_FPE_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_XGMAC_RX_IPC_INTR_MASK);
|
||||
}
|
||||
|
||||
static void dwxgmac_read_mmc_reg(void __iomem *addr, u32 reg, u32 *dest)
|
||||
{
|
||||
u64 tmp = 0;
|
||||
|
||||
tmp += readl(addr + reg);
|
||||
tmp += ((u64 )readl(addr + reg + 0x4)) << 32;
|
||||
if (tmp > GENMASK(31, 0))
|
||||
*dest = ~0x0;
|
||||
else
|
||||
*dest = *dest + tmp;
|
||||
}
|
||||
|
||||
/* This reads the MAC core counters (if actaully supported).
|
||||
* by default the MMC core is programmed to reset each
|
||||
* counter after a read. So all the field of the mmc struct
|
||||
* have to be incremented.
|
||||
*/
|
||||
static void dwxgmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc)
|
||||
{
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_OCTET_GB,
|
||||
&mmc->mmc_tx_octetcount_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_PKT_GB,
|
||||
&mmc->mmc_tx_framecount_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_BROAD_PKT_G,
|
||||
&mmc->mmc_tx_broadcastframe_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_MULTI_PKT_G,
|
||||
&mmc->mmc_tx_multicastframe_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_64OCT_GB,
|
||||
&mmc->mmc_tx_64_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_65OCT_GB,
|
||||
&mmc->mmc_tx_65_to_127_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_128OCT_GB,
|
||||
&mmc->mmc_tx_128_to_255_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_256OCT_GB,
|
||||
&mmc->mmc_tx_256_to_511_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_512OCT_GB,
|
||||
&mmc->mmc_tx_512_to_1023_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_1024OCT_GB,
|
||||
&mmc->mmc_tx_1024_to_max_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_UNI_PKT_GB,
|
||||
&mmc->mmc_tx_unicast_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_MULTI_PKT_GB,
|
||||
&mmc->mmc_tx_multicast_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_BROAD_PKT_GB,
|
||||
&mmc->mmc_tx_broadcast_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_UNDER,
|
||||
&mmc->mmc_tx_underflow_error);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_OCTET_G,
|
||||
&mmc->mmc_tx_octetcount_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_PKT_G,
|
||||
&mmc->mmc_tx_framecount_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_PAUSE,
|
||||
&mmc->mmc_tx_pause_frame);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_VLAN_PKT_G,
|
||||
&mmc->mmc_tx_vlan_frame_g);
|
||||
mmc->mmc_tx_lpi_usec += readl(mmcaddr + MMC_XGMAC_TX_LPI_USEC);
|
||||
mmc->mmc_tx_lpi_tran += readl(mmcaddr + MMC_XGMAC_TX_LPI_TRAN);
|
||||
|
||||
/* MMC RX counter registers */
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_PKT_GB,
|
||||
&mmc->mmc_rx_framecount_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_OCTET_GB,
|
||||
&mmc->mmc_rx_octetcount_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_OCTET_G,
|
||||
&mmc->mmc_rx_octetcount_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_BROAD_PKT_G,
|
||||
&mmc->mmc_rx_broadcastframe_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_MULTI_PKT_G,
|
||||
&mmc->mmc_rx_multicastframe_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_CRC_ERR,
|
||||
&mmc->mmc_rx_crc_error);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_CRC_ERR,
|
||||
&mmc->mmc_rx_crc_error);
|
||||
mmc->mmc_rx_run_error += readl(mmcaddr + MMC_XGMAC_RX_RUNT_ERR);
|
||||
mmc->mmc_rx_jabber_error += readl(mmcaddr + MMC_XGMAC_RX_JABBER_ERR);
|
||||
mmc->mmc_rx_undersize_g += readl(mmcaddr + MMC_XGMAC_RX_UNDER);
|
||||
mmc->mmc_rx_oversize_g += readl(mmcaddr + MMC_XGMAC_RX_OVER);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_64OCT_GB,
|
||||
&mmc->mmc_rx_64_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_65OCT_GB,
|
||||
&mmc->mmc_rx_65_to_127_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_128OCT_GB,
|
||||
&mmc->mmc_rx_128_to_255_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_256OCT_GB,
|
||||
&mmc->mmc_rx_256_to_511_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_512OCT_GB,
|
||||
&mmc->mmc_rx_512_to_1023_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_1024OCT_GB,
|
||||
&mmc->mmc_rx_1024_to_max_octets_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UNI_PKT_G,
|
||||
&mmc->mmc_rx_unicast_g);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_LENGTH_ERR,
|
||||
&mmc->mmc_rx_length_error);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_RANGE,
|
||||
&mmc->mmc_rx_autofrangetype);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_PAUSE,
|
||||
&mmc->mmc_rx_pause_frames);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_FIFOOVER_PKT,
|
||||
&mmc->mmc_rx_fifo_overflow);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_VLAN_PKT_GB,
|
||||
&mmc->mmc_rx_vlan_frames_gb);
|
||||
mmc->mmc_rx_watchdog_error += readl(mmcaddr + MMC_XGMAC_RX_WATCHDOG_ERR);
|
||||
mmc->mmc_rx_lpi_usec += readl(mmcaddr + MMC_XGMAC_RX_LPI_USEC);
|
||||
mmc->mmc_rx_lpi_tran += readl(mmcaddr + MMC_XGMAC_RX_LPI_TRAN);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_DISCARD_PKT_GB,
|
||||
&mmc->mmc_rx_discard_frames_gb);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_DISCARD_OCT_GB,
|
||||
&mmc->mmc_rx_discard_octets_gb);
|
||||
mmc->mmc_rx_align_err_frames +=
|
||||
readl(mmcaddr + MMC_XGMAC_RX_ALIGN_ERR_PKT);
|
||||
|
||||
mmc->mmc_sgf_pass_fragment_cntr +=
|
||||
readl(mmcaddr + MMC_XGMAC_SGF_PASS_PKT);
|
||||
mmc->mmc_sgf_fail_fragment_cntr +=
|
||||
readl(mmcaddr + MMC_XGMAC_SGF_FAIL_PKT);
|
||||
mmc->mmc_tx_fpe_fragment_cntr += readl(mmcaddr + MMC_XGMAC_TX_FPE_FRAG);
|
||||
mmc->mmc_tx_hold_req_cntr += readl(mmcaddr + MMC_XGMAC_TX_HOLD_REQ);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_GATE_OVERRUN,
|
||||
&mmc->mmc_tx_gate_overrun_cntr);
|
||||
mmc->mmc_rx_packet_assembly_err_cntr +=
|
||||
readl(mmcaddr + MMC_XGMAC_RX_PKT_ASSEMBLY_ERR);
|
||||
mmc->mmc_rx_packet_smd_err_cntr +=
|
||||
readl(mmcaddr + MMC_XGMAC_RX_PKT_SMD_ERR);
|
||||
mmc->mmc_rx_packet_assembly_ok_cntr +=
|
||||
readl(mmcaddr + MMC_XGMAC_RX_PKT_ASSEMBLY_OK);
|
||||
mmc->mmc_rx_fpe_fragment_cntr +=
|
||||
readl(mmcaddr + MMC_XGMAC_RX_FPE_FRAG);
|
||||
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_GD,
|
||||
&mmc->mmc_rx_ipv4_gd);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_HDERR,
|
||||
&mmc->mmc_rx_ipv4_hderr);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_NOPAY,
|
||||
&mmc->mmc_rx_ipv4_nopay);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_FRAG,
|
||||
&mmc->mmc_rx_ipv4_frag);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_UDSBL,
|
||||
&mmc->mmc_rx_ipv4_udsbl);
|
||||
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_GD,
|
||||
&mmc->mmc_rx_ipv6_gd);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_HDERR,
|
||||
&mmc->mmc_rx_ipv6_hderr);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_NOPAY,
|
||||
&mmc->mmc_rx_ipv6_nopay);
|
||||
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UDP_GD,
|
||||
&mmc->mmc_rx_udp_gd);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UDP_ERR,
|
||||
&mmc->mmc_rx_udp_err);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_TCP_GD,
|
||||
&mmc->mmc_rx_tcp_gd);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_TCP_ERR,
|
||||
&mmc->mmc_rx_tcp_err);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_ICMP_GD,
|
||||
&mmc->mmc_rx_icmp_gd);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_ICMP_ERR,
|
||||
&mmc->mmc_rx_icmp_err);
|
||||
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_GD_OCTETS,
|
||||
&mmc->mmc_rx_ipv4_gd_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_HDERR_OCTETS,
|
||||
&mmc->mmc_rx_ipv4_hderr_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_NOPAY_OCTETS,
|
||||
&mmc->mmc_rx_ipv4_nopay_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_FRAG_OCTETS,
|
||||
&mmc->mmc_rx_ipv4_frag_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_UDSBL_OCTETS,
|
||||
&mmc->mmc_rx_ipv4_udsbl_octets);
|
||||
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_GD_OCTETS,
|
||||
&mmc->mmc_rx_ipv6_gd_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_HDERR_OCTETS,
|
||||
&mmc->mmc_rx_ipv6_hderr_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_NOPAY_OCTETS,
|
||||
&mmc->mmc_rx_ipv6_nopay_octets);
|
||||
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UDP_GD_OCTETS,
|
||||
&mmc->mmc_rx_udp_gd_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UDP_ERR_OCTETS,
|
||||
&mmc->mmc_rx_udp_err_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_TCP_GD_OCTETS,
|
||||
&mmc->mmc_rx_tcp_gd_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_TCP_ERR_OCTETS,
|
||||
&mmc->mmc_rx_tcp_err_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_ICMP_GD_OCTETS,
|
||||
&mmc->mmc_rx_icmp_gd_octets);
|
||||
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_ICMP_ERR_OCTETS,
|
||||
&mmc->mmc_rx_icmp_err_octets);
|
||||
}
|
||||
|
||||
const struct stmmac_mmc_ops dwxgmac_mmc_ops = {
|
||||
.ctrl = dwxgmac_mmc_ctrl,
|
||||
.intr_all_mask = dwxgmac_mmc_intr_all_mask,
|
||||
.read = dwxgmac_mmc_read,
|
||||
};
|
||||
|
|
@ -0,0 +1,319 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This contains the functions to handle the normal descriptors.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/stmmac.h>
|
||||
#include "common-6.12-ethercat.h"
|
||||
#include "descs_com-6.12-ethercat.h"
|
||||
|
||||
static int ndesc_get_tx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p, void __iomem *ioaddr)
|
||||
{
|
||||
unsigned int tdes0 = le32_to_cpu(p->des0);
|
||||
unsigned int tdes1 = le32_to_cpu(p->des1);
|
||||
int ret = tx_done;
|
||||
|
||||
/* Get tx owner first */
|
||||
if (unlikely(tdes0 & TDES0_OWN))
|
||||
return tx_dma_own;
|
||||
|
||||
/* Verify tx error by looking at the last segment. */
|
||||
if (likely(!(tdes1 & TDES1_LAST_SEGMENT)))
|
||||
return tx_not_ls;
|
||||
|
||||
if (unlikely(tdes0 & TDES0_ERROR_SUMMARY)) {
|
||||
if (unlikely(tdes0 & TDES0_UNDERFLOW_ERROR)) {
|
||||
x->tx_underflow++;
|
||||
}
|
||||
if (unlikely(tdes0 & TDES0_NO_CARRIER)) {
|
||||
x->tx_carrier++;
|
||||
}
|
||||
if (unlikely(tdes0 & TDES0_LOSS_CARRIER)) {
|
||||
x->tx_losscarrier++;
|
||||
}
|
||||
if (unlikely((tdes0 & TDES0_EXCESSIVE_DEFERRAL) ||
|
||||
(tdes0 & TDES0_EXCESSIVE_COLLISIONS) ||
|
||||
(tdes0 & TDES0_LATE_COLLISION))) {
|
||||
unsigned int collisions;
|
||||
|
||||
collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3;
|
||||
x->tx_collision += collisions;
|
||||
}
|
||||
ret = tx_err;
|
||||
}
|
||||
|
||||
if (tdes0 & TDES0_VLAN_FRAME)
|
||||
x->tx_vlan++;
|
||||
|
||||
if (unlikely(tdes0 & TDES0_DEFERRED))
|
||||
x->tx_deferred++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_len(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des1) & RDES1_BUFFER1_SIZE_MASK);
|
||||
}
|
||||
|
||||
/* This function verifies if each incoming frame has some errors
|
||||
* and, if required, updates the multicast statistics.
|
||||
* In case of success, it returns good_frame because the GMAC device
|
||||
* is supposed to be able to compute the csum in HW. */
|
||||
static int ndesc_get_rx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p)
|
||||
{
|
||||
int ret = good_frame;
|
||||
unsigned int rdes0 = le32_to_cpu(p->des0);
|
||||
|
||||
if (unlikely(rdes0 & RDES0_OWN))
|
||||
return dma_own;
|
||||
|
||||
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
|
||||
x->rx_length++;
|
||||
return discard_frame;
|
||||
}
|
||||
|
||||
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
|
||||
if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR))
|
||||
x->rx_desc++;
|
||||
if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL))
|
||||
x->sa_filter_fail++;
|
||||
if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
|
||||
x->overflow_error++;
|
||||
if (unlikely(rdes0 & RDES0_IPC_CSUM_ERROR))
|
||||
x->ipc_csum_error++;
|
||||
if (unlikely(rdes0 & RDES0_COLLISION)) {
|
||||
x->rx_collision++;
|
||||
}
|
||||
if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
|
||||
x->rx_crc_errors++;
|
||||
}
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(rdes0 & RDES0_DRIBBLING))
|
||||
x->dribbling_bit++;
|
||||
|
||||
if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) {
|
||||
x->rx_length++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(rdes0 & RDES0_MII_ERROR)) {
|
||||
x->rx_mii++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
if (rdes0 & RDES0_VLAN_TAG)
|
||||
x->vlan_tag++;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
|
||||
int end, int bfsize)
|
||||
{
|
||||
int bfsize1;
|
||||
|
||||
p->des0 |= cpu_to_le32(RDES0_OWN);
|
||||
|
||||
bfsize1 = min(bfsize, BUF_SIZE_2KiB - 1);
|
||||
p->des1 |= cpu_to_le32(bfsize1 & RDES1_BUFFER1_SIZE_MASK);
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ndesc_rx_set_on_chain(p, end);
|
||||
else
|
||||
ndesc_rx_set_on_ring(p, end, bfsize);
|
||||
|
||||
if (disable_rx_ic)
|
||||
p->des1 |= cpu_to_le32(RDES1_DISABLE_IC);
|
||||
}
|
||||
|
||||
static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
|
||||
{
|
||||
p->des0 &= cpu_to_le32(~TDES0_OWN);
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ndesc_tx_set_on_chain(p);
|
||||
else
|
||||
ndesc_end_tx_desc_on_ring(p, end);
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des0) & TDES0_OWN) >> 31;
|
||||
}
|
||||
|
||||
static void ndesc_set_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(TDES0_OWN);
|
||||
}
|
||||
|
||||
static void ndesc_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(RDES0_OWN);
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_ls(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des1) & TDES1_LAST_SEGMENT) >> 30;
|
||||
}
|
||||
|
||||
static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
|
||||
{
|
||||
int ter = (le32_to_cpu(p->des1) & TDES1_END_RING) >> 25;
|
||||
|
||||
memset(p, 0, offsetof(struct dma_desc, des2));
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ndesc_tx_set_on_chain(p);
|
||||
else
|
||||
ndesc_end_tx_desc_on_ring(p, ter);
|
||||
}
|
||||
|
||||
static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
bool csum_flag, int mode, bool tx_own,
|
||||
bool ls, unsigned int tot_pkt_len)
|
||||
{
|
||||
unsigned int tdes1 = le32_to_cpu(p->des1);
|
||||
|
||||
if (is_fs)
|
||||
tdes1 |= TDES1_FIRST_SEGMENT;
|
||||
else
|
||||
tdes1 &= ~TDES1_FIRST_SEGMENT;
|
||||
|
||||
if (likely(csum_flag))
|
||||
tdes1 |= (TX_CIC_FULL) << TDES1_CHECKSUM_INSERTION_SHIFT;
|
||||
else
|
||||
tdes1 &= ~(TX_CIC_FULL << TDES1_CHECKSUM_INSERTION_SHIFT);
|
||||
|
||||
if (ls)
|
||||
tdes1 |= TDES1_LAST_SEGMENT;
|
||||
|
||||
p->des1 = cpu_to_le32(tdes1);
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
norm_set_tx_desc_len_on_chain(p, len);
|
||||
else
|
||||
norm_set_tx_desc_len_on_ring(p, len);
|
||||
|
||||
if (tx_own)
|
||||
p->des0 |= cpu_to_le32(TDES0_OWN);
|
||||
}
|
||||
|
||||
static void ndesc_set_tx_ic(struct dma_desc *p)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(TDES1_INTERRUPT);
|
||||
}
|
||||
|
||||
static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
|
||||
{
|
||||
unsigned int csum = 0;
|
||||
|
||||
/* The type-1 checksum offload engines append the checksum at
|
||||
* the end of frame and the two bytes of checksum are added in
|
||||
* the length.
|
||||
* Adjust for that in the framelen for type-1 checksum offload
|
||||
* engines
|
||||
*/
|
||||
if (rx_coe_type == STMMAC_RX_COE_TYPE1)
|
||||
csum = 2;
|
||||
|
||||
return (((le32_to_cpu(p->des0) & RDES0_FRAME_LEN_MASK)
|
||||
>> RDES0_FRAME_LEN_SHIFT) -
|
||||
csum);
|
||||
|
||||
}
|
||||
|
||||
static void ndesc_enable_tx_timestamp(struct dma_desc *p)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(TDES1_TIME_STAMP_ENABLE);
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des0) & TDES0_TIME_STAMP_STATUS) >> 17;
|
||||
}
|
||||
|
||||
static void ndesc_get_timestamp(void *desc, u32 ats, u64 *ts)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
u64 ns;
|
||||
|
||||
ns = le32_to_cpu(p->des2);
|
||||
/* convert high/sec time stamp value to nanosecond */
|
||||
ns += le32_to_cpu(p->des3) * 1000000000ULL;
|
||||
|
||||
*ts = ns;
|
||||
}
|
||||
|
||||
static int ndesc_get_rx_timestamp_status(void *desc, void *next_desc, u32 ats)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
|
||||
if ((le32_to_cpu(p->des2) == 0xffffffff) &&
|
||||
(le32_to_cpu(p->des3) == 0xffffffff))
|
||||
/* timestamp is corrupted, hence don't store it */
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void ndesc_display_ring(void *head, unsigned int size, bool rx,
|
||||
dma_addr_t dma_rx_phy, unsigned int desc_size)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)head;
|
||||
dma_addr_t dma_addr;
|
||||
int i;
|
||||
|
||||
pr_info("%s descriptor ring:\n", rx ? "RX" : "TX");
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
u64 x;
|
||||
dma_addr = dma_rx_phy + i * sizeof(*p);
|
||||
|
||||
x = *(u64 *)p;
|
||||
pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x",
|
||||
i, &dma_addr,
|
||||
(unsigned int)x, (unsigned int)(x >> 32),
|
||||
p->des2, p->des3);
|
||||
p++;
|
||||
}
|
||||
pr_info("\n");
|
||||
}
|
||||
|
||||
static void ndesc_set_addr(struct dma_desc *p, dma_addr_t addr)
|
||||
{
|
||||
p->des2 = cpu_to_le32(addr);
|
||||
}
|
||||
|
||||
static void ndesc_clear(struct dma_desc *p)
|
||||
{
|
||||
p->des2 = 0;
|
||||
}
|
||||
|
||||
const struct stmmac_desc_ops ndesc_ops = {
|
||||
.tx_status = ndesc_get_tx_status,
|
||||
.rx_status = ndesc_get_rx_status,
|
||||
.get_tx_len = ndesc_get_tx_len,
|
||||
.init_rx_desc = ndesc_init_rx_desc,
|
||||
.init_tx_desc = ndesc_init_tx_desc,
|
||||
.get_tx_owner = ndesc_get_tx_owner,
|
||||
.release_tx_desc = ndesc_release_tx_desc,
|
||||
.prepare_tx_desc = ndesc_prepare_tx_desc,
|
||||
.set_tx_ic = ndesc_set_tx_ic,
|
||||
.get_tx_ls = ndesc_get_tx_ls,
|
||||
.set_tx_owner = ndesc_set_tx_owner,
|
||||
.set_rx_owner = ndesc_set_rx_owner,
|
||||
.get_rx_frame_len = ndesc_get_rx_frame_len,
|
||||
.enable_tx_timestamp = ndesc_enable_tx_timestamp,
|
||||
.get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
|
||||
.get_timestamp = ndesc_get_timestamp,
|
||||
.get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
|
||||
.display_ring = ndesc_display_ring,
|
||||
.set_addr = ndesc_set_addr,
|
||||
.clear = ndesc_clear,
|
||||
};
|
||||
|
|
@ -0,0 +1,319 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This contains the functions to handle the normal descriptors.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/stmmac.h>
|
||||
#include "common.h"
|
||||
#include "descs_com.h"
|
||||
|
||||
static int ndesc_get_tx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p, void __iomem *ioaddr)
|
||||
{
|
||||
unsigned int tdes0 = le32_to_cpu(p->des0);
|
||||
unsigned int tdes1 = le32_to_cpu(p->des1);
|
||||
int ret = tx_done;
|
||||
|
||||
/* Get tx owner first */
|
||||
if (unlikely(tdes0 & TDES0_OWN))
|
||||
return tx_dma_own;
|
||||
|
||||
/* Verify tx error by looking at the last segment. */
|
||||
if (likely(!(tdes1 & TDES1_LAST_SEGMENT)))
|
||||
return tx_not_ls;
|
||||
|
||||
if (unlikely(tdes0 & TDES0_ERROR_SUMMARY)) {
|
||||
if (unlikely(tdes0 & TDES0_UNDERFLOW_ERROR)) {
|
||||
x->tx_underflow++;
|
||||
}
|
||||
if (unlikely(tdes0 & TDES0_NO_CARRIER)) {
|
||||
x->tx_carrier++;
|
||||
}
|
||||
if (unlikely(tdes0 & TDES0_LOSS_CARRIER)) {
|
||||
x->tx_losscarrier++;
|
||||
}
|
||||
if (unlikely((tdes0 & TDES0_EXCESSIVE_DEFERRAL) ||
|
||||
(tdes0 & TDES0_EXCESSIVE_COLLISIONS) ||
|
||||
(tdes0 & TDES0_LATE_COLLISION))) {
|
||||
unsigned int collisions;
|
||||
|
||||
collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3;
|
||||
x->tx_collision += collisions;
|
||||
}
|
||||
ret = tx_err;
|
||||
}
|
||||
|
||||
if (tdes0 & TDES0_VLAN_FRAME)
|
||||
x->tx_vlan++;
|
||||
|
||||
if (unlikely(tdes0 & TDES0_DEFERRED))
|
||||
x->tx_deferred++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_len(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des1) & RDES1_BUFFER1_SIZE_MASK);
|
||||
}
|
||||
|
||||
/* This function verifies if each incoming frame has some errors
|
||||
* and, if required, updates the multicast statistics.
|
||||
* In case of success, it returns good_frame because the GMAC device
|
||||
* is supposed to be able to compute the csum in HW. */
|
||||
static int ndesc_get_rx_status(struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p)
|
||||
{
|
||||
int ret = good_frame;
|
||||
unsigned int rdes0 = le32_to_cpu(p->des0);
|
||||
|
||||
if (unlikely(rdes0 & RDES0_OWN))
|
||||
return dma_own;
|
||||
|
||||
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
|
||||
x->rx_length++;
|
||||
return discard_frame;
|
||||
}
|
||||
|
||||
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
|
||||
if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR))
|
||||
x->rx_desc++;
|
||||
if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL))
|
||||
x->sa_filter_fail++;
|
||||
if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
|
||||
x->overflow_error++;
|
||||
if (unlikely(rdes0 & RDES0_IPC_CSUM_ERROR))
|
||||
x->ipc_csum_error++;
|
||||
if (unlikely(rdes0 & RDES0_COLLISION)) {
|
||||
x->rx_collision++;
|
||||
}
|
||||
if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
|
||||
x->rx_crc_errors++;
|
||||
}
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(rdes0 & RDES0_DRIBBLING))
|
||||
x->dribbling_bit++;
|
||||
|
||||
if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) {
|
||||
x->rx_length++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(rdes0 & RDES0_MII_ERROR)) {
|
||||
x->rx_mii++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
if (rdes0 & RDES0_VLAN_TAG)
|
||||
x->vlan_tag++;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
|
||||
int end, int bfsize)
|
||||
{
|
||||
int bfsize1;
|
||||
|
||||
p->des0 |= cpu_to_le32(RDES0_OWN);
|
||||
|
||||
bfsize1 = min(bfsize, BUF_SIZE_2KiB - 1);
|
||||
p->des1 |= cpu_to_le32(bfsize1 & RDES1_BUFFER1_SIZE_MASK);
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ndesc_rx_set_on_chain(p, end);
|
||||
else
|
||||
ndesc_rx_set_on_ring(p, end, bfsize);
|
||||
|
||||
if (disable_rx_ic)
|
||||
p->des1 |= cpu_to_le32(RDES1_DISABLE_IC);
|
||||
}
|
||||
|
||||
static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
|
||||
{
|
||||
p->des0 &= cpu_to_le32(~TDES0_OWN);
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ndesc_tx_set_on_chain(p);
|
||||
else
|
||||
ndesc_end_tx_desc_on_ring(p, end);
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des0) & TDES0_OWN) >> 31;
|
||||
}
|
||||
|
||||
static void ndesc_set_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(TDES0_OWN);
|
||||
}
|
||||
|
||||
static void ndesc_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
|
||||
{
|
||||
p->des0 |= cpu_to_le32(RDES0_OWN);
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_ls(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des1) & TDES1_LAST_SEGMENT) >> 30;
|
||||
}
|
||||
|
||||
static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
|
||||
{
|
||||
int ter = (le32_to_cpu(p->des1) & TDES1_END_RING) >> 25;
|
||||
|
||||
memset(p, 0, offsetof(struct dma_desc, des2));
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ndesc_tx_set_on_chain(p);
|
||||
else
|
||||
ndesc_end_tx_desc_on_ring(p, ter);
|
||||
}
|
||||
|
||||
static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
bool csum_flag, int mode, bool tx_own,
|
||||
bool ls, unsigned int tot_pkt_len)
|
||||
{
|
||||
unsigned int tdes1 = le32_to_cpu(p->des1);
|
||||
|
||||
if (is_fs)
|
||||
tdes1 |= TDES1_FIRST_SEGMENT;
|
||||
else
|
||||
tdes1 &= ~TDES1_FIRST_SEGMENT;
|
||||
|
||||
if (likely(csum_flag))
|
||||
tdes1 |= (TX_CIC_FULL) << TDES1_CHECKSUM_INSERTION_SHIFT;
|
||||
else
|
||||
tdes1 &= ~(TX_CIC_FULL << TDES1_CHECKSUM_INSERTION_SHIFT);
|
||||
|
||||
if (ls)
|
||||
tdes1 |= TDES1_LAST_SEGMENT;
|
||||
|
||||
p->des1 = cpu_to_le32(tdes1);
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
norm_set_tx_desc_len_on_chain(p, len);
|
||||
else
|
||||
norm_set_tx_desc_len_on_ring(p, len);
|
||||
|
||||
if (tx_own)
|
||||
p->des0 |= cpu_to_le32(TDES0_OWN);
|
||||
}
|
||||
|
||||
static void ndesc_set_tx_ic(struct dma_desc *p)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(TDES1_INTERRUPT);
|
||||
}
|
||||
|
||||
static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
|
||||
{
|
||||
unsigned int csum = 0;
|
||||
|
||||
/* The type-1 checksum offload engines append the checksum at
|
||||
* the end of frame and the two bytes of checksum are added in
|
||||
* the length.
|
||||
* Adjust for that in the framelen for type-1 checksum offload
|
||||
* engines
|
||||
*/
|
||||
if (rx_coe_type == STMMAC_RX_COE_TYPE1)
|
||||
csum = 2;
|
||||
|
||||
return (((le32_to_cpu(p->des0) & RDES0_FRAME_LEN_MASK)
|
||||
>> RDES0_FRAME_LEN_SHIFT) -
|
||||
csum);
|
||||
|
||||
}
|
||||
|
||||
static void ndesc_enable_tx_timestamp(struct dma_desc *p)
|
||||
{
|
||||
p->des1 |= cpu_to_le32(TDES1_TIME_STAMP_ENABLE);
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
|
||||
{
|
||||
return (le32_to_cpu(p->des0) & TDES0_TIME_STAMP_STATUS) >> 17;
|
||||
}
|
||||
|
||||
static void ndesc_get_timestamp(void *desc, u32 ats, u64 *ts)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
u64 ns;
|
||||
|
||||
ns = le32_to_cpu(p->des2);
|
||||
/* convert high/sec time stamp value to nanosecond */
|
||||
ns += le32_to_cpu(p->des3) * 1000000000ULL;
|
||||
|
||||
*ts = ns;
|
||||
}
|
||||
|
||||
static int ndesc_get_rx_timestamp_status(void *desc, void *next_desc, u32 ats)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
|
||||
if ((le32_to_cpu(p->des2) == 0xffffffff) &&
|
||||
(le32_to_cpu(p->des3) == 0xffffffff))
|
||||
/* timestamp is corrupted, hence don't store it */
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void ndesc_display_ring(void *head, unsigned int size, bool rx,
|
||||
dma_addr_t dma_rx_phy, unsigned int desc_size)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)head;
|
||||
dma_addr_t dma_addr;
|
||||
int i;
|
||||
|
||||
pr_info("%s descriptor ring:\n", rx ? "RX" : "TX");
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
u64 x;
|
||||
dma_addr = dma_rx_phy + i * sizeof(*p);
|
||||
|
||||
x = *(u64 *)p;
|
||||
pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x",
|
||||
i, &dma_addr,
|
||||
(unsigned int)x, (unsigned int)(x >> 32),
|
||||
p->des2, p->des3);
|
||||
p++;
|
||||
}
|
||||
pr_info("\n");
|
||||
}
|
||||
|
||||
static void ndesc_set_addr(struct dma_desc *p, dma_addr_t addr)
|
||||
{
|
||||
p->des2 = cpu_to_le32(addr);
|
||||
}
|
||||
|
||||
static void ndesc_clear(struct dma_desc *p)
|
||||
{
|
||||
p->des2 = 0;
|
||||
}
|
||||
|
||||
const struct stmmac_desc_ops ndesc_ops = {
|
||||
.tx_status = ndesc_get_tx_status,
|
||||
.rx_status = ndesc_get_rx_status,
|
||||
.get_tx_len = ndesc_get_tx_len,
|
||||
.init_rx_desc = ndesc_init_rx_desc,
|
||||
.init_tx_desc = ndesc_init_tx_desc,
|
||||
.get_tx_owner = ndesc_get_tx_owner,
|
||||
.release_tx_desc = ndesc_release_tx_desc,
|
||||
.prepare_tx_desc = ndesc_prepare_tx_desc,
|
||||
.set_tx_ic = ndesc_set_tx_ic,
|
||||
.get_tx_ls = ndesc_get_tx_ls,
|
||||
.set_tx_owner = ndesc_set_tx_owner,
|
||||
.set_rx_owner = ndesc_set_rx_owner,
|
||||
.get_rx_frame_len = ndesc_get_rx_frame_len,
|
||||
.enable_tx_timestamp = ndesc_enable_tx_timestamp,
|
||||
.get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
|
||||
.get_timestamp = ndesc_get_timestamp,
|
||||
.get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
|
||||
.display_ring = ndesc_display_ring,
|
||||
.set_addr = ndesc_set_addr,
|
||||
.clear = ndesc_clear,
|
||||
};
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
Specialised functions for managing Ring mode
|
||||
|
||||
Copyright(C) 2011 STMicroelectronics Ltd
|
||||
|
||||
It defines all the functions used to handle the normal/enhanced
|
||||
descriptors in case of the DMA is configured to work in chained or
|
||||
in ring mode.
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
|
||||
static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
|
||||
int csum)
|
||||
{
|
||||
unsigned int nopaged_len = skb_headlen(skb);
|
||||
struct stmmac_priv *priv = tx_q->priv_data;
|
||||
unsigned int entry = tx_q->cur_tx;
|
||||
unsigned int bmax, len, des2;
|
||||
struct dma_desc *desc;
|
||||
|
||||
if (priv->extend_desc)
|
||||
desc = (struct dma_desc *)(tx_q->dma_etx + entry);
|
||||
else
|
||||
desc = tx_q->dma_tx + entry;
|
||||
|
||||
if (priv->plat->enh_desc)
|
||||
bmax = BUF_SIZE_8KiB;
|
||||
else
|
||||
bmax = BUF_SIZE_2KiB;
|
||||
|
||||
len = nopaged_len - bmax;
|
||||
|
||||
if (nopaged_len > BUF_SIZE_8KiB) {
|
||||
|
||||
des2 = dma_map_single(priv->device, skb->data, bmax,
|
||||
DMA_TO_DEVICE);
|
||||
desc->des2 = cpu_to_le32(des2);
|
||||
if (dma_mapping_error(priv->device, des2))
|
||||
return -1;
|
||||
|
||||
tx_q->tx_skbuff_dma[entry].buf = des2;
|
||||
tx_q->tx_skbuff_dma[entry].len = bmax;
|
||||
tx_q->tx_skbuff_dma[entry].is_jumbo = true;
|
||||
|
||||
desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
|
||||
stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum,
|
||||
STMMAC_RING_MODE, 0, false, skb->len);
|
||||
tx_q->tx_skbuff[entry] = NULL;
|
||||
entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
|
||||
|
||||
if (priv->extend_desc)
|
||||
desc = (struct dma_desc *)(tx_q->dma_etx + entry);
|
||||
else
|
||||
desc = tx_q->dma_tx + entry;
|
||||
|
||||
des2 = dma_map_single(priv->device, skb->data + bmax, len,
|
||||
DMA_TO_DEVICE);
|
||||
desc->des2 = cpu_to_le32(des2);
|
||||
if (dma_mapping_error(priv->device, des2))
|
||||
return -1;
|
||||
tx_q->tx_skbuff_dma[entry].buf = des2;
|
||||
tx_q->tx_skbuff_dma[entry].len = len;
|
||||
tx_q->tx_skbuff_dma[entry].is_jumbo = true;
|
||||
|
||||
desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
|
||||
stmmac_prepare_tx_desc(priv, desc, 0, len, csum,
|
||||
STMMAC_RING_MODE, 1, !skb_is_nonlinear(skb),
|
||||
skb->len);
|
||||
} else {
|
||||
des2 = dma_map_single(priv->device, skb->data,
|
||||
nopaged_len, DMA_TO_DEVICE);
|
||||
desc->des2 = cpu_to_le32(des2);
|
||||
if (dma_mapping_error(priv->device, des2))
|
||||
return -1;
|
||||
tx_q->tx_skbuff_dma[entry].buf = des2;
|
||||
tx_q->tx_skbuff_dma[entry].len = nopaged_len;
|
||||
tx_q->tx_skbuff_dma[entry].is_jumbo = true;
|
||||
desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
|
||||
stmmac_prepare_tx_desc(priv, desc, 1, nopaged_len, csum,
|
||||
STMMAC_RING_MODE, 0, !skb_is_nonlinear(skb),
|
||||
skb->len);
|
||||
}
|
||||
|
||||
tx_q->cur_tx = entry;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static unsigned int is_jumbo_frm(int len, int enh_desc)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
if (len >= BUF_SIZE_4KiB)
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void refill_desc3(struct stmmac_rx_queue *rx_q, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = rx_q->priv_data;
|
||||
|
||||
/* Fill DES3 in case of RING mode */
|
||||
if (priv->dma_conf.dma_buf_sz == BUF_SIZE_16KiB)
|
||||
p->des3 = cpu_to_le32(le32_to_cpu(p->des2) + BUF_SIZE_8KiB);
|
||||
}
|
||||
|
||||
/* In ring mode we need to fill the desc3 because it is used as buffer */
|
||||
static void init_desc3(struct dma_desc *p)
|
||||
{
|
||||
p->des3 = cpu_to_le32(le32_to_cpu(p->des2) + BUF_SIZE_8KiB);
|
||||
}
|
||||
|
||||
static void clean_desc3(struct stmmac_tx_queue *tx_q, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = tx_q->priv_data;
|
||||
unsigned int entry = tx_q->dirty_tx;
|
||||
|
||||
/* des3 is only used for jumbo frames tx or time stamping */
|
||||
if (unlikely(tx_q->tx_skbuff_dma[entry].is_jumbo ||
|
||||
(tx_q->tx_skbuff_dma[entry].last_segment &&
|
||||
!priv->extend_desc && priv->hwts_tx_en)))
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static int set_16kib_bfsize(int mtu)
|
||||
{
|
||||
int ret = 0;
|
||||
if (unlikely(mtu > BUF_SIZE_8KiB))
|
||||
ret = BUF_SIZE_16KiB;
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct stmmac_mode_ops ring_mode_ops = {
|
||||
.is_jumbo_frm = is_jumbo_frm,
|
||||
.jumbo_frm = jumbo_frm,
|
||||
.refill_desc3 = refill_desc3,
|
||||
.init_desc3 = init_desc3,
|
||||
.clean_desc3 = clean_desc3,
|
||||
.set_16kib_bfsize = set_16kib_bfsize,
|
||||
};
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
Specialised functions for managing Ring mode
|
||||
|
||||
Copyright(C) 2011 STMicroelectronics Ltd
|
||||
|
||||
It defines all the functions used to handle the normal/enhanced
|
||||
descriptors in case of the DMA is configured to work in chained or
|
||||
in ring mode.
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include "stmmac.h"
|
||||
|
||||
static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
|
||||
int csum)
|
||||
{
|
||||
unsigned int nopaged_len = skb_headlen(skb);
|
||||
struct stmmac_priv *priv = tx_q->priv_data;
|
||||
unsigned int entry = tx_q->cur_tx;
|
||||
unsigned int bmax, len, des2;
|
||||
struct dma_desc *desc;
|
||||
|
||||
if (priv->extend_desc)
|
||||
desc = (struct dma_desc *)(tx_q->dma_etx + entry);
|
||||
else
|
||||
desc = tx_q->dma_tx + entry;
|
||||
|
||||
if (priv->plat->enh_desc)
|
||||
bmax = BUF_SIZE_8KiB;
|
||||
else
|
||||
bmax = BUF_SIZE_2KiB;
|
||||
|
||||
len = nopaged_len - bmax;
|
||||
|
||||
if (nopaged_len > BUF_SIZE_8KiB) {
|
||||
|
||||
des2 = dma_map_single(priv->device, skb->data, bmax,
|
||||
DMA_TO_DEVICE);
|
||||
desc->des2 = cpu_to_le32(des2);
|
||||
if (dma_mapping_error(priv->device, des2))
|
||||
return -1;
|
||||
|
||||
tx_q->tx_skbuff_dma[entry].buf = des2;
|
||||
tx_q->tx_skbuff_dma[entry].len = bmax;
|
||||
tx_q->tx_skbuff_dma[entry].is_jumbo = true;
|
||||
|
||||
desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
|
||||
stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum,
|
||||
STMMAC_RING_MODE, 0, false, skb->len);
|
||||
tx_q->tx_skbuff[entry] = NULL;
|
||||
entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
|
||||
|
||||
if (priv->extend_desc)
|
||||
desc = (struct dma_desc *)(tx_q->dma_etx + entry);
|
||||
else
|
||||
desc = tx_q->dma_tx + entry;
|
||||
|
||||
des2 = dma_map_single(priv->device, skb->data + bmax, len,
|
||||
DMA_TO_DEVICE);
|
||||
desc->des2 = cpu_to_le32(des2);
|
||||
if (dma_mapping_error(priv->device, des2))
|
||||
return -1;
|
||||
tx_q->tx_skbuff_dma[entry].buf = des2;
|
||||
tx_q->tx_skbuff_dma[entry].len = len;
|
||||
tx_q->tx_skbuff_dma[entry].is_jumbo = true;
|
||||
|
||||
desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
|
||||
stmmac_prepare_tx_desc(priv, desc, 0, len, csum,
|
||||
STMMAC_RING_MODE, 1, !skb_is_nonlinear(skb),
|
||||
skb->len);
|
||||
} else {
|
||||
des2 = dma_map_single(priv->device, skb->data,
|
||||
nopaged_len, DMA_TO_DEVICE);
|
||||
desc->des2 = cpu_to_le32(des2);
|
||||
if (dma_mapping_error(priv->device, des2))
|
||||
return -1;
|
||||
tx_q->tx_skbuff_dma[entry].buf = des2;
|
||||
tx_q->tx_skbuff_dma[entry].len = nopaged_len;
|
||||
tx_q->tx_skbuff_dma[entry].is_jumbo = true;
|
||||
desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
|
||||
stmmac_prepare_tx_desc(priv, desc, 1, nopaged_len, csum,
|
||||
STMMAC_RING_MODE, 0, !skb_is_nonlinear(skb),
|
||||
skb->len);
|
||||
}
|
||||
|
||||
tx_q->cur_tx = entry;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static unsigned int is_jumbo_frm(int len, int enh_desc)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
if (len >= BUF_SIZE_4KiB)
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void refill_desc3(struct stmmac_rx_queue *rx_q, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = rx_q->priv_data;
|
||||
|
||||
/* Fill DES3 in case of RING mode */
|
||||
if (priv->dma_conf.dma_buf_sz == BUF_SIZE_16KiB)
|
||||
p->des3 = cpu_to_le32(le32_to_cpu(p->des2) + BUF_SIZE_8KiB);
|
||||
}
|
||||
|
||||
/* In ring mode we need to fill the desc3 because it is used as buffer */
|
||||
static void init_desc3(struct dma_desc *p)
|
||||
{
|
||||
p->des3 = cpu_to_le32(le32_to_cpu(p->des2) + BUF_SIZE_8KiB);
|
||||
}
|
||||
|
||||
static void clean_desc3(struct stmmac_tx_queue *tx_q, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = tx_q->priv_data;
|
||||
unsigned int entry = tx_q->dirty_tx;
|
||||
|
||||
/* des3 is only used for jumbo frames tx or time stamping */
|
||||
if (unlikely(tx_q->tx_skbuff_dma[entry].is_jumbo ||
|
||||
(tx_q->tx_skbuff_dma[entry].last_segment &&
|
||||
!priv->extend_desc && priv->hwts_tx_en)))
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static int set_16kib_bfsize(int mtu)
|
||||
{
|
||||
int ret = 0;
|
||||
if (unlikely(mtu > BUF_SIZE_8KiB))
|
||||
ret = BUF_SIZE_16KiB;
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct stmmac_mode_ops ring_mode_ops = {
|
||||
.is_jumbo_frm = is_jumbo_frm,
|
||||
.jumbo_frm = jumbo_frm,
|
||||
.refill_desc3 = refill_desc3,
|
||||
.init_desc3 = init_desc3,
|
||||
.clean_desc3 = clean_desc3,
|
||||
.set_16kib_bfsize = set_16kib_bfsize,
|
||||
};
|
||||
|
|
@ -0,0 +1,490 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __STMMAC_H__
|
||||
#define __STMMAC_H__
|
||||
|
||||
#define STMMAC_RESOURCE_NAME "ec_stmmaceth"
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/stmmac.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/pci.h>
|
||||
#include "common-6.12-ethercat.h"
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/reset.h>
|
||||
#include <net/page_pool/types.h>
|
||||
#include <net/xdp.h>
|
||||
#include <uapi/linux/bpf.h>
|
||||
#include <linux/irq_work.h>
|
||||
|
||||
/* EtherCAT header file */
|
||||
#include "../ecdev.h"
|
||||
|
||||
int __cold stmmac_init(void);
|
||||
void __cold stmmac_exit(void);
|
||||
|
||||
struct stmmac_resources {
|
||||
void __iomem *addr;
|
||||
u8 mac[ETH_ALEN];
|
||||
int wol_irq;
|
||||
int lpi_irq;
|
||||
int irq;
|
||||
int sfty_irq;
|
||||
int sfty_ce_irq;
|
||||
int sfty_ue_irq;
|
||||
int rx_irq[MTL_MAX_RX_QUEUES];
|
||||
int tx_irq[MTL_MAX_TX_QUEUES];
|
||||
};
|
||||
|
||||
enum stmmac_txbuf_type {
|
||||
STMMAC_TXBUF_T_SKB,
|
||||
STMMAC_TXBUF_T_XDP_TX,
|
||||
STMMAC_TXBUF_T_XDP_NDO,
|
||||
STMMAC_TXBUF_T_XSK_TX,
|
||||
};
|
||||
|
||||
struct stmmac_tx_info {
|
||||
dma_addr_t buf;
|
||||
bool map_as_page;
|
||||
unsigned len;
|
||||
bool last_segment;
|
||||
bool is_jumbo;
|
||||
enum stmmac_txbuf_type buf_type;
|
||||
struct xsk_tx_metadata_compl xsk_meta;
|
||||
};
|
||||
|
||||
#define STMMAC_TBS_AVAIL BIT(0)
|
||||
#define STMMAC_TBS_EN BIT(1)
|
||||
|
||||
/* Frequently used values are kept adjacent for cache effect */
|
||||
struct stmmac_tx_queue {
|
||||
u32 tx_count_frames;
|
||||
int tbs;
|
||||
struct hrtimer txtimer;
|
||||
u32 queue_index;
|
||||
struct stmmac_priv *priv_data;
|
||||
struct dma_extended_desc *dma_etx ____cacheline_aligned_in_smp;
|
||||
struct dma_edesc *dma_entx;
|
||||
struct dma_desc *dma_tx;
|
||||
union {
|
||||
struct sk_buff **tx_skbuff;
|
||||
struct xdp_frame **xdpf;
|
||||
};
|
||||
struct stmmac_tx_info *tx_skbuff_dma;
|
||||
struct xsk_buff_pool *xsk_pool;
|
||||
u32 xsk_frames_done;
|
||||
unsigned int cur_tx;
|
||||
unsigned int dirty_tx;
|
||||
dma_addr_t dma_tx_phy;
|
||||
dma_addr_t tx_tail_addr;
|
||||
u32 mss;
|
||||
};
|
||||
|
||||
struct stmmac_rx_buffer {
|
||||
union {
|
||||
struct {
|
||||
struct page *page;
|
||||
dma_addr_t addr;
|
||||
__u32 page_offset;
|
||||
};
|
||||
struct xdp_buff *xdp;
|
||||
};
|
||||
struct page *sec_page;
|
||||
dma_addr_t sec_addr;
|
||||
};
|
||||
|
||||
struct stmmac_xdp_buff {
|
||||
struct xdp_buff xdp;
|
||||
struct stmmac_priv *priv;
|
||||
struct dma_desc *desc;
|
||||
struct dma_desc *ndesc;
|
||||
};
|
||||
|
||||
struct stmmac_metadata_request {
|
||||
struct stmmac_priv *priv;
|
||||
struct dma_desc *tx_desc;
|
||||
bool *set_ic;
|
||||
};
|
||||
|
||||
struct stmmac_xsk_tx_complete {
|
||||
struct stmmac_priv *priv;
|
||||
struct dma_desc *desc;
|
||||
};
|
||||
|
||||
struct stmmac_rx_queue {
|
||||
u32 rx_count_frames;
|
||||
u32 queue_index;
|
||||
struct xdp_rxq_info xdp_rxq;
|
||||
struct xsk_buff_pool *xsk_pool;
|
||||
struct page_pool *page_pool;
|
||||
struct stmmac_rx_buffer *buf_pool;
|
||||
struct stmmac_priv *priv_data;
|
||||
struct dma_extended_desc *dma_erx;
|
||||
struct dma_desc *dma_rx ____cacheline_aligned_in_smp;
|
||||
unsigned int cur_rx;
|
||||
unsigned int dirty_rx;
|
||||
unsigned int buf_alloc_num;
|
||||
u32 rx_zeroc_thresh;
|
||||
dma_addr_t dma_rx_phy;
|
||||
u32 rx_tail_addr;
|
||||
unsigned int state_saved;
|
||||
struct {
|
||||
struct sk_buff *skb;
|
||||
unsigned int len;
|
||||
unsigned int error;
|
||||
} state;
|
||||
};
|
||||
|
||||
struct stmmac_channel {
|
||||
struct napi_struct rx_napi ____cacheline_aligned_in_smp;
|
||||
struct napi_struct tx_napi ____cacheline_aligned_in_smp;
|
||||
struct napi_struct rxtx_napi ____cacheline_aligned_in_smp;
|
||||
struct stmmac_priv *priv_data;
|
||||
spinlock_t lock;
|
||||
u32 index;
|
||||
};
|
||||
|
||||
/* FPE link-partner hand-shaking mPacket type */
|
||||
enum stmmac_mpacket_type {
|
||||
MPACKET_VERIFY = 0,
|
||||
MPACKET_RESPONSE = 1,
|
||||
};
|
||||
|
||||
#define STMMAC_FPE_MM_MAX_VERIFY_RETRIES 3
|
||||
#define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS 128
|
||||
|
||||
struct stmmac_fpe_cfg {
|
||||
/* Serialize access to MAC Merge state between ethtool requests
|
||||
* and link state updates.
|
||||
*/
|
||||
spinlock_t lock;
|
||||
|
||||
u32 fpe_csr; /* MAC_FPE_CTRL_STS reg cache */
|
||||
|
||||
enum ethtool_mm_verify_status status;
|
||||
struct timer_list verify_timer;
|
||||
bool verify_enabled;
|
||||
int verify_retries;
|
||||
bool pmac_enabled;
|
||||
u32 verify_time;
|
||||
bool tx_enabled;
|
||||
};
|
||||
|
||||
struct stmmac_tc_entry {
|
||||
bool in_use;
|
||||
bool in_hw;
|
||||
bool is_last;
|
||||
bool is_frag;
|
||||
void *frag_ptr;
|
||||
unsigned int table_pos;
|
||||
u32 handle;
|
||||
u32 prio;
|
||||
struct {
|
||||
u32 match_data;
|
||||
u32 match_en;
|
||||
u8 af:1;
|
||||
u8 rf:1;
|
||||
u8 im:1;
|
||||
u8 nc:1;
|
||||
u8 res1:4;
|
||||
u8 frame_offset;
|
||||
u8 ok_index;
|
||||
u8 dma_ch_no;
|
||||
u32 res2;
|
||||
} __packed val;
|
||||
};
|
||||
|
||||
#define STMMAC_PPS_MAX 4
|
||||
struct stmmac_pps_cfg {
|
||||
bool available;
|
||||
struct timespec64 start;
|
||||
struct timespec64 period;
|
||||
};
|
||||
|
||||
struct stmmac_rss {
|
||||
int enable;
|
||||
u8 key[STMMAC_RSS_HASH_KEY_SIZE];
|
||||
u32 table[STMMAC_RSS_MAX_TABLE_SIZE];
|
||||
};
|
||||
|
||||
#define STMMAC_FLOW_ACTION_DROP BIT(0)
|
||||
struct stmmac_flow_entry {
|
||||
unsigned long cookie;
|
||||
unsigned long action;
|
||||
u8 ip_proto;
|
||||
int in_use;
|
||||
int idx;
|
||||
int is_l4;
|
||||
};
|
||||
|
||||
/* Rx Frame Steering */
|
||||
enum stmmac_rfs_type {
|
||||
STMMAC_RFS_T_VLAN,
|
||||
STMMAC_RFS_T_LLDP,
|
||||
STMMAC_RFS_T_1588,
|
||||
STMMAC_RFS_T_MAX,
|
||||
};
|
||||
|
||||
struct stmmac_rfs_entry {
|
||||
unsigned long cookie;
|
||||
u16 etype;
|
||||
int in_use;
|
||||
int type;
|
||||
int tc;
|
||||
};
|
||||
|
||||
struct stmmac_dma_conf {
|
||||
unsigned int dma_buf_sz;
|
||||
|
||||
/* RX Queue */
|
||||
struct stmmac_rx_queue rx_queue[MTL_MAX_RX_QUEUES];
|
||||
unsigned int dma_rx_size;
|
||||
|
||||
/* TX Queue */
|
||||
struct stmmac_tx_queue tx_queue[MTL_MAX_TX_QUEUES];
|
||||
unsigned int dma_tx_size;
|
||||
};
|
||||
|
||||
#define EST_GCL 1024
|
||||
struct stmmac_est {
|
||||
int enable;
|
||||
u32 btr_reserve[2];
|
||||
u32 btr_offset[2];
|
||||
u32 btr[2];
|
||||
u32 ctr[2];
|
||||
u32 ter;
|
||||
u32 gcl_unaligned[EST_GCL];
|
||||
u32 gcl[EST_GCL];
|
||||
u32 gcl_size;
|
||||
u32 max_sdu[MTL_MAX_TX_QUEUES];
|
||||
};
|
||||
|
||||
struct stmmac_priv {
|
||||
/* Frequently used values are kept adjacent for cache effect */
|
||||
u32 tx_coal_frames[MTL_MAX_TX_QUEUES];
|
||||
u32 tx_coal_timer[MTL_MAX_TX_QUEUES];
|
||||
u32 rx_coal_frames[MTL_MAX_TX_QUEUES];
|
||||
|
||||
int hwts_tx_en;
|
||||
bool tx_path_in_lpi_mode;
|
||||
bool tso;
|
||||
int sph;
|
||||
int sph_cap;
|
||||
u32 sarc_type;
|
||||
|
||||
unsigned int rx_copybreak;
|
||||
u32 rx_riwt[MTL_MAX_TX_QUEUES];
|
||||
int hwts_rx_en;
|
||||
|
||||
void __iomem *ioaddr;
|
||||
struct net_device *dev;
|
||||
struct device *device;
|
||||
struct mac_device_info *hw;
|
||||
int (*hwif_quirks)(struct stmmac_priv *priv);
|
||||
struct mutex lock;
|
||||
|
||||
struct stmmac_dma_conf dma_conf;
|
||||
|
||||
/* Generic channel for NAPI */
|
||||
struct stmmac_channel channel[STMMAC_CH_MAX];
|
||||
|
||||
int speed;
|
||||
unsigned int flow_ctrl;
|
||||
unsigned int pause;
|
||||
struct mii_bus *mii;
|
||||
|
||||
struct phylink_config phylink_config;
|
||||
struct phylink *phylink;
|
||||
|
||||
struct stmmac_extra_stats xstats ____cacheline_aligned_in_smp;
|
||||
struct stmmac_safety_stats sstats;
|
||||
struct plat_stmmacenet_data *plat;
|
||||
/* Protect est parameters */
|
||||
struct mutex est_lock;
|
||||
struct stmmac_est *est;
|
||||
struct dma_features dma_cap;
|
||||
struct stmmac_counters mmc;
|
||||
int hw_cap_support;
|
||||
int synopsys_id;
|
||||
u32 msg_enable;
|
||||
int wolopts;
|
||||
int wol_irq;
|
||||
bool wol_irq_disabled;
|
||||
int clk_csr;
|
||||
struct timer_list eee_ctrl_timer;
|
||||
int lpi_irq;
|
||||
int eee_enabled;
|
||||
int eee_active;
|
||||
int tx_lpi_timer;
|
||||
int tx_lpi_enabled;
|
||||
int eee_tw_timer;
|
||||
bool eee_sw_timer_en;
|
||||
unsigned int mode;
|
||||
unsigned int chain_mode;
|
||||
int extend_desc;
|
||||
struct hwtstamp_config tstamp_config;
|
||||
struct ptp_clock *ptp_clock;
|
||||
struct ptp_clock_info ptp_clock_ops;
|
||||
unsigned int default_addend;
|
||||
u32 sub_second_inc;
|
||||
u32 systime_flags;
|
||||
u32 adv_ts;
|
||||
int use_riwt;
|
||||
int irq_wake;
|
||||
rwlock_t ptp_lock;
|
||||
/* Protects auxiliary snapshot registers from concurrent access. */
|
||||
struct mutex aux_ts_lock;
|
||||
wait_queue_head_t tstamp_busy_wait;
|
||||
|
||||
void __iomem *mmcaddr;
|
||||
void __iomem *ptpaddr;
|
||||
void __iomem *estaddr;
|
||||
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
|
||||
int sfty_irq;
|
||||
int sfty_ce_irq;
|
||||
int sfty_ue_irq;
|
||||
int rx_irq[MTL_MAX_RX_QUEUES];
|
||||
int tx_irq[MTL_MAX_TX_QUEUES];
|
||||
/*irq name */
|
||||
char int_name_mac[IFNAMSIZ + 9];
|
||||
char int_name_wol[IFNAMSIZ + 9];
|
||||
char int_name_lpi[IFNAMSIZ + 9];
|
||||
char int_name_sfty[IFNAMSIZ + 10];
|
||||
char int_name_sfty_ce[IFNAMSIZ + 10];
|
||||
char int_name_sfty_ue[IFNAMSIZ + 10];
|
||||
char int_name_rx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 14];
|
||||
char int_name_tx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 18];
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *dbgfs_dir;
|
||||
#endif
|
||||
|
||||
unsigned long state;
|
||||
struct workqueue_struct *wq;
|
||||
struct work_struct service_task;
|
||||
|
||||
/* Frame Preemption feature (FPE) */
|
||||
struct stmmac_fpe_cfg fpe_cfg;
|
||||
|
||||
/* TC Handling */
|
||||
unsigned int tc_entries_max;
|
||||
unsigned int tc_off_max;
|
||||
struct stmmac_tc_entry *tc_entries;
|
||||
unsigned int flow_entries_max;
|
||||
struct stmmac_flow_entry *flow_entries;
|
||||
unsigned int rfs_entries_max[STMMAC_RFS_T_MAX];
|
||||
unsigned int rfs_entries_cnt[STMMAC_RFS_T_MAX];
|
||||
unsigned int rfs_entries_total;
|
||||
struct stmmac_rfs_entry *rfs_entries;
|
||||
|
||||
/* Pulse Per Second output */
|
||||
struct stmmac_pps_cfg pps[STMMAC_PPS_MAX];
|
||||
|
||||
/* Receive Side Scaling */
|
||||
struct stmmac_rss rss;
|
||||
|
||||
/* XDP BPF Program */
|
||||
unsigned long *af_xdp_zc_qps;
|
||||
struct bpf_prog *xdp_prog;
|
||||
|
||||
/* EtherCAT device variables */
|
||||
ec_device_t *ecdev_;
|
||||
unsigned long ec_watchdog_jiffies;
|
||||
struct irq_work ec_watchdog_kicker;
|
||||
bool ecdev_initialized;
|
||||
};
|
||||
|
||||
static inline ec_device_t *get_ecdev(struct stmmac_priv *adapter)
|
||||
{
|
||||
#ifdef EC_ENABLE_DRIVER_RESOURCE_VERIFYING
|
||||
WARN_ON(!adapter->ecdev_initialized);
|
||||
#endif
|
||||
return adapter->ecdev_;
|
||||
}
|
||||
|
||||
enum stmmac_state {
|
||||
STMMAC_DOWN,
|
||||
STMMAC_RESET_REQUESTED,
|
||||
STMMAC_RESETING,
|
||||
STMMAC_SERVICE_SCHED,
|
||||
};
|
||||
|
||||
int stmmac_mdio_unregister(struct net_device *ndev);
|
||||
int stmmac_mdio_register(struct net_device *ndev);
|
||||
int stmmac_mdio_reset(struct mii_bus *mii);
|
||||
int stmmac_pcs_setup(struct net_device *ndev);
|
||||
void stmmac_pcs_clean(struct net_device *ndev);
|
||||
void stmmac_set_ethtool_ops(struct net_device *netdev);
|
||||
|
||||
int stmmac_init_tstamp_counter(struct stmmac_priv *priv, u32 systime_flags);
|
||||
void stmmac_ptp_register(struct stmmac_priv *priv);
|
||||
void stmmac_ptp_unregister(struct stmmac_priv *priv);
|
||||
int stmmac_xdp_open(struct net_device *dev);
|
||||
void stmmac_xdp_release(struct net_device *dev);
|
||||
int stmmac_resume(struct device *dev);
|
||||
int stmmac_suspend(struct device *dev);
|
||||
void stmmac_ec_dvr_remove(struct device *dev);
|
||||
int stmmac_ec_dvr_probe(struct device *device,
|
||||
struct plat_stmmacenet_data *plat_dat,
|
||||
struct stmmac_resources *res);
|
||||
void stmmac_disable_eee_mode(struct stmmac_priv *priv);
|
||||
bool stmmac_eee_init(struct stmmac_priv *priv);
|
||||
int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt);
|
||||
int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size);
|
||||
int ec_stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled);
|
||||
void stmmac_fpe_apply(struct stmmac_priv *priv);
|
||||
|
||||
static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv)
|
||||
{
|
||||
return !!priv->xdp_prog;
|
||||
}
|
||||
|
||||
static inline unsigned int stmmac_rx_offset(struct stmmac_priv *priv)
|
||||
{
|
||||
if (stmmac_xdp_is_enabled(priv))
|
||||
return XDP_PACKET_HEADROOM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stmmac_disable_rx_queue(struct stmmac_priv *priv, u32 queue);
|
||||
void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue);
|
||||
void stmmac_disable_tx_queue(struct stmmac_priv *priv, u32 queue);
|
||||
void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue);
|
||||
int stmmac_xsk_wakeup(struct net_device *dev, u32 queue, u32 flags);
|
||||
struct timespec64 stmmac_calc_tas_basetime(ktime_t old_base_time,
|
||||
ktime_t current_time,
|
||||
u64 cycle_time);
|
||||
|
||||
#if IS_ENABLED(CONFIG_STMMAC_SELFTESTS)
|
||||
void stmmac_selftest_run(struct net_device *dev,
|
||||
struct ethtool_test *etest, u64 *buf);
|
||||
void stmmac_selftest_get_strings(struct stmmac_priv *priv, u8 *data);
|
||||
int stmmac_selftest_get_count(struct stmmac_priv *priv);
|
||||
#else
|
||||
static inline void stmmac_selftest_run(struct net_device *dev,
|
||||
struct ethtool_test *etest, u64 *buf)
|
||||
{
|
||||
/* Not enabled */
|
||||
}
|
||||
static inline void stmmac_selftest_get_strings(struct stmmac_priv *priv,
|
||||
u8 *data)
|
||||
{
|
||||
/* Not enabled */
|
||||
}
|
||||
static inline int stmmac_selftest_get_count(struct stmmac_priv *priv)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif /* CONFIG_STMMAC_SELFTESTS */
|
||||
|
||||
#endif /* __STMMAC_H__ */
|
||||
|
|
@ -0,0 +1,469 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __STMMAC_H__
|
||||
#define __STMMAC_H__
|
||||
|
||||
#define STMMAC_RESOURCE_NAME "stmmaceth"
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/stmmac.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/pci.h>
|
||||
#include "common.h"
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/reset.h>
|
||||
#include <net/page_pool/types.h>
|
||||
#include <net/xdp.h>
|
||||
#include <uapi/linux/bpf.h>
|
||||
|
||||
struct stmmac_resources {
|
||||
void __iomem *addr;
|
||||
u8 mac[ETH_ALEN];
|
||||
int wol_irq;
|
||||
int lpi_irq;
|
||||
int irq;
|
||||
int sfty_irq;
|
||||
int sfty_ce_irq;
|
||||
int sfty_ue_irq;
|
||||
int rx_irq[MTL_MAX_RX_QUEUES];
|
||||
int tx_irq[MTL_MAX_TX_QUEUES];
|
||||
};
|
||||
|
||||
enum stmmac_txbuf_type {
|
||||
STMMAC_TXBUF_T_SKB,
|
||||
STMMAC_TXBUF_T_XDP_TX,
|
||||
STMMAC_TXBUF_T_XDP_NDO,
|
||||
STMMAC_TXBUF_T_XSK_TX,
|
||||
};
|
||||
|
||||
struct stmmac_tx_info {
|
||||
dma_addr_t buf;
|
||||
bool map_as_page;
|
||||
unsigned len;
|
||||
bool last_segment;
|
||||
bool is_jumbo;
|
||||
enum stmmac_txbuf_type buf_type;
|
||||
struct xsk_tx_metadata_compl xsk_meta;
|
||||
};
|
||||
|
||||
#define STMMAC_TBS_AVAIL BIT(0)
|
||||
#define STMMAC_TBS_EN BIT(1)
|
||||
|
||||
/* Frequently used values are kept adjacent for cache effect */
|
||||
struct stmmac_tx_queue {
|
||||
u32 tx_count_frames;
|
||||
int tbs;
|
||||
struct hrtimer txtimer;
|
||||
u32 queue_index;
|
||||
struct stmmac_priv *priv_data;
|
||||
struct dma_extended_desc *dma_etx ____cacheline_aligned_in_smp;
|
||||
struct dma_edesc *dma_entx;
|
||||
struct dma_desc *dma_tx;
|
||||
union {
|
||||
struct sk_buff **tx_skbuff;
|
||||
struct xdp_frame **xdpf;
|
||||
};
|
||||
struct stmmac_tx_info *tx_skbuff_dma;
|
||||
struct xsk_buff_pool *xsk_pool;
|
||||
u32 xsk_frames_done;
|
||||
unsigned int cur_tx;
|
||||
unsigned int dirty_tx;
|
||||
dma_addr_t dma_tx_phy;
|
||||
dma_addr_t tx_tail_addr;
|
||||
u32 mss;
|
||||
};
|
||||
|
||||
struct stmmac_rx_buffer {
|
||||
union {
|
||||
struct {
|
||||
struct page *page;
|
||||
dma_addr_t addr;
|
||||
__u32 page_offset;
|
||||
};
|
||||
struct xdp_buff *xdp;
|
||||
};
|
||||
struct page *sec_page;
|
||||
dma_addr_t sec_addr;
|
||||
};
|
||||
|
||||
struct stmmac_xdp_buff {
|
||||
struct xdp_buff xdp;
|
||||
struct stmmac_priv *priv;
|
||||
struct dma_desc *desc;
|
||||
struct dma_desc *ndesc;
|
||||
};
|
||||
|
||||
struct stmmac_metadata_request {
|
||||
struct stmmac_priv *priv;
|
||||
struct dma_desc *tx_desc;
|
||||
bool *set_ic;
|
||||
};
|
||||
|
||||
struct stmmac_xsk_tx_complete {
|
||||
struct stmmac_priv *priv;
|
||||
struct dma_desc *desc;
|
||||
};
|
||||
|
||||
struct stmmac_rx_queue {
|
||||
u32 rx_count_frames;
|
||||
u32 queue_index;
|
||||
struct xdp_rxq_info xdp_rxq;
|
||||
struct xsk_buff_pool *xsk_pool;
|
||||
struct page_pool *page_pool;
|
||||
struct stmmac_rx_buffer *buf_pool;
|
||||
struct stmmac_priv *priv_data;
|
||||
struct dma_extended_desc *dma_erx;
|
||||
struct dma_desc *dma_rx ____cacheline_aligned_in_smp;
|
||||
unsigned int cur_rx;
|
||||
unsigned int dirty_rx;
|
||||
unsigned int buf_alloc_num;
|
||||
u32 rx_zeroc_thresh;
|
||||
dma_addr_t dma_rx_phy;
|
||||
u32 rx_tail_addr;
|
||||
unsigned int state_saved;
|
||||
struct {
|
||||
struct sk_buff *skb;
|
||||
unsigned int len;
|
||||
unsigned int error;
|
||||
} state;
|
||||
};
|
||||
|
||||
struct stmmac_channel {
|
||||
struct napi_struct rx_napi ____cacheline_aligned_in_smp;
|
||||
struct napi_struct tx_napi ____cacheline_aligned_in_smp;
|
||||
struct napi_struct rxtx_napi ____cacheline_aligned_in_smp;
|
||||
struct stmmac_priv *priv_data;
|
||||
spinlock_t lock;
|
||||
u32 index;
|
||||
};
|
||||
|
||||
/* FPE link-partner hand-shaking mPacket type */
|
||||
enum stmmac_mpacket_type {
|
||||
MPACKET_VERIFY = 0,
|
||||
MPACKET_RESPONSE = 1,
|
||||
};
|
||||
|
||||
#define STMMAC_FPE_MM_MAX_VERIFY_RETRIES 3
|
||||
#define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS 128
|
||||
|
||||
struct stmmac_fpe_cfg {
|
||||
/* Serialize access to MAC Merge state between ethtool requests
|
||||
* and link state updates.
|
||||
*/
|
||||
spinlock_t lock;
|
||||
|
||||
u32 fpe_csr; /* MAC_FPE_CTRL_STS reg cache */
|
||||
|
||||
enum ethtool_mm_verify_status status;
|
||||
struct timer_list verify_timer;
|
||||
bool verify_enabled;
|
||||
int verify_retries;
|
||||
bool pmac_enabled;
|
||||
u32 verify_time;
|
||||
bool tx_enabled;
|
||||
};
|
||||
|
||||
struct stmmac_tc_entry {
|
||||
bool in_use;
|
||||
bool in_hw;
|
||||
bool is_last;
|
||||
bool is_frag;
|
||||
void *frag_ptr;
|
||||
unsigned int table_pos;
|
||||
u32 handle;
|
||||
u32 prio;
|
||||
struct {
|
||||
u32 match_data;
|
||||
u32 match_en;
|
||||
u8 af:1;
|
||||
u8 rf:1;
|
||||
u8 im:1;
|
||||
u8 nc:1;
|
||||
u8 res1:4;
|
||||
u8 frame_offset;
|
||||
u8 ok_index;
|
||||
u8 dma_ch_no;
|
||||
u32 res2;
|
||||
} __packed val;
|
||||
};
|
||||
|
||||
#define STMMAC_PPS_MAX 4
|
||||
struct stmmac_pps_cfg {
|
||||
bool available;
|
||||
struct timespec64 start;
|
||||
struct timespec64 period;
|
||||
};
|
||||
|
||||
struct stmmac_rss {
|
||||
int enable;
|
||||
u8 key[STMMAC_RSS_HASH_KEY_SIZE];
|
||||
u32 table[STMMAC_RSS_MAX_TABLE_SIZE];
|
||||
};
|
||||
|
||||
#define STMMAC_FLOW_ACTION_DROP BIT(0)
|
||||
struct stmmac_flow_entry {
|
||||
unsigned long cookie;
|
||||
unsigned long action;
|
||||
u8 ip_proto;
|
||||
int in_use;
|
||||
int idx;
|
||||
int is_l4;
|
||||
};
|
||||
|
||||
/* Rx Frame Steering */
|
||||
enum stmmac_rfs_type {
|
||||
STMMAC_RFS_T_VLAN,
|
||||
STMMAC_RFS_T_LLDP,
|
||||
STMMAC_RFS_T_1588,
|
||||
STMMAC_RFS_T_MAX,
|
||||
};
|
||||
|
||||
struct stmmac_rfs_entry {
|
||||
unsigned long cookie;
|
||||
u16 etype;
|
||||
int in_use;
|
||||
int type;
|
||||
int tc;
|
||||
};
|
||||
|
||||
struct stmmac_dma_conf {
|
||||
unsigned int dma_buf_sz;
|
||||
|
||||
/* RX Queue */
|
||||
struct stmmac_rx_queue rx_queue[MTL_MAX_RX_QUEUES];
|
||||
unsigned int dma_rx_size;
|
||||
|
||||
/* TX Queue */
|
||||
struct stmmac_tx_queue tx_queue[MTL_MAX_TX_QUEUES];
|
||||
unsigned int dma_tx_size;
|
||||
};
|
||||
|
||||
#define EST_GCL 1024
|
||||
struct stmmac_est {
|
||||
int enable;
|
||||
u32 btr_reserve[2];
|
||||
u32 btr_offset[2];
|
||||
u32 btr[2];
|
||||
u32 ctr[2];
|
||||
u32 ter;
|
||||
u32 gcl_unaligned[EST_GCL];
|
||||
u32 gcl[EST_GCL];
|
||||
u32 gcl_size;
|
||||
u32 max_sdu[MTL_MAX_TX_QUEUES];
|
||||
};
|
||||
|
||||
struct stmmac_priv {
|
||||
/* Frequently used values are kept adjacent for cache effect */
|
||||
u32 tx_coal_frames[MTL_MAX_TX_QUEUES];
|
||||
u32 tx_coal_timer[MTL_MAX_TX_QUEUES];
|
||||
u32 rx_coal_frames[MTL_MAX_TX_QUEUES];
|
||||
|
||||
int hwts_tx_en;
|
||||
bool tx_path_in_lpi_mode;
|
||||
bool tso;
|
||||
int sph;
|
||||
int sph_cap;
|
||||
u32 sarc_type;
|
||||
|
||||
unsigned int rx_copybreak;
|
||||
u32 rx_riwt[MTL_MAX_TX_QUEUES];
|
||||
int hwts_rx_en;
|
||||
|
||||
void __iomem *ioaddr;
|
||||
struct net_device *dev;
|
||||
struct device *device;
|
||||
struct mac_device_info *hw;
|
||||
int (*hwif_quirks)(struct stmmac_priv *priv);
|
||||
struct mutex lock;
|
||||
|
||||
struct stmmac_dma_conf dma_conf;
|
||||
|
||||
/* Generic channel for NAPI */
|
||||
struct stmmac_channel channel[STMMAC_CH_MAX];
|
||||
|
||||
int speed;
|
||||
unsigned int flow_ctrl;
|
||||
unsigned int pause;
|
||||
struct mii_bus *mii;
|
||||
|
||||
struct phylink_config phylink_config;
|
||||
struct phylink *phylink;
|
||||
|
||||
struct stmmac_extra_stats xstats ____cacheline_aligned_in_smp;
|
||||
struct stmmac_safety_stats sstats;
|
||||
struct plat_stmmacenet_data *plat;
|
||||
/* Protect est parameters */
|
||||
struct mutex est_lock;
|
||||
struct stmmac_est *est;
|
||||
struct dma_features dma_cap;
|
||||
struct stmmac_counters mmc;
|
||||
int hw_cap_support;
|
||||
int synopsys_id;
|
||||
u32 msg_enable;
|
||||
int wolopts;
|
||||
int wol_irq;
|
||||
bool wol_irq_disabled;
|
||||
int clk_csr;
|
||||
struct timer_list eee_ctrl_timer;
|
||||
int lpi_irq;
|
||||
int eee_enabled;
|
||||
int eee_active;
|
||||
int tx_lpi_timer;
|
||||
int tx_lpi_enabled;
|
||||
int eee_tw_timer;
|
||||
bool eee_sw_timer_en;
|
||||
unsigned int mode;
|
||||
unsigned int chain_mode;
|
||||
int extend_desc;
|
||||
struct hwtstamp_config tstamp_config;
|
||||
struct ptp_clock *ptp_clock;
|
||||
struct ptp_clock_info ptp_clock_ops;
|
||||
unsigned int default_addend;
|
||||
u32 sub_second_inc;
|
||||
u32 systime_flags;
|
||||
u32 adv_ts;
|
||||
int use_riwt;
|
||||
int irq_wake;
|
||||
rwlock_t ptp_lock;
|
||||
/* Protects auxiliary snapshot registers from concurrent access. */
|
||||
struct mutex aux_ts_lock;
|
||||
wait_queue_head_t tstamp_busy_wait;
|
||||
|
||||
void __iomem *mmcaddr;
|
||||
void __iomem *ptpaddr;
|
||||
void __iomem *estaddr;
|
||||
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
|
||||
int sfty_irq;
|
||||
int sfty_ce_irq;
|
||||
int sfty_ue_irq;
|
||||
int rx_irq[MTL_MAX_RX_QUEUES];
|
||||
int tx_irq[MTL_MAX_TX_QUEUES];
|
||||
/*irq name */
|
||||
char int_name_mac[IFNAMSIZ + 9];
|
||||
char int_name_wol[IFNAMSIZ + 9];
|
||||
char int_name_lpi[IFNAMSIZ + 9];
|
||||
char int_name_sfty[IFNAMSIZ + 10];
|
||||
char int_name_sfty_ce[IFNAMSIZ + 10];
|
||||
char int_name_sfty_ue[IFNAMSIZ + 10];
|
||||
char int_name_rx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 14];
|
||||
char int_name_tx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 18];
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *dbgfs_dir;
|
||||
#endif
|
||||
|
||||
unsigned long state;
|
||||
struct workqueue_struct *wq;
|
||||
struct work_struct service_task;
|
||||
|
||||
/* Frame Preemption feature (FPE) */
|
||||
struct stmmac_fpe_cfg fpe_cfg;
|
||||
|
||||
/* TC Handling */
|
||||
unsigned int tc_entries_max;
|
||||
unsigned int tc_off_max;
|
||||
struct stmmac_tc_entry *tc_entries;
|
||||
unsigned int flow_entries_max;
|
||||
struct stmmac_flow_entry *flow_entries;
|
||||
unsigned int rfs_entries_max[STMMAC_RFS_T_MAX];
|
||||
unsigned int rfs_entries_cnt[STMMAC_RFS_T_MAX];
|
||||
unsigned int rfs_entries_total;
|
||||
struct stmmac_rfs_entry *rfs_entries;
|
||||
|
||||
/* Pulse Per Second output */
|
||||
struct stmmac_pps_cfg pps[STMMAC_PPS_MAX];
|
||||
|
||||
/* Receive Side Scaling */
|
||||
struct stmmac_rss rss;
|
||||
|
||||
/* XDP BPF Program */
|
||||
unsigned long *af_xdp_zc_qps;
|
||||
struct bpf_prog *xdp_prog;
|
||||
};
|
||||
|
||||
enum stmmac_state {
|
||||
STMMAC_DOWN,
|
||||
STMMAC_RESET_REQUESTED,
|
||||
STMMAC_RESETING,
|
||||
STMMAC_SERVICE_SCHED,
|
||||
};
|
||||
|
||||
int stmmac_mdio_unregister(struct net_device *ndev);
|
||||
int stmmac_mdio_register(struct net_device *ndev);
|
||||
int stmmac_mdio_reset(struct mii_bus *mii);
|
||||
int stmmac_pcs_setup(struct net_device *ndev);
|
||||
void stmmac_pcs_clean(struct net_device *ndev);
|
||||
void stmmac_set_ethtool_ops(struct net_device *netdev);
|
||||
|
||||
int stmmac_init_tstamp_counter(struct stmmac_priv *priv, u32 systime_flags);
|
||||
void stmmac_ptp_register(struct stmmac_priv *priv);
|
||||
void stmmac_ptp_unregister(struct stmmac_priv *priv);
|
||||
int stmmac_xdp_open(struct net_device *dev);
|
||||
void stmmac_xdp_release(struct net_device *dev);
|
||||
int stmmac_resume(struct device *dev);
|
||||
int stmmac_suspend(struct device *dev);
|
||||
void stmmac_dvr_remove(struct device *dev);
|
||||
int stmmac_dvr_probe(struct device *device,
|
||||
struct plat_stmmacenet_data *plat_dat,
|
||||
struct stmmac_resources *res);
|
||||
void stmmac_disable_eee_mode(struct stmmac_priv *priv);
|
||||
bool stmmac_eee_init(struct stmmac_priv *priv);
|
||||
int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt);
|
||||
int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size);
|
||||
int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled);
|
||||
void stmmac_fpe_apply(struct stmmac_priv *priv);
|
||||
|
||||
static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv)
|
||||
{
|
||||
return !!priv->xdp_prog;
|
||||
}
|
||||
|
||||
static inline unsigned int stmmac_rx_offset(struct stmmac_priv *priv)
|
||||
{
|
||||
if (stmmac_xdp_is_enabled(priv))
|
||||
return XDP_PACKET_HEADROOM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stmmac_disable_rx_queue(struct stmmac_priv *priv, u32 queue);
|
||||
void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue);
|
||||
void stmmac_disable_tx_queue(struct stmmac_priv *priv, u32 queue);
|
||||
void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue);
|
||||
int stmmac_xsk_wakeup(struct net_device *dev, u32 queue, u32 flags);
|
||||
struct timespec64 stmmac_calc_tas_basetime(ktime_t old_base_time,
|
||||
ktime_t current_time,
|
||||
u64 cycle_time);
|
||||
|
||||
#if IS_ENABLED(CONFIG_STMMAC_SELFTESTS)
|
||||
void stmmac_selftest_run(struct net_device *dev,
|
||||
struct ethtool_test *etest, u64 *buf);
|
||||
void stmmac_selftest_get_strings(struct stmmac_priv *priv, u8 *data);
|
||||
int stmmac_selftest_get_count(struct stmmac_priv *priv);
|
||||
#else
|
||||
static inline void stmmac_selftest_run(struct net_device *dev,
|
||||
struct ethtool_test *etest, u64 *buf)
|
||||
{
|
||||
/* Not enabled */
|
||||
}
|
||||
static inline void stmmac_selftest_get_strings(struct stmmac_priv *priv,
|
||||
u8 *data)
|
||||
{
|
||||
/* Not enabled */
|
||||
}
|
||||
static inline int stmmac_selftest_get_count(struct stmmac_priv *priv)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif /* CONFIG_STMMAC_SELFTESTS */
|
||||
|
||||
#endif /* __STMMAC_H__ */
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2023, Intel Corporation
|
||||
* stmmac EST(802.3 Qbv) handling
|
||||
*/
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/types.h>
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
#include "stmmac_est-6.12-ethercat.h"
|
||||
|
||||
static int est_write(void __iomem *est_addr, u32 reg, u32 val, bool gcl)
|
||||
{
|
||||
u32 ctrl;
|
||||
|
||||
writel(val, est_addr + EST_GCL_DATA);
|
||||
|
||||
ctrl = (reg << EST_ADDR_SHIFT);
|
||||
ctrl |= gcl ? 0 : EST_GCRR;
|
||||
writel(ctrl, est_addr + EST_GCL_CONTROL);
|
||||
|
||||
ctrl |= EST_SRWO;
|
||||
writel(ctrl, est_addr + EST_GCL_CONTROL);
|
||||
|
||||
return readl_poll_timeout(est_addr + EST_GCL_CONTROL, ctrl,
|
||||
!(ctrl & EST_SRWO), 100, 5000);
|
||||
}
|
||||
|
||||
static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
|
||||
unsigned int ptp_rate)
|
||||
{
|
||||
void __iomem *est_addr = priv->estaddr;
|
||||
int i, ret = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ret |= est_write(est_addr, EST_BTR_LOW, cfg->btr[0], false);
|
||||
ret |= est_write(est_addr, EST_BTR_HIGH, cfg->btr[1], false);
|
||||
ret |= est_write(est_addr, EST_TER, cfg->ter, false);
|
||||
ret |= est_write(est_addr, EST_LLR, cfg->gcl_size, false);
|
||||
ret |= est_write(est_addr, EST_CTR_LOW, cfg->ctr[0], false);
|
||||
ret |= est_write(est_addr, EST_CTR_HIGH, cfg->ctr[1], false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < cfg->gcl_size; i++) {
|
||||
ret = est_write(est_addr, i, cfg->gcl[i], true);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctrl = readl(est_addr + EST_CONTROL);
|
||||
if (priv->plat->has_xgmac) {
|
||||
ctrl &= ~EST_XGMAC_PTOV;
|
||||
ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_XGMAC_PTOV_MUL) <<
|
||||
EST_XGMAC_PTOV_SHIFT;
|
||||
} else {
|
||||
ctrl &= ~EST_GMAC5_PTOV;
|
||||
ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_GMAC5_PTOV_MUL) <<
|
||||
EST_GMAC5_PTOV_SHIFT;
|
||||
}
|
||||
if (cfg->enable)
|
||||
ctrl |= EST_EEST | EST_SSWL;
|
||||
else
|
||||
ctrl &= ~EST_EEST;
|
||||
|
||||
writel(ctrl, est_addr + EST_CONTROL);
|
||||
|
||||
/* Configure EST interrupt */
|
||||
if (cfg->enable)
|
||||
ctrl = EST_IECGCE | EST_IEHS | EST_IEHF | EST_IEBE | EST_IECC;
|
||||
else
|
||||
ctrl = 0;
|
||||
|
||||
writel(ctrl, est_addr + EST_INT_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev,
|
||||
struct stmmac_extra_stats *x, u32 txqcnt)
|
||||
{
|
||||
u32 status, value, feqn, hbfq, hbfs, btrl, btrl_max;
|
||||
void __iomem *est_addr = priv->estaddr;
|
||||
u32 txqcnt_mask = BIT(txqcnt) - 1;
|
||||
int i;
|
||||
|
||||
status = readl(est_addr + EST_STATUS);
|
||||
|
||||
value = EST_CGCE | EST_HLBS | EST_HLBF | EST_BTRE | EST_SWLC;
|
||||
|
||||
/* Return if there is no error */
|
||||
if (!(status & value))
|
||||
return;
|
||||
|
||||
if (status & EST_CGCE) {
|
||||
/* Clear Interrupt */
|
||||
writel(EST_CGCE, est_addr + EST_STATUS);
|
||||
|
||||
x->mtl_est_cgce++;
|
||||
}
|
||||
|
||||
if (status & EST_HLBS) {
|
||||
value = readl(est_addr + EST_SCH_ERR);
|
||||
value &= txqcnt_mask;
|
||||
|
||||
x->mtl_est_hlbs++;
|
||||
|
||||
/* Clear Interrupt */
|
||||
writel(value, est_addr + EST_SCH_ERR);
|
||||
|
||||
/* Collecting info to shows all the queues that has HLBS
|
||||
* issue. The only way to clear this is to clear the
|
||||
* statistic
|
||||
*/
|
||||
if (net_ratelimit())
|
||||
netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value);
|
||||
}
|
||||
|
||||
if (status & EST_HLBF) {
|
||||
value = readl(est_addr + EST_FRM_SZ_ERR);
|
||||
feqn = value & txqcnt_mask;
|
||||
|
||||
value = readl(est_addr + EST_FRM_SZ_CAP);
|
||||
hbfq = (value & EST_SZ_CAP_HBFQ_MASK(txqcnt)) >>
|
||||
EST_SZ_CAP_HBFQ_SHIFT;
|
||||
hbfs = value & EST_SZ_CAP_HBFS_MASK;
|
||||
|
||||
x->mtl_est_hlbf++;
|
||||
|
||||
for (i = 0; i < txqcnt; i++) {
|
||||
if (feqn & BIT(i))
|
||||
x->mtl_est_txq_hlbf[i]++;
|
||||
}
|
||||
|
||||
/* Clear Interrupt */
|
||||
writel(feqn, est_addr + EST_FRM_SZ_ERR);
|
||||
|
||||
if (net_ratelimit())
|
||||
netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n",
|
||||
hbfq, hbfs);
|
||||
}
|
||||
|
||||
if (status & EST_BTRE) {
|
||||
if (priv->plat->has_xgmac) {
|
||||
btrl = FIELD_GET(EST_XGMAC_BTRL, status);
|
||||
btrl_max = FIELD_MAX(EST_XGMAC_BTRL);
|
||||
} else {
|
||||
btrl = FIELD_GET(EST_GMAC5_BTRL, status);
|
||||
btrl_max = FIELD_MAX(EST_GMAC5_BTRL);
|
||||
}
|
||||
if (btrl == btrl_max)
|
||||
x->mtl_est_btrlm++;
|
||||
else
|
||||
x->mtl_est_btre++;
|
||||
|
||||
if (net_ratelimit())
|
||||
netdev_info(dev, "EST: BTR Error Loop Count %u\n",
|
||||
btrl);
|
||||
|
||||
writel(EST_BTRE, est_addr + EST_STATUS);
|
||||
}
|
||||
|
||||
if (status & EST_SWLC) {
|
||||
writel(EST_SWLC, est_addr + EST_STATUS);
|
||||
netdev_info(dev, "EST: SWOL has been switched\n");
|
||||
}
|
||||
}
|
||||
|
||||
const struct stmmac_est_ops dwmac510_est_ops = {
|
||||
.configure = est_configure,
|
||||
.irq_status = est_irq_status,
|
||||
};
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2023, Intel Corporation
|
||||
* stmmac EST(802.3 Qbv) handling
|
||||
*/
|
||||
|
||||
#define EST_GMAC4_OFFSET 0x00000c50
|
||||
#define EST_XGMAC_OFFSET 0x00001050
|
||||
|
||||
#define EST_CONTROL 0x00000000
|
||||
#define EST_GMAC5_PTOV GENMASK(31, 24)
|
||||
#define EST_GMAC5_PTOV_SHIFT 24
|
||||
#define EST_GMAC5_PTOV_MUL 6
|
||||
#define EST_XGMAC_PTOV GENMASK(31, 23)
|
||||
#define EST_XGMAC_PTOV_SHIFT 23
|
||||
#define EST_XGMAC_PTOV_MUL 9
|
||||
#define EST_SSWL BIT(1)
|
||||
#define EST_EEST BIT(0)
|
||||
|
||||
#define EST_STATUS 0x00000008
|
||||
#define EST_GMAC5_BTRL GENMASK(11, 8)
|
||||
#define EST_XGMAC_BTRL GENMASK(15, 8)
|
||||
#define EST_SWOL BIT(7)
|
||||
#define EST_SWOL_SHIFT 7
|
||||
#define EST_CGCE BIT(4)
|
||||
#define EST_HLBS BIT(3)
|
||||
#define EST_HLBF BIT(2)
|
||||
#define EST_BTRE BIT(1)
|
||||
#define EST_SWLC BIT(0)
|
||||
|
||||
#define EST_SCH_ERR 0x00000010
|
||||
|
||||
#define EST_FRM_SZ_ERR 0x00000014
|
||||
|
||||
#define EST_FRM_SZ_CAP 0x00000018
|
||||
#define EST_SZ_CAP_HBFS_MASK GENMASK(14, 0)
|
||||
#define EST_SZ_CAP_HBFQ_SHIFT 16
|
||||
#define EST_SZ_CAP_HBFQ_MASK(val) \
|
||||
({ \
|
||||
typeof(val) _val = (val); \
|
||||
(_val > 4 ? GENMASK(18, 16) : \
|
||||
_val > 2 ? GENMASK(17, 16) : \
|
||||
BIT(16)); \
|
||||
})
|
||||
|
||||
#define EST_INT_EN 0x00000020
|
||||
#define EST_IECGCE EST_CGCE
|
||||
#define EST_IEHS EST_HLBS
|
||||
#define EST_IEHF EST_HLBF
|
||||
#define EST_IEBE EST_BTRE
|
||||
#define EST_IECC EST_SWLC
|
||||
|
||||
#define EST_GCL_CONTROL 0x00000030
|
||||
#define EST_BTR_LOW 0x0
|
||||
#define EST_BTR_HIGH 0x1
|
||||
#define EST_CTR_LOW 0x2
|
||||
#define EST_CTR_HIGH 0x3
|
||||
#define EST_TER 0x4
|
||||
#define EST_LLR 0x5
|
||||
#define EST_ADDR_SHIFT 8
|
||||
#define EST_GCRR BIT(2)
|
||||
#define EST_SRWO BIT(0)
|
||||
|
||||
#define EST_GCL_DATA 0x00000034
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2023, Intel Corporation
|
||||
* stmmac EST(802.3 Qbv) handling
|
||||
*/
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/types.h>
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_est.h"
|
||||
|
||||
static int est_write(void __iomem *est_addr, u32 reg, u32 val, bool gcl)
|
||||
{
|
||||
u32 ctrl;
|
||||
|
||||
writel(val, est_addr + EST_GCL_DATA);
|
||||
|
||||
ctrl = (reg << EST_ADDR_SHIFT);
|
||||
ctrl |= gcl ? 0 : EST_GCRR;
|
||||
writel(ctrl, est_addr + EST_GCL_CONTROL);
|
||||
|
||||
ctrl |= EST_SRWO;
|
||||
writel(ctrl, est_addr + EST_GCL_CONTROL);
|
||||
|
||||
return readl_poll_timeout(est_addr + EST_GCL_CONTROL, ctrl,
|
||||
!(ctrl & EST_SRWO), 100, 5000);
|
||||
}
|
||||
|
||||
static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
|
||||
unsigned int ptp_rate)
|
||||
{
|
||||
void __iomem *est_addr = priv->estaddr;
|
||||
int i, ret = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ret |= est_write(est_addr, EST_BTR_LOW, cfg->btr[0], false);
|
||||
ret |= est_write(est_addr, EST_BTR_HIGH, cfg->btr[1], false);
|
||||
ret |= est_write(est_addr, EST_TER, cfg->ter, false);
|
||||
ret |= est_write(est_addr, EST_LLR, cfg->gcl_size, false);
|
||||
ret |= est_write(est_addr, EST_CTR_LOW, cfg->ctr[0], false);
|
||||
ret |= est_write(est_addr, EST_CTR_HIGH, cfg->ctr[1], false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < cfg->gcl_size; i++) {
|
||||
ret = est_write(est_addr, i, cfg->gcl[i], true);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctrl = readl(est_addr + EST_CONTROL);
|
||||
if (priv->plat->has_xgmac) {
|
||||
ctrl &= ~EST_XGMAC_PTOV;
|
||||
ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_XGMAC_PTOV_MUL) <<
|
||||
EST_XGMAC_PTOV_SHIFT;
|
||||
} else {
|
||||
ctrl &= ~EST_GMAC5_PTOV;
|
||||
ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_GMAC5_PTOV_MUL) <<
|
||||
EST_GMAC5_PTOV_SHIFT;
|
||||
}
|
||||
if (cfg->enable)
|
||||
ctrl |= EST_EEST | EST_SSWL;
|
||||
else
|
||||
ctrl &= ~EST_EEST;
|
||||
|
||||
writel(ctrl, est_addr + EST_CONTROL);
|
||||
|
||||
/* Configure EST interrupt */
|
||||
if (cfg->enable)
|
||||
ctrl = EST_IECGCE | EST_IEHS | EST_IEHF | EST_IEBE | EST_IECC;
|
||||
else
|
||||
ctrl = 0;
|
||||
|
||||
writel(ctrl, est_addr + EST_INT_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev,
|
||||
struct stmmac_extra_stats *x, u32 txqcnt)
|
||||
{
|
||||
u32 status, value, feqn, hbfq, hbfs, btrl, btrl_max;
|
||||
void __iomem *est_addr = priv->estaddr;
|
||||
u32 txqcnt_mask = BIT(txqcnt) - 1;
|
||||
int i;
|
||||
|
||||
status = readl(est_addr + EST_STATUS);
|
||||
|
||||
value = EST_CGCE | EST_HLBS | EST_HLBF | EST_BTRE | EST_SWLC;
|
||||
|
||||
/* Return if there is no error */
|
||||
if (!(status & value))
|
||||
return;
|
||||
|
||||
if (status & EST_CGCE) {
|
||||
/* Clear Interrupt */
|
||||
writel(EST_CGCE, est_addr + EST_STATUS);
|
||||
|
||||
x->mtl_est_cgce++;
|
||||
}
|
||||
|
||||
if (status & EST_HLBS) {
|
||||
value = readl(est_addr + EST_SCH_ERR);
|
||||
value &= txqcnt_mask;
|
||||
|
||||
x->mtl_est_hlbs++;
|
||||
|
||||
/* Clear Interrupt */
|
||||
writel(value, est_addr + EST_SCH_ERR);
|
||||
|
||||
/* Collecting info to shows all the queues that has HLBS
|
||||
* issue. The only way to clear this is to clear the
|
||||
* statistic
|
||||
*/
|
||||
if (net_ratelimit())
|
||||
netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value);
|
||||
}
|
||||
|
||||
if (status & EST_HLBF) {
|
||||
value = readl(est_addr + EST_FRM_SZ_ERR);
|
||||
feqn = value & txqcnt_mask;
|
||||
|
||||
value = readl(est_addr + EST_FRM_SZ_CAP);
|
||||
hbfq = (value & EST_SZ_CAP_HBFQ_MASK(txqcnt)) >>
|
||||
EST_SZ_CAP_HBFQ_SHIFT;
|
||||
hbfs = value & EST_SZ_CAP_HBFS_MASK;
|
||||
|
||||
x->mtl_est_hlbf++;
|
||||
|
||||
for (i = 0; i < txqcnt; i++) {
|
||||
if (feqn & BIT(i))
|
||||
x->mtl_est_txq_hlbf[i]++;
|
||||
}
|
||||
|
||||
/* Clear Interrupt */
|
||||
writel(feqn, est_addr + EST_FRM_SZ_ERR);
|
||||
|
||||
if (net_ratelimit())
|
||||
netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n",
|
||||
hbfq, hbfs);
|
||||
}
|
||||
|
||||
if (status & EST_BTRE) {
|
||||
if (priv->plat->has_xgmac) {
|
||||
btrl = FIELD_GET(EST_XGMAC_BTRL, status);
|
||||
btrl_max = FIELD_MAX(EST_XGMAC_BTRL);
|
||||
} else {
|
||||
btrl = FIELD_GET(EST_GMAC5_BTRL, status);
|
||||
btrl_max = FIELD_MAX(EST_GMAC5_BTRL);
|
||||
}
|
||||
if (btrl == btrl_max)
|
||||
x->mtl_est_btrlm++;
|
||||
else
|
||||
x->mtl_est_btre++;
|
||||
|
||||
if (net_ratelimit())
|
||||
netdev_info(dev, "EST: BTR Error Loop Count %u\n",
|
||||
btrl);
|
||||
|
||||
writel(EST_BTRE, est_addr + EST_STATUS);
|
||||
}
|
||||
|
||||
if (status & EST_SWLC) {
|
||||
writel(EST_SWLC, est_addr + EST_STATUS);
|
||||
netdev_info(dev, "EST: SWOL has been switched\n");
|
||||
}
|
||||
}
|
||||
|
||||
const struct stmmac_est_ops dwmac510_est_ops = {
|
||||
.configure = est_configure,
|
||||
.irq_status = est_irq_status,
|
||||
};
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2023, Intel Corporation
|
||||
* stmmac EST(802.3 Qbv) handling
|
||||
*/
|
||||
|
||||
#define EST_GMAC4_OFFSET 0x00000c50
|
||||
#define EST_XGMAC_OFFSET 0x00001050
|
||||
|
||||
#define EST_CONTROL 0x00000000
|
||||
#define EST_GMAC5_PTOV GENMASK(31, 24)
|
||||
#define EST_GMAC5_PTOV_SHIFT 24
|
||||
#define EST_GMAC5_PTOV_MUL 6
|
||||
#define EST_XGMAC_PTOV GENMASK(31, 23)
|
||||
#define EST_XGMAC_PTOV_SHIFT 23
|
||||
#define EST_XGMAC_PTOV_MUL 9
|
||||
#define EST_SSWL BIT(1)
|
||||
#define EST_EEST BIT(0)
|
||||
|
||||
#define EST_STATUS 0x00000008
|
||||
#define EST_GMAC5_BTRL GENMASK(11, 8)
|
||||
#define EST_XGMAC_BTRL GENMASK(15, 8)
|
||||
#define EST_SWOL BIT(7)
|
||||
#define EST_SWOL_SHIFT 7
|
||||
#define EST_CGCE BIT(4)
|
||||
#define EST_HLBS BIT(3)
|
||||
#define EST_HLBF BIT(2)
|
||||
#define EST_BTRE BIT(1)
|
||||
#define EST_SWLC BIT(0)
|
||||
|
||||
#define EST_SCH_ERR 0x00000010
|
||||
|
||||
#define EST_FRM_SZ_ERR 0x00000014
|
||||
|
||||
#define EST_FRM_SZ_CAP 0x00000018
|
||||
#define EST_SZ_CAP_HBFS_MASK GENMASK(14, 0)
|
||||
#define EST_SZ_CAP_HBFQ_SHIFT 16
|
||||
#define EST_SZ_CAP_HBFQ_MASK(val) \
|
||||
({ \
|
||||
typeof(val) _val = (val); \
|
||||
(_val > 4 ? GENMASK(18, 16) : \
|
||||
_val > 2 ? GENMASK(17, 16) : \
|
||||
BIT(16)); \
|
||||
})
|
||||
|
||||
#define EST_INT_EN 0x00000020
|
||||
#define EST_IECGCE EST_CGCE
|
||||
#define EST_IEHS EST_HLBS
|
||||
#define EST_IEHF EST_HLBF
|
||||
#define EST_IEBE EST_BTRE
|
||||
#define EST_IECC EST_SWLC
|
||||
|
||||
#define EST_GCL_CONTROL 0x00000030
|
||||
#define EST_BTR_LOW 0x0
|
||||
#define EST_BTR_HIGH 0x1
|
||||
#define EST_CTR_LOW 0x2
|
||||
#define EST_CTR_HIGH 0x3
|
||||
#define EST_TER 0x4
|
||||
#define EST_LLR 0x5
|
||||
#define EST_ADDR_SHIFT 8
|
||||
#define EST_GCRR BIT(2)
|
||||
#define EST_SRWO BIT(0)
|
||||
|
||||
#define EST_GCL_DATA 0x00000034
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,271 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2013 Vayavya Labs Pvt Ltd
|
||||
|
||||
This implements all the API for managing HW timestamp & PTP.
|
||||
|
||||
|
||||
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include "common-6.12-ethercat.h"
|
||||
#include "stmmac_ptp-6.12-ethercat.h"
|
||||
#include "dwmac4-6.12-ethercat.h"
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
|
||||
static void config_hw_tstamping(void __iomem *ioaddr, u32 data)
|
||||
{
|
||||
writel(data, ioaddr + PTP_TCR);
|
||||
}
|
||||
|
||||
static void config_sub_second_increment(void __iomem *ioaddr,
|
||||
u32 ptp_clock, int gmac4, u32 *ssinc)
|
||||
{
|
||||
u32 value = readl(ioaddr + PTP_TCR);
|
||||
unsigned long data;
|
||||
u32 reg_value;
|
||||
|
||||
/* For GMAC3.x, 4.x versions, in "fine adjustement mode" set sub-second
|
||||
* increment to twice the number of nanoseconds of a clock cycle.
|
||||
* The calculation of the default_addend value by the caller will set it
|
||||
* to mid-range = 2^31 when the remainder of this division is zero,
|
||||
* which will make the accumulator overflow once every 2 ptp_clock
|
||||
* cycles, adding twice the number of nanoseconds of a clock cycle :
|
||||
* 2000000000ULL / ptp_clock.
|
||||
*/
|
||||
if (value & PTP_TCR_TSCFUPDT)
|
||||
data = (2000000000ULL / ptp_clock);
|
||||
else
|
||||
data = (1000000000ULL / ptp_clock);
|
||||
|
||||
/* 0.465ns accuracy */
|
||||
if (!(value & PTP_TCR_TSCTRLSSR))
|
||||
data = (data * 1000) / 465;
|
||||
|
||||
if (data > PTP_SSIR_SSINC_MAX)
|
||||
data = PTP_SSIR_SSINC_MAX;
|
||||
|
||||
reg_value = data;
|
||||
if (gmac4)
|
||||
reg_value <<= GMAC4_PTP_SSIR_SSINC_SHIFT;
|
||||
|
||||
writel(reg_value, ioaddr + PTP_SSIR);
|
||||
|
||||
if (ssinc)
|
||||
*ssinc = data;
|
||||
}
|
||||
|
||||
static void hwtstamp_correct_latency(struct stmmac_priv *priv)
|
||||
{
|
||||
void __iomem *ioaddr = priv->ptpaddr;
|
||||
u32 reg_tsic, reg_tsicsns;
|
||||
u32 reg_tsec, reg_tsecsns;
|
||||
u64 scaled_ns;
|
||||
u32 val;
|
||||
|
||||
/* MAC-internal ingress latency */
|
||||
scaled_ns = readl(ioaddr + PTP_TS_INGR_LAT);
|
||||
|
||||
/* See section 11.7.2.5.3.1 "Ingress Correction" on page 4001 of
|
||||
* i.MX8MP Applications Processor Reference Manual Rev. 1, 06/2021
|
||||
*/
|
||||
val = readl(ioaddr + PTP_TCR);
|
||||
if (val & PTP_TCR_TSCTRLSSR)
|
||||
/* nanoseconds field is in decimal format with granularity of 1ns/bit */
|
||||
scaled_ns = ((u64)NSEC_PER_SEC << 16) - scaled_ns;
|
||||
else
|
||||
/* nanoseconds field is in binary format with granularity of ~0.466ns/bit */
|
||||
scaled_ns = ((1ULL << 31) << 16) -
|
||||
DIV_U64_ROUND_CLOSEST(scaled_ns * PSEC_PER_NSEC, 466U);
|
||||
|
||||
reg_tsic = scaled_ns >> 16;
|
||||
reg_tsicsns = scaled_ns & 0xff00;
|
||||
|
||||
/* set bit 31 for 2's compliment */
|
||||
reg_tsic |= BIT(31);
|
||||
|
||||
writel(reg_tsic, ioaddr + PTP_TS_INGR_CORR_NS);
|
||||
writel(reg_tsicsns, ioaddr + PTP_TS_INGR_CORR_SNS);
|
||||
|
||||
/* MAC-internal egress latency */
|
||||
scaled_ns = readl(ioaddr + PTP_TS_EGR_LAT);
|
||||
|
||||
reg_tsec = scaled_ns >> 16;
|
||||
reg_tsecsns = scaled_ns & 0xff00;
|
||||
|
||||
writel(reg_tsec, ioaddr + PTP_TS_EGR_CORR_NS);
|
||||
writel(reg_tsecsns, ioaddr + PTP_TS_EGR_CORR_SNS);
|
||||
}
|
||||
|
||||
static int init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
writel(sec, ioaddr + PTP_STSUR);
|
||||
writel(nsec, ioaddr + PTP_STNSUR);
|
||||
/* issue command to initialize the system time value */
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
value |= PTP_TCR_TSINIT;
|
||||
writel(value, ioaddr + PTP_TCR);
|
||||
|
||||
/* wait for present system time initialize to complete */
|
||||
return readl_poll_timeout_atomic(ioaddr + PTP_TCR, value,
|
||||
!(value & PTP_TCR_TSINIT),
|
||||
10, 100000);
|
||||
}
|
||||
|
||||
static int config_addend(void __iomem *ioaddr, u32 addend)
|
||||
{
|
||||
u32 value;
|
||||
int limit;
|
||||
|
||||
writel(addend, ioaddr + PTP_TAR);
|
||||
/* issue command to update the addend value */
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
value |= PTP_TCR_TSADDREG;
|
||||
writel(value, ioaddr + PTP_TCR);
|
||||
|
||||
/* wait for present addend update to complete */
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
|
||||
int add_sub, int gmac4)
|
||||
{
|
||||
u32 value;
|
||||
int limit;
|
||||
|
||||
if (add_sub) {
|
||||
/* If the new sec value needs to be subtracted with
|
||||
* the system time, then MAC_STSUR reg should be
|
||||
* programmed with (2^32 – <new_sec_value>)
|
||||
*/
|
||||
if (gmac4)
|
||||
sec = -sec;
|
||||
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
if (value & PTP_TCR_TSCTRLSSR)
|
||||
nsec = (PTP_DIGITAL_ROLLOVER_MODE - nsec);
|
||||
else
|
||||
nsec = (PTP_BINARY_ROLLOVER_MODE - nsec);
|
||||
}
|
||||
|
||||
writel(sec, ioaddr + PTP_STSUR);
|
||||
value = (add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec;
|
||||
writel(value, ioaddr + PTP_STNSUR);
|
||||
|
||||
/* issue command to initialize the system time value */
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
value |= PTP_TCR_TSUPDT;
|
||||
writel(value, ioaddr + PTP_TCR);
|
||||
|
||||
/* wait for present system time adjust/update to complete */
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void get_systime(void __iomem *ioaddr, u64 *systime)
|
||||
{
|
||||
u64 ns, sec0, sec1;
|
||||
|
||||
/* Get the TSS value */
|
||||
sec1 = readl_relaxed(ioaddr + PTP_STSR);
|
||||
do {
|
||||
sec0 = sec1;
|
||||
/* Get the TSSS value */
|
||||
ns = readl_relaxed(ioaddr + PTP_STNSR);
|
||||
/* Get the TSS value */
|
||||
sec1 = readl_relaxed(ioaddr + PTP_STSR);
|
||||
} while (sec0 != sec1);
|
||||
|
||||
if (systime)
|
||||
*systime = ns + (sec1 * 1000000000ULL);
|
||||
}
|
||||
|
||||
static void get_ptptime(void __iomem *ptpaddr, u64 *ptp_time)
|
||||
{
|
||||
u64 ns;
|
||||
|
||||
ns = readl(ptpaddr + PTP_ATNR);
|
||||
ns += readl(ptpaddr + PTP_ATSR) * NSEC_PER_SEC;
|
||||
|
||||
*ptp_time = ns;
|
||||
}
|
||||
|
||||
static void timestamp_interrupt(struct stmmac_priv *priv)
|
||||
{
|
||||
u32 num_snapshot, ts_status, tsync_int;
|
||||
struct ptp_clock_event event;
|
||||
u32 acr_value, channel;
|
||||
unsigned long flags;
|
||||
u64 ptp_time;
|
||||
int i;
|
||||
|
||||
if (priv->plat->flags & STMMAC_FLAG_INT_SNAPSHOT_EN) {
|
||||
wake_up(&priv->tstamp_busy_wait);
|
||||
return;
|
||||
}
|
||||
|
||||
tsync_int = readl(priv->ioaddr + GMAC_INT_STATUS) & GMAC_INT_TSIE;
|
||||
|
||||
if (!tsync_int)
|
||||
return;
|
||||
|
||||
/* Read timestamp status to clear interrupt from either external
|
||||
* timestamp or start/end of PPS.
|
||||
*/
|
||||
ts_status = readl(priv->ioaddr + GMAC_TIMESTAMP_STATUS);
|
||||
|
||||
if (!(priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN))
|
||||
return;
|
||||
|
||||
num_snapshot = (ts_status & GMAC_TIMESTAMP_ATSNS_MASK) >>
|
||||
GMAC_TIMESTAMP_ATSNS_SHIFT;
|
||||
|
||||
acr_value = readl(priv->ptpaddr + PTP_ACR);
|
||||
channel = ilog2(FIELD_GET(PTP_ACR_MASK, acr_value));
|
||||
|
||||
for (i = 0; i < num_snapshot; i++) {
|
||||
read_lock_irqsave(&priv->ptp_lock, flags);
|
||||
get_ptptime(priv->ptpaddr, &ptp_time);
|
||||
read_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
event.type = PTP_CLOCK_EXTTS;
|
||||
event.index = channel;
|
||||
event.timestamp = ptp_time;
|
||||
ptp_clock_event(priv->ptp_clock, &event);
|
||||
}
|
||||
}
|
||||
|
||||
const struct stmmac_hwtimestamp stmmac_ptp = {
|
||||
.config_hw_tstamping = config_hw_tstamping,
|
||||
.init_systime = init_systime,
|
||||
.config_sub_second_increment = config_sub_second_increment,
|
||||
.config_addend = config_addend,
|
||||
.adjust_systime = adjust_systime,
|
||||
.get_systime = get_systime,
|
||||
.get_ptptime = get_ptptime,
|
||||
.timestamp_interrupt = timestamp_interrupt,
|
||||
.hwtstamp_correct_latency = hwtstamp_correct_latency,
|
||||
};
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2013 Vayavya Labs Pvt Ltd
|
||||
|
||||
This implements all the API for managing HW timestamp & PTP.
|
||||
|
||||
|
||||
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include "common.h"
|
||||
#include "stmmac_ptp.h"
|
||||
#include "dwmac4.h"
|
||||
#include "stmmac.h"
|
||||
|
||||
static void config_hw_tstamping(void __iomem *ioaddr, u32 data)
|
||||
{
|
||||
writel(data, ioaddr + PTP_TCR);
|
||||
}
|
||||
|
||||
static void config_sub_second_increment(void __iomem *ioaddr,
|
||||
u32 ptp_clock, int gmac4, u32 *ssinc)
|
||||
{
|
||||
u32 value = readl(ioaddr + PTP_TCR);
|
||||
unsigned long data;
|
||||
u32 reg_value;
|
||||
|
||||
/* For GMAC3.x, 4.x versions, in "fine adjustement mode" set sub-second
|
||||
* increment to twice the number of nanoseconds of a clock cycle.
|
||||
* The calculation of the default_addend value by the caller will set it
|
||||
* to mid-range = 2^31 when the remainder of this division is zero,
|
||||
* which will make the accumulator overflow once every 2 ptp_clock
|
||||
* cycles, adding twice the number of nanoseconds of a clock cycle :
|
||||
* 2000000000ULL / ptp_clock.
|
||||
*/
|
||||
if (value & PTP_TCR_TSCFUPDT)
|
||||
data = (2000000000ULL / ptp_clock);
|
||||
else
|
||||
data = (1000000000ULL / ptp_clock);
|
||||
|
||||
/* 0.465ns accuracy */
|
||||
if (!(value & PTP_TCR_TSCTRLSSR))
|
||||
data = (data * 1000) / 465;
|
||||
|
||||
if (data > PTP_SSIR_SSINC_MAX)
|
||||
data = PTP_SSIR_SSINC_MAX;
|
||||
|
||||
reg_value = data;
|
||||
if (gmac4)
|
||||
reg_value <<= GMAC4_PTP_SSIR_SSINC_SHIFT;
|
||||
|
||||
writel(reg_value, ioaddr + PTP_SSIR);
|
||||
|
||||
if (ssinc)
|
||||
*ssinc = data;
|
||||
}
|
||||
|
||||
static void hwtstamp_correct_latency(struct stmmac_priv *priv)
|
||||
{
|
||||
void __iomem *ioaddr = priv->ptpaddr;
|
||||
u32 reg_tsic, reg_tsicsns;
|
||||
u32 reg_tsec, reg_tsecsns;
|
||||
u64 scaled_ns;
|
||||
u32 val;
|
||||
|
||||
/* MAC-internal ingress latency */
|
||||
scaled_ns = readl(ioaddr + PTP_TS_INGR_LAT);
|
||||
|
||||
/* See section 11.7.2.5.3.1 "Ingress Correction" on page 4001 of
|
||||
* i.MX8MP Applications Processor Reference Manual Rev. 1, 06/2021
|
||||
*/
|
||||
val = readl(ioaddr + PTP_TCR);
|
||||
if (val & PTP_TCR_TSCTRLSSR)
|
||||
/* nanoseconds field is in decimal format with granularity of 1ns/bit */
|
||||
scaled_ns = ((u64)NSEC_PER_SEC << 16) - scaled_ns;
|
||||
else
|
||||
/* nanoseconds field is in binary format with granularity of ~0.466ns/bit */
|
||||
scaled_ns = ((1ULL << 31) << 16) -
|
||||
DIV_U64_ROUND_CLOSEST(scaled_ns * PSEC_PER_NSEC, 466U);
|
||||
|
||||
reg_tsic = scaled_ns >> 16;
|
||||
reg_tsicsns = scaled_ns & 0xff00;
|
||||
|
||||
/* set bit 31 for 2's compliment */
|
||||
reg_tsic |= BIT(31);
|
||||
|
||||
writel(reg_tsic, ioaddr + PTP_TS_INGR_CORR_NS);
|
||||
writel(reg_tsicsns, ioaddr + PTP_TS_INGR_CORR_SNS);
|
||||
|
||||
/* MAC-internal egress latency */
|
||||
scaled_ns = readl(ioaddr + PTP_TS_EGR_LAT);
|
||||
|
||||
reg_tsec = scaled_ns >> 16;
|
||||
reg_tsecsns = scaled_ns & 0xff00;
|
||||
|
||||
writel(reg_tsec, ioaddr + PTP_TS_EGR_CORR_NS);
|
||||
writel(reg_tsecsns, ioaddr + PTP_TS_EGR_CORR_SNS);
|
||||
}
|
||||
|
||||
static int init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
writel(sec, ioaddr + PTP_STSUR);
|
||||
writel(nsec, ioaddr + PTP_STNSUR);
|
||||
/* issue command to initialize the system time value */
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
value |= PTP_TCR_TSINIT;
|
||||
writel(value, ioaddr + PTP_TCR);
|
||||
|
||||
/* wait for present system time initialize to complete */
|
||||
return readl_poll_timeout_atomic(ioaddr + PTP_TCR, value,
|
||||
!(value & PTP_TCR_TSINIT),
|
||||
10, 100000);
|
||||
}
|
||||
|
||||
static int config_addend(void __iomem *ioaddr, u32 addend)
|
||||
{
|
||||
u32 value;
|
||||
int limit;
|
||||
|
||||
writel(addend, ioaddr + PTP_TAR);
|
||||
/* issue command to update the addend value */
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
value |= PTP_TCR_TSADDREG;
|
||||
writel(value, ioaddr + PTP_TCR);
|
||||
|
||||
/* wait for present addend update to complete */
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
|
||||
int add_sub, int gmac4)
|
||||
{
|
||||
u32 value;
|
||||
int limit;
|
||||
|
||||
if (add_sub) {
|
||||
/* If the new sec value needs to be subtracted with
|
||||
* the system time, then MAC_STSUR reg should be
|
||||
* programmed with (2^32 – <new_sec_value>)
|
||||
*/
|
||||
if (gmac4)
|
||||
sec = -sec;
|
||||
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
if (value & PTP_TCR_TSCTRLSSR)
|
||||
nsec = (PTP_DIGITAL_ROLLOVER_MODE - nsec);
|
||||
else
|
||||
nsec = (PTP_BINARY_ROLLOVER_MODE - nsec);
|
||||
}
|
||||
|
||||
writel(sec, ioaddr + PTP_STSUR);
|
||||
value = (add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec;
|
||||
writel(value, ioaddr + PTP_STNSUR);
|
||||
|
||||
/* issue command to initialize the system time value */
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
value |= PTP_TCR_TSUPDT;
|
||||
writel(value, ioaddr + PTP_TCR);
|
||||
|
||||
/* wait for present system time adjust/update to complete */
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void get_systime(void __iomem *ioaddr, u64 *systime)
|
||||
{
|
||||
u64 ns, sec0, sec1;
|
||||
|
||||
/* Get the TSS value */
|
||||
sec1 = readl_relaxed(ioaddr + PTP_STSR);
|
||||
do {
|
||||
sec0 = sec1;
|
||||
/* Get the TSSS value */
|
||||
ns = readl_relaxed(ioaddr + PTP_STNSR);
|
||||
/* Get the TSS value */
|
||||
sec1 = readl_relaxed(ioaddr + PTP_STSR);
|
||||
} while (sec0 != sec1);
|
||||
|
||||
if (systime)
|
||||
*systime = ns + (sec1 * 1000000000ULL);
|
||||
}
|
||||
|
||||
static void get_ptptime(void __iomem *ptpaddr, u64 *ptp_time)
|
||||
{
|
||||
u64 ns;
|
||||
|
||||
ns = readl(ptpaddr + PTP_ATNR);
|
||||
ns += readl(ptpaddr + PTP_ATSR) * NSEC_PER_SEC;
|
||||
|
||||
*ptp_time = ns;
|
||||
}
|
||||
|
||||
static void timestamp_interrupt(struct stmmac_priv *priv)
|
||||
{
|
||||
u32 num_snapshot, ts_status, tsync_int;
|
||||
struct ptp_clock_event event;
|
||||
u32 acr_value, channel;
|
||||
unsigned long flags;
|
||||
u64 ptp_time;
|
||||
int i;
|
||||
|
||||
if (priv->plat->flags & STMMAC_FLAG_INT_SNAPSHOT_EN) {
|
||||
wake_up(&priv->tstamp_busy_wait);
|
||||
return;
|
||||
}
|
||||
|
||||
tsync_int = readl(priv->ioaddr + GMAC_INT_STATUS) & GMAC_INT_TSIE;
|
||||
|
||||
if (!tsync_int)
|
||||
return;
|
||||
|
||||
/* Read timestamp status to clear interrupt from either external
|
||||
* timestamp or start/end of PPS.
|
||||
*/
|
||||
ts_status = readl(priv->ioaddr + GMAC_TIMESTAMP_STATUS);
|
||||
|
||||
if (!(priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN))
|
||||
return;
|
||||
|
||||
num_snapshot = (ts_status & GMAC_TIMESTAMP_ATSNS_MASK) >>
|
||||
GMAC_TIMESTAMP_ATSNS_SHIFT;
|
||||
|
||||
acr_value = readl(priv->ptpaddr + PTP_ACR);
|
||||
channel = ilog2(FIELD_GET(PTP_ACR_MASK, acr_value));
|
||||
|
||||
for (i = 0; i < num_snapshot; i++) {
|
||||
read_lock_irqsave(&priv->ptp_lock, flags);
|
||||
get_ptptime(priv->ptpaddr, &ptp_time);
|
||||
read_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
event.type = PTP_CLOCK_EXTTS;
|
||||
event.index = channel;
|
||||
event.timestamp = ptp_time;
|
||||
ptp_clock_event(priv->ptp_clock, &event);
|
||||
}
|
||||
}
|
||||
|
||||
const struct stmmac_hwtimestamp stmmac_ptp = {
|
||||
.config_hw_tstamping = config_hw_tstamping,
|
||||
.init_systime = init_systime,
|
||||
.config_sub_second_increment = config_sub_second_increment,
|
||||
.config_addend = config_addend,
|
||||
.adjust_systime = adjust_systime,
|
||||
.get_systime = get_systime,
|
||||
.get_ptptime = get_ptptime,
|
||||
.timestamp_interrupt = timestamp_interrupt,
|
||||
.hwtstamp_correct_latency = hwtstamp_correct_latency,
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,709 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
STMMAC Ethernet Driver -- MDIO bus implementation
|
||||
Provides Bus interface for MII registers
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Carl Shaw <carl.shaw@st.com>
|
||||
Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/of_mdio.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "dwxgmac2-6.12-ethercat.h"
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
|
||||
#define MII_BUSY 0x00000001
|
||||
#define MII_WRITE 0x00000002
|
||||
#define MII_DATA_MASK GENMASK(15, 0)
|
||||
|
||||
/* GMAC4 defines */
|
||||
#define MII_GMAC4_GOC_SHIFT 2
|
||||
#define MII_GMAC4_REG_ADDR_SHIFT 16
|
||||
#define MII_GMAC4_WRITE (1 << MII_GMAC4_GOC_SHIFT)
|
||||
#define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT)
|
||||
#define MII_GMAC4_C45E BIT(1)
|
||||
|
||||
/* XGMAC defines */
|
||||
#define MII_XGMAC_SADDR BIT(18)
|
||||
#define MII_XGMAC_CMD_SHIFT 16
|
||||
#define MII_XGMAC_WRITE (1 << MII_XGMAC_CMD_SHIFT)
|
||||
#define MII_XGMAC_READ (3 << MII_XGMAC_CMD_SHIFT)
|
||||
#define MII_XGMAC_BUSY BIT(22)
|
||||
#define MII_XGMAC_MAX_C22ADDR 3
|
||||
#define MII_XGMAC_C22P_MASK GENMASK(MII_XGMAC_MAX_C22ADDR, 0)
|
||||
#define MII_XGMAC_PA_SHIFT 16
|
||||
#define MII_XGMAC_DA_SHIFT 21
|
||||
|
||||
static void stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr,
|
||||
int devad, int phyreg, u32 *hw_addr)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
/* Set port as Clause 45 */
|
||||
tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
|
||||
tmp &= ~BIT(phyaddr);
|
||||
writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
|
||||
|
||||
*hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0xffff);
|
||||
*hw_addr |= devad << MII_XGMAC_DA_SHIFT;
|
||||
}
|
||||
|
||||
static void stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr,
|
||||
int phyreg, u32 *hw_addr)
|
||||
{
|
||||
u32 tmp = 0;
|
||||
|
||||
if (priv->synopsys_id < DWXGMAC_CORE_2_20) {
|
||||
/* Until ver 2.20 XGMAC does not support C22 addr >= 4. Those
|
||||
* bits above bit 3 of XGMAC_MDIO_C22P register are reserved.
|
||||
*/
|
||||
tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
|
||||
tmp &= ~MII_XGMAC_C22P_MASK;
|
||||
}
|
||||
/* Set port as Clause 22 */
|
||||
tmp |= BIT(phyaddr);
|
||||
writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
|
||||
|
||||
*hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f);
|
||||
}
|
||||
|
||||
static int stmmac_xgmac2_mdio_read(struct stmmac_priv *priv, u32 addr,
|
||||
u32 value)
|
||||
{
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
unsigned int mii_data = priv->hw->mii.data;
|
||||
u32 tmp;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(priv->device);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
|
||||
ret = -EBUSY;
|
||||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
|
||||
& priv->hw->mii.clk_csr_mask;
|
||||
value |= MII_XGMAC_READ;
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||
!(tmp & MII_XGMAC_BUSY), 100, 30000)) {
|
||||
ret = -EBUSY;
|
||||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
/* Set the MII address register to read */
|
||||
writel(addr, priv->ioaddr + mii_address);
|
||||
writel(value, priv->ioaddr + mii_data);
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||
!(tmp & MII_XGMAC_BUSY), 100, 30000)) {
|
||||
ret = -EBUSY;
|
||||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
/* Read the data from the MII data register */
|
||||
ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
|
||||
|
||||
err_disable_clks:
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stmmac_xgmac2_mdio_read_c22(struct mii_bus *bus, int phyaddr,
|
||||
int phyreg)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv;
|
||||
u32 addr;
|
||||
|
||||
priv = netdev_priv(ndev);
|
||||
|
||||
/* Until ver 2.20 XGMAC does not support C22 addr >= 4 */
|
||||
if (priv->synopsys_id < DWXGMAC_CORE_2_20 &&
|
||||
phyaddr > MII_XGMAC_MAX_C22ADDR)
|
||||
return -ENODEV;
|
||||
|
||||
stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
|
||||
|
||||
return stmmac_xgmac2_mdio_read(priv, addr, MII_XGMAC_BUSY);
|
||||
}
|
||||
|
||||
static int stmmac_xgmac2_mdio_read_c45(struct mii_bus *bus, int phyaddr,
|
||||
int devad, int phyreg)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv;
|
||||
u32 addr;
|
||||
|
||||
priv = netdev_priv(ndev);
|
||||
|
||||
stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr);
|
||||
|
||||
return stmmac_xgmac2_mdio_read(priv, addr, MII_XGMAC_BUSY);
|
||||
}
|
||||
|
||||
static int stmmac_xgmac2_mdio_write(struct stmmac_priv *priv, u32 addr,
|
||||
u32 value, u16 phydata)
|
||||
{
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
unsigned int mii_data = priv->hw->mii.data;
|
||||
u32 tmp;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(priv->device);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||
!(tmp & MII_XGMAC_BUSY), 100, 30000)) {
|
||||
ret = -EBUSY;
|
||||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
|
||||
& priv->hw->mii.clk_csr_mask;
|
||||
value |= phydata;
|
||||
value |= MII_XGMAC_WRITE;
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||
!(tmp & MII_XGMAC_BUSY), 100, 30000)) {
|
||||
ret = -EBUSY;
|
||||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
/* Set the MII address register to write */
|
||||
writel(addr, priv->ioaddr + mii_address);
|
||||
writel(value, priv->ioaddr + mii_data);
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||
!(tmp & MII_XGMAC_BUSY), 100, 30000);
|
||||
|
||||
err_disable_clks:
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stmmac_xgmac2_mdio_write_c22(struct mii_bus *bus, int phyaddr,
|
||||
int phyreg, u16 phydata)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv;
|
||||
u32 addr;
|
||||
|
||||
priv = netdev_priv(ndev);
|
||||
|
||||
/* Until ver 2.20 XGMAC does not support C22 addr >= 4 */
|
||||
if (priv->synopsys_id < DWXGMAC_CORE_2_20 &&
|
||||
phyaddr > MII_XGMAC_MAX_C22ADDR)
|
||||
return -ENODEV;
|
||||
|
||||
stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
|
||||
|
||||
return stmmac_xgmac2_mdio_write(priv, addr,
|
||||
MII_XGMAC_BUSY | MII_XGMAC_SADDR, phydata);
|
||||
}
|
||||
|
||||
static int stmmac_xgmac2_mdio_write_c45(struct mii_bus *bus, int phyaddr,
|
||||
int devad, int phyreg, u16 phydata)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv;
|
||||
u32 addr;
|
||||
|
||||
priv = netdev_priv(ndev);
|
||||
|
||||
stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr);
|
||||
|
||||
return stmmac_xgmac2_mdio_write(priv, addr, MII_XGMAC_BUSY,
|
||||
phydata);
|
||||
}
|
||||
|
||||
static int stmmac_mdio_read(struct stmmac_priv *priv, int data, u32 value)
|
||||
{
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
unsigned int mii_data = priv->hw->mii.data;
|
||||
u32 v;
|
||||
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
||||
100, 30000))
|
||||
return -EBUSY;
|
||||
|
||||
writel(data, priv->ioaddr + mii_data);
|
||||
writel(value, priv->ioaddr + mii_address);
|
||||
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
||||
100, 30000))
|
||||
return -EBUSY;
|
||||
|
||||
/* Read the data from the MII data register */
|
||||
return readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_read_c22
|
||||
* @bus: points to the mii_bus structure
|
||||
* @phyaddr: MII addr
|
||||
* @phyreg: MII reg
|
||||
* Description: it reads data from the MII register from within the phy device.
|
||||
* For the 7111 GMAC, we must set the bit 0 in the MII address register while
|
||||
* accessing the PHY registers.
|
||||
* Fortunately, it seems this has no drawback for the 7109 MAC.
|
||||
*/
|
||||
static int stmmac_mdio_read_c22(struct mii_bus *bus, int phyaddr, int phyreg)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
u32 value = MII_BUSY;
|
||||
int data = 0;
|
||||
|
||||
data = pm_runtime_resume_and_get(priv->device);
|
||||
if (data < 0)
|
||||
return data;
|
||||
|
||||
value |= (phyaddr << priv->hw->mii.addr_shift)
|
||||
& priv->hw->mii.addr_mask;
|
||||
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
|
||||
& priv->hw->mii.clk_csr_mask;
|
||||
if (priv->plat->has_gmac4)
|
||||
value |= MII_GMAC4_READ;
|
||||
|
||||
data = stmmac_mdio_read(priv, data, value);
|
||||
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_read_c45
|
||||
* @bus: points to the mii_bus structure
|
||||
* @phyaddr: MII addr
|
||||
* @devad: device address to read
|
||||
* @phyreg: MII reg
|
||||
* Description: it reads data from the MII register from within the phy device.
|
||||
* For the 7111 GMAC, we must set the bit 0 in the MII address register while
|
||||
* accessing the PHY registers.
|
||||
* Fortunately, it seems this has no drawback for the 7109 MAC.
|
||||
*/
|
||||
static int stmmac_mdio_read_c45(struct mii_bus *bus, int phyaddr, int devad,
|
||||
int phyreg)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
u32 value = MII_BUSY;
|
||||
int data = 0;
|
||||
|
||||
data = pm_runtime_get_sync(priv->device);
|
||||
if (data < 0) {
|
||||
pm_runtime_put_noidle(priv->device);
|
||||
return data;
|
||||
}
|
||||
|
||||
value |= (phyaddr << priv->hw->mii.addr_shift)
|
||||
& priv->hw->mii.addr_mask;
|
||||
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
|
||||
& priv->hw->mii.clk_csr_mask;
|
||||
value |= MII_GMAC4_READ;
|
||||
value |= MII_GMAC4_C45E;
|
||||
value &= ~priv->hw->mii.reg_mask;
|
||||
value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||
|
||||
data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT;
|
||||
|
||||
data = stmmac_mdio_read(priv, data, value);
|
||||
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int stmmac_mdio_write(struct stmmac_priv *priv, int data, u32 value)
|
||||
{
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
unsigned int mii_data = priv->hw->mii.data;
|
||||
u32 v;
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
||||
100, 30000))
|
||||
return -EBUSY;
|
||||
|
||||
/* Set the MII address register to write */
|
||||
writel(data, priv->ioaddr + mii_data);
|
||||
writel(value, priv->ioaddr + mii_address);
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
return readl_poll_timeout(priv->ioaddr + mii_address, v,
|
||||
!(v & MII_BUSY), 100, 30000);
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_write_c22
|
||||
* @bus: points to the mii_bus structure
|
||||
* @phyaddr: MII addr
|
||||
* @phyreg: MII reg
|
||||
* @phydata: phy data
|
||||
* Description: it writes the data into the MII register from within the device.
|
||||
*/
|
||||
static int stmmac_mdio_write_c22(struct mii_bus *bus, int phyaddr, int phyreg,
|
||||
u16 phydata)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
int ret, data = phydata;
|
||||
u32 value = MII_BUSY;
|
||||
|
||||
ret = pm_runtime_resume_and_get(priv->device);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
value |= (phyaddr << priv->hw->mii.addr_shift)
|
||||
& priv->hw->mii.addr_mask;
|
||||
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||
|
||||
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
|
||||
& priv->hw->mii.clk_csr_mask;
|
||||
if (priv->plat->has_gmac4)
|
||||
value |= MII_GMAC4_WRITE;
|
||||
else
|
||||
value |= MII_WRITE;
|
||||
|
||||
ret = stmmac_mdio_write(priv, data, value);
|
||||
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_write_c45
|
||||
* @bus: points to the mii_bus structure
|
||||
* @phyaddr: MII addr
|
||||
* @phyreg: MII reg
|
||||
* @devad: device address to read
|
||||
* @phydata: phy data
|
||||
* Description: it writes the data into the MII register from within the device.
|
||||
*/
|
||||
static int stmmac_mdio_write_c45(struct mii_bus *bus, int phyaddr,
|
||||
int devad, int phyreg, u16 phydata)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
int ret, data = phydata;
|
||||
u32 value = MII_BUSY;
|
||||
|
||||
ret = pm_runtime_get_sync(priv->device);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(priv->device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
value |= (phyaddr << priv->hw->mii.addr_shift)
|
||||
& priv->hw->mii.addr_mask;
|
||||
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||
|
||||
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
|
||||
& priv->hw->mii.clk_csr_mask;
|
||||
|
||||
value |= MII_GMAC4_WRITE;
|
||||
value |= MII_GMAC4_C45E;
|
||||
value &= ~priv->hw->mii.reg_mask;
|
||||
value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||
|
||||
data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT;
|
||||
|
||||
ret = stmmac_mdio_write(priv, data, value);
|
||||
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_reset
|
||||
* @bus: points to the mii_bus structure
|
||||
* Description: reset the MII bus
|
||||
*/
|
||||
int stmmac_mdio_reset(struct mii_bus *bus)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_STMMAC_PLATFORM)
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
if (priv->device->of_node) {
|
||||
struct gpio_desc *reset_gpio;
|
||||
u32 delays[3] = { 0, 0, 0 };
|
||||
|
||||
reset_gpio = devm_gpiod_get_optional(priv->device,
|
||||
"snps,reset",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(reset_gpio))
|
||||
return PTR_ERR(reset_gpio);
|
||||
|
||||
device_property_read_u32_array(priv->device,
|
||||
"snps,reset-delays-us",
|
||||
delays, ARRAY_SIZE(delays));
|
||||
|
||||
if (delays[0])
|
||||
msleep(DIV_ROUND_UP(delays[0], 1000));
|
||||
|
||||
gpiod_set_value_cansleep(reset_gpio, 1);
|
||||
if (delays[1])
|
||||
msleep(DIV_ROUND_UP(delays[1], 1000));
|
||||
|
||||
gpiod_set_value_cansleep(reset_gpio, 0);
|
||||
if (delays[2])
|
||||
msleep(DIV_ROUND_UP(delays[2], 1000));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This is a workaround for problems with the STE101P PHY.
|
||||
* It doesn't complete its reset until at least one clock cycle
|
||||
* on MDC, so perform a dummy mdio read. To be updated for GMAC4
|
||||
* if needed.
|
||||
*/
|
||||
if (!priv->plat->has_gmac4)
|
||||
writel(0, priv->ioaddr + mii_address);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmmac_pcs_setup(struct net_device *ndev)
|
||||
{
|
||||
struct fwnode_handle *devnode, *pcsnode;
|
||||
struct dw_xpcs *xpcs = NULL;
|
||||
struct stmmac_priv *priv;
|
||||
int addr, mode, ret;
|
||||
|
||||
priv = netdev_priv(ndev);
|
||||
mode = priv->plat->phy_interface;
|
||||
devnode = priv->plat->port_node;
|
||||
|
||||
if (priv->plat->pcs_init) {
|
||||
ret = priv->plat->pcs_init(priv);
|
||||
} else if (fwnode_property_present(devnode, "pcs-handle")) {
|
||||
pcsnode = fwnode_find_reference(devnode, "pcs-handle", 0);
|
||||
xpcs = xpcs_create_fwnode(pcsnode, mode);
|
||||
fwnode_handle_put(pcsnode);
|
||||
ret = PTR_ERR_OR_ZERO(xpcs);
|
||||
} else if (priv->plat->mdio_bus_data &&
|
||||
priv->plat->mdio_bus_data->pcs_mask) {
|
||||
addr = ffs(priv->plat->mdio_bus_data->pcs_mask) - 1;
|
||||
xpcs = xpcs_create_mdiodev(priv->mii, addr, mode);
|
||||
ret = PTR_ERR_OR_ZERO(xpcs);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return dev_err_probe(priv->device, ret, "No xPCS found\n");
|
||||
|
||||
priv->hw->xpcs = xpcs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stmmac_pcs_clean(struct net_device *ndev)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
|
||||
if (priv->plat->pcs_exit)
|
||||
priv->plat->pcs_exit(priv);
|
||||
|
||||
if (!priv->hw->xpcs)
|
||||
return;
|
||||
|
||||
xpcs_destroy(priv->hw->xpcs);
|
||||
priv->hw->xpcs = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_register
|
||||
* @ndev: net device structure
|
||||
* Description: it registers the MII bus
|
||||
*/
|
||||
int stmmac_mdio_register(struct net_device *ndev)
|
||||
{
|
||||
int err = 0;
|
||||
struct mii_bus *new_bus;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
|
||||
struct device_node *mdio_node = priv->plat->mdio_node;
|
||||
struct device *dev = ndev->dev.parent;
|
||||
struct fwnode_handle *fixed_node;
|
||||
struct fwnode_handle *fwnode;
|
||||
int addr, found, max_addr;
|
||||
|
||||
if (!mdio_bus_data)
|
||||
return 0;
|
||||
|
||||
new_bus = mdiobus_alloc();
|
||||
if (!new_bus)
|
||||
return -ENOMEM;
|
||||
|
||||
if (mdio_bus_data->irqs)
|
||||
memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq));
|
||||
|
||||
new_bus->name = "ec_stmmac";
|
||||
|
||||
if (priv->plat->has_xgmac) {
|
||||
new_bus->read = &stmmac_xgmac2_mdio_read_c22;
|
||||
new_bus->write = &stmmac_xgmac2_mdio_write_c22;
|
||||
new_bus->read_c45 = &stmmac_xgmac2_mdio_read_c45;
|
||||
new_bus->write_c45 = &stmmac_xgmac2_mdio_write_c45;
|
||||
|
||||
if (priv->synopsys_id < DWXGMAC_CORE_2_20) {
|
||||
/* Right now only C22 phys are supported */
|
||||
max_addr = MII_XGMAC_MAX_C22ADDR + 1;
|
||||
|
||||
/* Check if DT specified an unsupported phy addr */
|
||||
if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR)
|
||||
dev_err(dev, "Unsupported phy_addr (max=%d)\n",
|
||||
MII_XGMAC_MAX_C22ADDR);
|
||||
} else {
|
||||
/* XGMAC version 2.20 onwards support 32 phy addr */
|
||||
max_addr = PHY_MAX_ADDR;
|
||||
}
|
||||
} else {
|
||||
new_bus->read = &stmmac_mdio_read_c22;
|
||||
new_bus->write = &stmmac_mdio_write_c22;
|
||||
if (priv->plat->has_gmac4) {
|
||||
new_bus->read_c45 = &stmmac_mdio_read_c45;
|
||||
new_bus->write_c45 = &stmmac_mdio_write_c45;
|
||||
}
|
||||
|
||||
max_addr = PHY_MAX_ADDR;
|
||||
}
|
||||
|
||||
if (mdio_bus_data->needs_reset)
|
||||
new_bus->reset = &stmmac_mdio_reset;
|
||||
|
||||
snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
|
||||
new_bus->name, priv->plat->bus_id);
|
||||
new_bus->priv = ndev;
|
||||
new_bus->phy_mask = mdio_bus_data->phy_mask | mdio_bus_data->pcs_mask;
|
||||
new_bus->parent = priv->device;
|
||||
|
||||
err = of_mdiobus_register(new_bus, mdio_node);
|
||||
if (err == -ENODEV) {
|
||||
err = 0;
|
||||
dev_info(dev, "MDIO bus is disabled\n");
|
||||
goto bus_register_fail;
|
||||
} else if (err) {
|
||||
dev_err_probe(dev, err, "Cannot register the MDIO bus\n");
|
||||
goto bus_register_fail;
|
||||
}
|
||||
|
||||
/* Looks like we need a dummy read for XGMAC only and C45 PHYs */
|
||||
if (priv->plat->has_xgmac)
|
||||
stmmac_xgmac2_mdio_read_c45(new_bus, 0, 0, 0);
|
||||
|
||||
/* If fixed-link is set, skip PHY scanning */
|
||||
fwnode = priv->plat->port_node;
|
||||
if (!fwnode)
|
||||
fwnode = dev_fwnode(priv->device);
|
||||
|
||||
if (fwnode) {
|
||||
fixed_node = fwnode_get_named_child_node(fwnode, "fixed-link");
|
||||
if (fixed_node) {
|
||||
fwnode_handle_put(fixed_node);
|
||||
goto bus_register_done;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->plat->phy_node || mdio_node)
|
||||
goto bus_register_done;
|
||||
|
||||
found = 0;
|
||||
for (addr = 0; addr < max_addr; addr++) {
|
||||
struct phy_device *phydev = mdiobus_get_phy(new_bus, addr);
|
||||
|
||||
if (!phydev)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If an IRQ was provided to be assigned after
|
||||
* the bus probe, do it here.
|
||||
*/
|
||||
if (!mdio_bus_data->irqs &&
|
||||
(mdio_bus_data->probed_phy_irq > 0)) {
|
||||
new_bus->irq[addr] = mdio_bus_data->probed_phy_irq;
|
||||
phydev->irq = mdio_bus_data->probed_phy_irq;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're going to bind the MAC to this PHY bus,
|
||||
* and no PHY number was provided to the MAC,
|
||||
* use the one probed here.
|
||||
*/
|
||||
if (priv->plat->phy_addr == -1)
|
||||
priv->plat->phy_addr = addr;
|
||||
|
||||
phy_attached_info(phydev);
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (!found && !mdio_node) {
|
||||
dev_warn(dev, "No PHY found\n");
|
||||
err = -ENODEV;
|
||||
goto no_phy_found;
|
||||
}
|
||||
|
||||
bus_register_done:
|
||||
priv->mii = new_bus;
|
||||
|
||||
return 0;
|
||||
|
||||
no_phy_found:
|
||||
mdiobus_unregister(new_bus);
|
||||
bus_register_fail:
|
||||
mdiobus_free(new_bus);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_unregister
|
||||
* @ndev: net device structure
|
||||
* Description: it unregisters the MII bus
|
||||
*/
|
||||
int stmmac_mdio_unregister(struct net_device *ndev)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
|
||||
if (!priv->mii)
|
||||
return 0;
|
||||
|
||||
mdiobus_unregister(priv->mii);
|
||||
priv->mii->priv = NULL;
|
||||
mdiobus_free(priv->mii);
|
||||
priv->mii = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,709 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
STMMAC Ethernet Driver -- MDIO bus implementation
|
||||
Provides Bus interface for MII registers
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
|
||||
Author: Carl Shaw <carl.shaw@st.com>
|
||||
Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/of_mdio.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "dwxgmac2.h"
|
||||
#include "stmmac.h"
|
||||
|
||||
#define MII_BUSY 0x00000001
|
||||
#define MII_WRITE 0x00000002
|
||||
#define MII_DATA_MASK GENMASK(15, 0)
|
||||
|
||||
/* GMAC4 defines */
|
||||
#define MII_GMAC4_GOC_SHIFT 2
|
||||
#define MII_GMAC4_REG_ADDR_SHIFT 16
|
||||
#define MII_GMAC4_WRITE (1 << MII_GMAC4_GOC_SHIFT)
|
||||
#define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT)
|
||||
#define MII_GMAC4_C45E BIT(1)
|
||||
|
||||
/* XGMAC defines */
|
||||
#define MII_XGMAC_SADDR BIT(18)
|
||||
#define MII_XGMAC_CMD_SHIFT 16
|
||||
#define MII_XGMAC_WRITE (1 << MII_XGMAC_CMD_SHIFT)
|
||||
#define MII_XGMAC_READ (3 << MII_XGMAC_CMD_SHIFT)
|
||||
#define MII_XGMAC_BUSY BIT(22)
|
||||
#define MII_XGMAC_MAX_C22ADDR 3
|
||||
#define MII_XGMAC_C22P_MASK GENMASK(MII_XGMAC_MAX_C22ADDR, 0)
|
||||
#define MII_XGMAC_PA_SHIFT 16
|
||||
#define MII_XGMAC_DA_SHIFT 21
|
||||
|
||||
static void stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr,
|
||||
int devad, int phyreg, u32 *hw_addr)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
/* Set port as Clause 45 */
|
||||
tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
|
||||
tmp &= ~BIT(phyaddr);
|
||||
writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
|
||||
|
||||
*hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0xffff);
|
||||
*hw_addr |= devad << MII_XGMAC_DA_SHIFT;
|
||||
}
|
||||
|
||||
static void stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr,
|
||||
int phyreg, u32 *hw_addr)
|
||||
{
|
||||
u32 tmp = 0;
|
||||
|
||||
if (priv->synopsys_id < DWXGMAC_CORE_2_20) {
|
||||
/* Until ver 2.20 XGMAC does not support C22 addr >= 4. Those
|
||||
* bits above bit 3 of XGMAC_MDIO_C22P register are reserved.
|
||||
*/
|
||||
tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
|
||||
tmp &= ~MII_XGMAC_C22P_MASK;
|
||||
}
|
||||
/* Set port as Clause 22 */
|
||||
tmp |= BIT(phyaddr);
|
||||
writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
|
||||
|
||||
*hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f);
|
||||
}
|
||||
|
||||
static int stmmac_xgmac2_mdio_read(struct stmmac_priv *priv, u32 addr,
|
||||
u32 value)
|
||||
{
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
unsigned int mii_data = priv->hw->mii.data;
|
||||
u32 tmp;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(priv->device);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
|
||||
ret = -EBUSY;
|
||||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
|
||||
& priv->hw->mii.clk_csr_mask;
|
||||
value |= MII_XGMAC_READ;
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
|
||||
ret = -EBUSY;
|
||||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
/* Set the MII address register to read */
|
||||
writel(addr, priv->ioaddr + mii_address);
|
||||
writel(value, priv->ioaddr + mii_data);
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
|
||||
ret = -EBUSY;
|
||||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
/* Read the data from the MII data register */
|
||||
ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
|
||||
|
||||
err_disable_clks:
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stmmac_xgmac2_mdio_read_c22(struct mii_bus *bus, int phyaddr,
|
||||
int phyreg)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv;
|
||||
u32 addr;
|
||||
|
||||
priv = netdev_priv(ndev);
|
||||
|
||||
/* Until ver 2.20 XGMAC does not support C22 addr >= 4 */
|
||||
if (priv->synopsys_id < DWXGMAC_CORE_2_20 &&
|
||||
phyaddr > MII_XGMAC_MAX_C22ADDR)
|
||||
return -ENODEV;
|
||||
|
||||
stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
|
||||
|
||||
return stmmac_xgmac2_mdio_read(priv, addr, MII_XGMAC_BUSY);
|
||||
}
|
||||
|
||||
static int stmmac_xgmac2_mdio_read_c45(struct mii_bus *bus, int phyaddr,
|
||||
int devad, int phyreg)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv;
|
||||
u32 addr;
|
||||
|
||||
priv = netdev_priv(ndev);
|
||||
|
||||
stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr);
|
||||
|
||||
return stmmac_xgmac2_mdio_read(priv, addr, MII_XGMAC_BUSY);
|
||||
}
|
||||
|
||||
static int stmmac_xgmac2_mdio_write(struct stmmac_priv *priv, u32 addr,
|
||||
u32 value, u16 phydata)
|
||||
{
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
unsigned int mii_data = priv->hw->mii.data;
|
||||
u32 tmp;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(priv->device);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
|
||||
ret = -EBUSY;
|
||||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
|
||||
& priv->hw->mii.clk_csr_mask;
|
||||
value |= phydata;
|
||||
value |= MII_XGMAC_WRITE;
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
|
||||
ret = -EBUSY;
|
||||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
/* Set the MII address register to write */
|
||||
writel(addr, priv->ioaddr + mii_address);
|
||||
writel(value, priv->ioaddr + mii_data);
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||
!(tmp & MII_XGMAC_BUSY), 100, 10000);
|
||||
|
||||
err_disable_clks:
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stmmac_xgmac2_mdio_write_c22(struct mii_bus *bus, int phyaddr,
|
||||
int phyreg, u16 phydata)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv;
|
||||
u32 addr;
|
||||
|
||||
priv = netdev_priv(ndev);
|
||||
|
||||
/* Until ver 2.20 XGMAC does not support C22 addr >= 4 */
|
||||
if (priv->synopsys_id < DWXGMAC_CORE_2_20 &&
|
||||
phyaddr > MII_XGMAC_MAX_C22ADDR)
|
||||
return -ENODEV;
|
||||
|
||||
stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
|
||||
|
||||
return stmmac_xgmac2_mdio_write(priv, addr,
|
||||
MII_XGMAC_BUSY | MII_XGMAC_SADDR, phydata);
|
||||
}
|
||||
|
||||
static int stmmac_xgmac2_mdio_write_c45(struct mii_bus *bus, int phyaddr,
|
||||
int devad, int phyreg, u16 phydata)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv;
|
||||
u32 addr;
|
||||
|
||||
priv = netdev_priv(ndev);
|
||||
|
||||
stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr);
|
||||
|
||||
return stmmac_xgmac2_mdio_write(priv, addr, MII_XGMAC_BUSY,
|
||||
phydata);
|
||||
}
|
||||
|
||||
static int stmmac_mdio_read(struct stmmac_priv *priv, int data, u32 value)
|
||||
{
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
unsigned int mii_data = priv->hw->mii.data;
|
||||
u32 v;
|
||||
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
||||
100, 10000))
|
||||
return -EBUSY;
|
||||
|
||||
writel(data, priv->ioaddr + mii_data);
|
||||
writel(value, priv->ioaddr + mii_address);
|
||||
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
||||
100, 10000))
|
||||
return -EBUSY;
|
||||
|
||||
/* Read the data from the MII data register */
|
||||
return readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_read_c22
|
||||
* @bus: points to the mii_bus structure
|
||||
* @phyaddr: MII addr
|
||||
* @phyreg: MII reg
|
||||
* Description: it reads data from the MII register from within the phy device.
|
||||
* For the 7111 GMAC, we must set the bit 0 in the MII address register while
|
||||
* accessing the PHY registers.
|
||||
* Fortunately, it seems this has no drawback for the 7109 MAC.
|
||||
*/
|
||||
static int stmmac_mdio_read_c22(struct mii_bus *bus, int phyaddr, int phyreg)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
u32 value = MII_BUSY;
|
||||
int data = 0;
|
||||
|
||||
data = pm_runtime_resume_and_get(priv->device);
|
||||
if (data < 0)
|
||||
return data;
|
||||
|
||||
value |= (phyaddr << priv->hw->mii.addr_shift)
|
||||
& priv->hw->mii.addr_mask;
|
||||
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
|
||||
& priv->hw->mii.clk_csr_mask;
|
||||
if (priv->plat->has_gmac4)
|
||||
value |= MII_GMAC4_READ;
|
||||
|
||||
data = stmmac_mdio_read(priv, data, value);
|
||||
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_read_c45
|
||||
* @bus: points to the mii_bus structure
|
||||
* @phyaddr: MII addr
|
||||
* @devad: device address to read
|
||||
* @phyreg: MII reg
|
||||
* Description: it reads data from the MII register from within the phy device.
|
||||
* For the 7111 GMAC, we must set the bit 0 in the MII address register while
|
||||
* accessing the PHY registers.
|
||||
* Fortunately, it seems this has no drawback for the 7109 MAC.
|
||||
*/
|
||||
static int stmmac_mdio_read_c45(struct mii_bus *bus, int phyaddr, int devad,
|
||||
int phyreg)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
u32 value = MII_BUSY;
|
||||
int data = 0;
|
||||
|
||||
data = pm_runtime_get_sync(priv->device);
|
||||
if (data < 0) {
|
||||
pm_runtime_put_noidle(priv->device);
|
||||
return data;
|
||||
}
|
||||
|
||||
value |= (phyaddr << priv->hw->mii.addr_shift)
|
||||
& priv->hw->mii.addr_mask;
|
||||
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
|
||||
& priv->hw->mii.clk_csr_mask;
|
||||
value |= MII_GMAC4_READ;
|
||||
value |= MII_GMAC4_C45E;
|
||||
value &= ~priv->hw->mii.reg_mask;
|
||||
value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||
|
||||
data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT;
|
||||
|
||||
data = stmmac_mdio_read(priv, data, value);
|
||||
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int stmmac_mdio_write(struct stmmac_priv *priv, int data, u32 value)
|
||||
{
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
unsigned int mii_data = priv->hw->mii.data;
|
||||
u32 v;
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
||||
100, 10000))
|
||||
return -EBUSY;
|
||||
|
||||
/* Set the MII address register to write */
|
||||
writel(data, priv->ioaddr + mii_data);
|
||||
writel(value, priv->ioaddr + mii_address);
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
return readl_poll_timeout(priv->ioaddr + mii_address, v,
|
||||
!(v & MII_BUSY), 100, 10000);
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_write_c22
|
||||
* @bus: points to the mii_bus structure
|
||||
* @phyaddr: MII addr
|
||||
* @phyreg: MII reg
|
||||
* @phydata: phy data
|
||||
* Description: it writes the data into the MII register from within the device.
|
||||
*/
|
||||
static int stmmac_mdio_write_c22(struct mii_bus *bus, int phyaddr, int phyreg,
|
||||
u16 phydata)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
int ret, data = phydata;
|
||||
u32 value = MII_BUSY;
|
||||
|
||||
ret = pm_runtime_resume_and_get(priv->device);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
value |= (phyaddr << priv->hw->mii.addr_shift)
|
||||
& priv->hw->mii.addr_mask;
|
||||
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||
|
||||
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
|
||||
& priv->hw->mii.clk_csr_mask;
|
||||
if (priv->plat->has_gmac4)
|
||||
value |= MII_GMAC4_WRITE;
|
||||
else
|
||||
value |= MII_WRITE;
|
||||
|
||||
ret = stmmac_mdio_write(priv, data, value);
|
||||
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_write_c45
|
||||
* @bus: points to the mii_bus structure
|
||||
* @phyaddr: MII addr
|
||||
* @phyreg: MII reg
|
||||
* @devad: device address to read
|
||||
* @phydata: phy data
|
||||
* Description: it writes the data into the MII register from within the device.
|
||||
*/
|
||||
static int stmmac_mdio_write_c45(struct mii_bus *bus, int phyaddr,
|
||||
int devad, int phyreg, u16 phydata)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
int ret, data = phydata;
|
||||
u32 value = MII_BUSY;
|
||||
|
||||
ret = pm_runtime_get_sync(priv->device);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(priv->device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
value |= (phyaddr << priv->hw->mii.addr_shift)
|
||||
& priv->hw->mii.addr_mask;
|
||||
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||
|
||||
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
|
||||
& priv->hw->mii.clk_csr_mask;
|
||||
|
||||
value |= MII_GMAC4_WRITE;
|
||||
value |= MII_GMAC4_C45E;
|
||||
value &= ~priv->hw->mii.reg_mask;
|
||||
value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||
|
||||
data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT;
|
||||
|
||||
ret = stmmac_mdio_write(priv, data, value);
|
||||
|
||||
pm_runtime_put(priv->device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_reset
|
||||
* @bus: points to the mii_bus structure
|
||||
* Description: reset the MII bus
|
||||
*/
|
||||
int stmmac_mdio_reset(struct mii_bus *bus)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_STMMAC_PLATFORM)
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
if (priv->device->of_node) {
|
||||
struct gpio_desc *reset_gpio;
|
||||
u32 delays[3] = { 0, 0, 0 };
|
||||
|
||||
reset_gpio = devm_gpiod_get_optional(priv->device,
|
||||
"snps,reset",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(reset_gpio))
|
||||
return PTR_ERR(reset_gpio);
|
||||
|
||||
device_property_read_u32_array(priv->device,
|
||||
"snps,reset-delays-us",
|
||||
delays, ARRAY_SIZE(delays));
|
||||
|
||||
if (delays[0])
|
||||
msleep(DIV_ROUND_UP(delays[0], 1000));
|
||||
|
||||
gpiod_set_value_cansleep(reset_gpio, 1);
|
||||
if (delays[1])
|
||||
msleep(DIV_ROUND_UP(delays[1], 1000));
|
||||
|
||||
gpiod_set_value_cansleep(reset_gpio, 0);
|
||||
if (delays[2])
|
||||
msleep(DIV_ROUND_UP(delays[2], 1000));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This is a workaround for problems with the STE101P PHY.
|
||||
* It doesn't complete its reset until at least one clock cycle
|
||||
* on MDC, so perform a dummy mdio read. To be updated for GMAC4
|
||||
* if needed.
|
||||
*/
|
||||
if (!priv->plat->has_gmac4)
|
||||
writel(0, priv->ioaddr + mii_address);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmmac_pcs_setup(struct net_device *ndev)
|
||||
{
|
||||
struct fwnode_handle *devnode, *pcsnode;
|
||||
struct dw_xpcs *xpcs = NULL;
|
||||
struct stmmac_priv *priv;
|
||||
int addr, mode, ret;
|
||||
|
||||
priv = netdev_priv(ndev);
|
||||
mode = priv->plat->phy_interface;
|
||||
devnode = priv->plat->port_node;
|
||||
|
||||
if (priv->plat->pcs_init) {
|
||||
ret = priv->plat->pcs_init(priv);
|
||||
} else if (fwnode_property_present(devnode, "pcs-handle")) {
|
||||
pcsnode = fwnode_find_reference(devnode, "pcs-handle", 0);
|
||||
xpcs = xpcs_create_fwnode(pcsnode, mode);
|
||||
fwnode_handle_put(pcsnode);
|
||||
ret = PTR_ERR_OR_ZERO(xpcs);
|
||||
} else if (priv->plat->mdio_bus_data &&
|
||||
priv->plat->mdio_bus_data->pcs_mask) {
|
||||
addr = ffs(priv->plat->mdio_bus_data->pcs_mask) - 1;
|
||||
xpcs = xpcs_create_mdiodev(priv->mii, addr, mode);
|
||||
ret = PTR_ERR_OR_ZERO(xpcs);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return dev_err_probe(priv->device, ret, "No xPCS found\n");
|
||||
|
||||
priv->hw->xpcs = xpcs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stmmac_pcs_clean(struct net_device *ndev)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
|
||||
if (priv->plat->pcs_exit)
|
||||
priv->plat->pcs_exit(priv);
|
||||
|
||||
if (!priv->hw->xpcs)
|
||||
return;
|
||||
|
||||
xpcs_destroy(priv->hw->xpcs);
|
||||
priv->hw->xpcs = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_register
|
||||
* @ndev: net device structure
|
||||
* Description: it registers the MII bus
|
||||
*/
|
||||
int stmmac_mdio_register(struct net_device *ndev)
|
||||
{
|
||||
int err = 0;
|
||||
struct mii_bus *new_bus;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
|
||||
struct device_node *mdio_node = priv->plat->mdio_node;
|
||||
struct device *dev = ndev->dev.parent;
|
||||
struct fwnode_handle *fixed_node;
|
||||
struct fwnode_handle *fwnode;
|
||||
int addr, found, max_addr;
|
||||
|
||||
if (!mdio_bus_data)
|
||||
return 0;
|
||||
|
||||
new_bus = mdiobus_alloc();
|
||||
if (!new_bus)
|
||||
return -ENOMEM;
|
||||
|
||||
if (mdio_bus_data->irqs)
|
||||
memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq));
|
||||
|
||||
new_bus->name = "stmmac";
|
||||
|
||||
if (priv->plat->has_xgmac) {
|
||||
new_bus->read = &stmmac_xgmac2_mdio_read_c22;
|
||||
new_bus->write = &stmmac_xgmac2_mdio_write_c22;
|
||||
new_bus->read_c45 = &stmmac_xgmac2_mdio_read_c45;
|
||||
new_bus->write_c45 = &stmmac_xgmac2_mdio_write_c45;
|
||||
|
||||
if (priv->synopsys_id < DWXGMAC_CORE_2_20) {
|
||||
/* Right now only C22 phys are supported */
|
||||
max_addr = MII_XGMAC_MAX_C22ADDR + 1;
|
||||
|
||||
/* Check if DT specified an unsupported phy addr */
|
||||
if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR)
|
||||
dev_err(dev, "Unsupported phy_addr (max=%d)\n",
|
||||
MII_XGMAC_MAX_C22ADDR);
|
||||
} else {
|
||||
/* XGMAC version 2.20 onwards support 32 phy addr */
|
||||
max_addr = PHY_MAX_ADDR;
|
||||
}
|
||||
} else {
|
||||
new_bus->read = &stmmac_mdio_read_c22;
|
||||
new_bus->write = &stmmac_mdio_write_c22;
|
||||
if (priv->plat->has_gmac4) {
|
||||
new_bus->read_c45 = &stmmac_mdio_read_c45;
|
||||
new_bus->write_c45 = &stmmac_mdio_write_c45;
|
||||
}
|
||||
|
||||
max_addr = PHY_MAX_ADDR;
|
||||
}
|
||||
|
||||
if (mdio_bus_data->needs_reset)
|
||||
new_bus->reset = &stmmac_mdio_reset;
|
||||
|
||||
snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
|
||||
new_bus->name, priv->plat->bus_id);
|
||||
new_bus->priv = ndev;
|
||||
new_bus->phy_mask = mdio_bus_data->phy_mask | mdio_bus_data->pcs_mask;
|
||||
new_bus->parent = priv->device;
|
||||
|
||||
err = of_mdiobus_register(new_bus, mdio_node);
|
||||
if (err == -ENODEV) {
|
||||
err = 0;
|
||||
dev_info(dev, "MDIO bus is disabled\n");
|
||||
goto bus_register_fail;
|
||||
} else if (err) {
|
||||
dev_err_probe(dev, err, "Cannot register the MDIO bus\n");
|
||||
goto bus_register_fail;
|
||||
}
|
||||
|
||||
/* Looks like we need a dummy read for XGMAC only and C45 PHYs */
|
||||
if (priv->plat->has_xgmac)
|
||||
stmmac_xgmac2_mdio_read_c45(new_bus, 0, 0, 0);
|
||||
|
||||
/* If fixed-link is set, skip PHY scanning */
|
||||
fwnode = priv->plat->port_node;
|
||||
if (!fwnode)
|
||||
fwnode = dev_fwnode(priv->device);
|
||||
|
||||
if (fwnode) {
|
||||
fixed_node = fwnode_get_named_child_node(fwnode, "fixed-link");
|
||||
if (fixed_node) {
|
||||
fwnode_handle_put(fixed_node);
|
||||
goto bus_register_done;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->plat->phy_node || mdio_node)
|
||||
goto bus_register_done;
|
||||
|
||||
found = 0;
|
||||
for (addr = 0; addr < max_addr; addr++) {
|
||||
struct phy_device *phydev = mdiobus_get_phy(new_bus, addr);
|
||||
|
||||
if (!phydev)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If an IRQ was provided to be assigned after
|
||||
* the bus probe, do it here.
|
||||
*/
|
||||
if (!mdio_bus_data->irqs &&
|
||||
(mdio_bus_data->probed_phy_irq > 0)) {
|
||||
new_bus->irq[addr] = mdio_bus_data->probed_phy_irq;
|
||||
phydev->irq = mdio_bus_data->probed_phy_irq;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're going to bind the MAC to this PHY bus,
|
||||
* and no PHY number was provided to the MAC,
|
||||
* use the one probed here.
|
||||
*/
|
||||
if (priv->plat->phy_addr == -1)
|
||||
priv->plat->phy_addr = addr;
|
||||
|
||||
phy_attached_info(phydev);
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (!found && !mdio_node) {
|
||||
dev_warn(dev, "No PHY found\n");
|
||||
err = -ENODEV;
|
||||
goto no_phy_found;
|
||||
}
|
||||
|
||||
bus_register_done:
|
||||
priv->mii = new_bus;
|
||||
|
||||
return 0;
|
||||
|
||||
no_phy_found:
|
||||
mdiobus_unregister(new_bus);
|
||||
bus_register_fail:
|
||||
mdiobus_free(new_bus);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_unregister
|
||||
* @ndev: net device structure
|
||||
* Description: it unregisters the MII bus
|
||||
*/
|
||||
int stmmac_mdio_unregister(struct net_device *ndev)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
|
||||
if (!priv->mii)
|
||||
return 0;
|
||||
|
||||
mdiobus_unregister(priv->mii);
|
||||
priv->mii->priv = NULL;
|
||||
mdiobus_free(priv->mii);
|
||||
priv->mii = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This contains the functions to handle the pci driver.
|
||||
|
||||
Copyright (C) 2011-2012 Vayavya Labs Pvt Ltd
|
||||
|
||||
|
||||
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
|
||||
struct stmmac_pci_info {
|
||||
int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat);
|
||||
};
|
||||
|
||||
static void common_default_data(struct plat_stmmacenet_data *plat)
|
||||
{
|
||||
plat->clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
|
||||
plat->has_gmac = 1;
|
||||
plat->force_sf_dma_mode = 1;
|
||||
|
||||
plat->mdio_bus_data->needs_reset = true;
|
||||
|
||||
/* Set default value for multicast hash bins */
|
||||
plat->multicast_filter_bins = HASH_TABLE_SIZE;
|
||||
|
||||
/* Set default value for unicast filter entries */
|
||||
plat->unicast_filter_entries = 1;
|
||||
|
||||
/* Set the maxmtu to a default of JUMBO_LEN */
|
||||
plat->maxmtu = JUMBO_LEN;
|
||||
|
||||
/* Set default number of RX and TX queues to use */
|
||||
plat->tx_queues_to_use = 1;
|
||||
plat->rx_queues_to_use = 1;
|
||||
|
||||
/* Disable Priority config by default */
|
||||
plat->tx_queues_cfg[0].use_prio = false;
|
||||
plat->rx_queues_cfg[0].use_prio = false;
|
||||
|
||||
/* Disable RX queues routing by default */
|
||||
plat->rx_queues_cfg[0].pkt_route = 0x0;
|
||||
}
|
||||
|
||||
static int stmmac_default_data(struct pci_dev *pdev,
|
||||
struct plat_stmmacenet_data *plat)
|
||||
{
|
||||
/* Set common default data first */
|
||||
common_default_data(plat);
|
||||
|
||||
plat->bus_id = 1;
|
||||
plat->phy_addr = 0;
|
||||
plat->phy_interface = PHY_INTERFACE_MODE_GMII;
|
||||
|
||||
plat->dma_cfg->pbl = 32;
|
||||
plat->dma_cfg->pblx8 = true;
|
||||
/* TODO: AXI */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct stmmac_pci_info stmmac_pci_info = {
|
||||
.setup = stmmac_default_data,
|
||||
};
|
||||
|
||||
static int snps_gmac5_default_data(struct pci_dev *pdev,
|
||||
struct plat_stmmacenet_data *plat)
|
||||
{
|
||||
int i;
|
||||
|
||||
plat->clk_csr = 5;
|
||||
plat->has_gmac4 = 1;
|
||||
plat->force_sf_dma_mode = 1;
|
||||
plat->flags |= STMMAC_FLAG_TSO_EN;
|
||||
plat->pmt = 1;
|
||||
|
||||
/* Set default value for multicast hash bins */
|
||||
plat->multicast_filter_bins = HASH_TABLE_SIZE;
|
||||
|
||||
/* Set default value for unicast filter entries */
|
||||
plat->unicast_filter_entries = 1;
|
||||
|
||||
/* Set the maxmtu to a default of JUMBO_LEN */
|
||||
plat->maxmtu = JUMBO_LEN;
|
||||
|
||||
/* Set default number of RX and TX queues to use */
|
||||
plat->tx_queues_to_use = 4;
|
||||
plat->rx_queues_to_use = 4;
|
||||
|
||||
plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR;
|
||||
for (i = 0; i < plat->tx_queues_to_use; i++) {
|
||||
plat->tx_queues_cfg[i].use_prio = false;
|
||||
plat->tx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
|
||||
plat->tx_queues_cfg[i].weight = 25;
|
||||
if (i > 0)
|
||||
plat->tx_queues_cfg[i].tbs_en = 1;
|
||||
}
|
||||
|
||||
plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
|
||||
for (i = 0; i < plat->rx_queues_to_use; i++) {
|
||||
plat->rx_queues_cfg[i].use_prio = false;
|
||||
plat->rx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
|
||||
plat->rx_queues_cfg[i].pkt_route = 0x0;
|
||||
plat->rx_queues_cfg[i].chan = i;
|
||||
}
|
||||
|
||||
plat->bus_id = 1;
|
||||
plat->phy_addr = -1;
|
||||
plat->phy_interface = PHY_INTERFACE_MODE_GMII;
|
||||
|
||||
plat->dma_cfg->pbl = 32;
|
||||
plat->dma_cfg->pblx8 = true;
|
||||
|
||||
/* Axi Configuration */
|
||||
plat->axi = devm_kzalloc(&pdev->dev, sizeof(*plat->axi), GFP_KERNEL);
|
||||
if (!plat->axi)
|
||||
return -ENOMEM;
|
||||
|
||||
plat->axi->axi_wr_osr_lmt = 31;
|
||||
plat->axi->axi_rd_osr_lmt = 31;
|
||||
|
||||
plat->axi->axi_fb = false;
|
||||
plat->axi->axi_blen[0] = 4;
|
||||
plat->axi->axi_blen[1] = 8;
|
||||
plat->axi->axi_blen[2] = 16;
|
||||
plat->axi->axi_blen[3] = 32;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct stmmac_pci_info snps_gmac5_pci_info = {
|
||||
.setup = snps_gmac5_default_data,
|
||||
};
|
||||
|
||||
/**
|
||||
* stmmac_pci_probe
|
||||
*
|
||||
* @pdev: pci device pointer
|
||||
* @id: pointer to table of device id/id's.
|
||||
*
|
||||
* Description: This probing function gets called for all PCI devices which
|
||||
* match the ID table and are not "owned" by other driver yet. This function
|
||||
* gets passed a "struct pci_dev *" for each device whose entry in the ID table
|
||||
* matches the device. The probe functions returns zero when the driver choose
|
||||
* to take "ownership" of the device or an error code(-ve no) otherwise.
|
||||
*/
|
||||
static int stmmac_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data;
|
||||
struct plat_stmmacenet_data *plat;
|
||||
struct stmmac_resources res;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
|
||||
if (!plat)
|
||||
return -ENOMEM;
|
||||
|
||||
plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*plat->mdio_bus_data),
|
||||
GFP_KERNEL);
|
||||
if (!plat->mdio_bus_data)
|
||||
return -ENOMEM;
|
||||
|
||||
plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg),
|
||||
GFP_KERNEL);
|
||||
if (!plat->dma_cfg)
|
||||
return -ENOMEM;
|
||||
|
||||
plat->safety_feat_cfg = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*plat->safety_feat_cfg),
|
||||
GFP_KERNEL);
|
||||
if (!plat->safety_feat_cfg)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Enable pci device */
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get the base address of device */
|
||||
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
|
||||
if (pci_resource_len(pdev, i) == 0)
|
||||
continue;
|
||||
ret = pcim_iomap_regions(pdev, BIT(i), pci_name(pdev));
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
ret = info->setup(pdev, plat);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memset(&res, 0, sizeof(res));
|
||||
res.addr = pcim_iomap_table(pdev)[i];
|
||||
res.wol_irq = pdev->irq;
|
||||
res.irq = pdev->irq;
|
||||
|
||||
plat->safety_feat_cfg->tsoee = 1;
|
||||
plat->safety_feat_cfg->mrxpee = 1;
|
||||
plat->safety_feat_cfg->mestee = 1;
|
||||
plat->safety_feat_cfg->mrxee = 1;
|
||||
plat->safety_feat_cfg->mtxee = 1;
|
||||
plat->safety_feat_cfg->epsi = 1;
|
||||
plat->safety_feat_cfg->edpp = 1;
|
||||
plat->safety_feat_cfg->prtyen = 1;
|
||||
plat->safety_feat_cfg->tmouten = 1;
|
||||
|
||||
return stmmac_ec_dvr_probe(&pdev->dev, plat, &res);
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_pci_remove
|
||||
*
|
||||
* @pdev: platform device pointer
|
||||
* Description: this function calls the main to free the net resources
|
||||
* and releases the PCI resources.
|
||||
*/
|
||||
static void stmmac_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
stmmac_ec_dvr_remove(&pdev->dev);
|
||||
|
||||
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
|
||||
if (pci_resource_len(pdev, i) == 0)
|
||||
continue;
|
||||
pcim_iounmap_regions(pdev, BIT(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int __maybe_unused stmmac_pci_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
int ret;
|
||||
|
||||
ret = stmmac_suspend(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pci_save_state(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_disable_device(pdev);
|
||||
pci_wake_from_d3(pdev, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused stmmac_pci_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
int ret;
|
||||
|
||||
pci_restore_state(pdev);
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
return stmmac_resume(dev);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume);
|
||||
|
||||
/* synthetic ID, no official vendor */
|
||||
#define PCI_VENDOR_ID_STMMAC 0x0700
|
||||
|
||||
#define PCI_DEVICE_ID_STMMAC_STMMAC 0x1108
|
||||
#define PCI_DEVICE_ID_SYNOPSYS_GMAC5_ID 0x7102
|
||||
|
||||
static const struct pci_device_id stmmac_id_table[] = {
|
||||
{ PCI_DEVICE_DATA(STMMAC, STMMAC, &stmmac_pci_info) },
|
||||
{ PCI_DEVICE_DATA(STMICRO, MAC, &stmmac_pci_info) },
|
||||
{ PCI_DEVICE_DATA(SYNOPSYS, GMAC5_ID, &snps_gmac5_pci_info) },
|
||||
{}
|
||||
};
|
||||
|
||||
//MODULE_DEVICE_TABLE(pci, stmmac_id_table);
|
||||
|
||||
static struct pci_driver stmmac_pci_driver = {
|
||||
.name = STMMAC_RESOURCE_NAME,
|
||||
.id_table = stmmac_id_table,
|
||||
.probe = stmmac_pci_probe,
|
||||
.remove = stmmac_pci_remove,
|
||||
.driver = {
|
||||
.pm = &stmmac_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init stmmac_pci_init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = stmmac_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = pci_register_driver(&stmmac_pci_driver);
|
||||
if (ret) {
|
||||
stmmac_exit();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit stmmac_pci_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&stmmac_pci_driver);
|
||||
stmmac_exit();
|
||||
}
|
||||
|
||||
module_init(stmmac_pci_init);
|
||||
module_exit(stmmac_pci_exit);
|
||||
|
||||
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PCI driver (EtherCAT-enabled)");
|
||||
MODULE_AUTHOR("Rayagond Kokatanur <rayagond.kokatanur@vayavyalabs.com>");
|
||||
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -0,0 +1,313 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
This contains the functions to handle the pci driver.
|
||||
|
||||
Copyright (C) 2011-2012 Vayavya Labs Pvt Ltd
|
||||
|
||||
|
||||
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
#include "stmmac.h"
|
||||
|
||||
struct stmmac_pci_info {
|
||||
int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat);
|
||||
};
|
||||
|
||||
static void common_default_data(struct plat_stmmacenet_data *plat)
|
||||
{
|
||||
plat->clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
|
||||
plat->has_gmac = 1;
|
||||
plat->force_sf_dma_mode = 1;
|
||||
|
||||
plat->mdio_bus_data->needs_reset = true;
|
||||
|
||||
/* Set default value for multicast hash bins */
|
||||
plat->multicast_filter_bins = HASH_TABLE_SIZE;
|
||||
|
||||
/* Set default value for unicast filter entries */
|
||||
plat->unicast_filter_entries = 1;
|
||||
|
||||
/* Set the maxmtu to a default of JUMBO_LEN */
|
||||
plat->maxmtu = JUMBO_LEN;
|
||||
|
||||
/* Set default number of RX and TX queues to use */
|
||||
plat->tx_queues_to_use = 1;
|
||||
plat->rx_queues_to_use = 1;
|
||||
|
||||
/* Disable Priority config by default */
|
||||
plat->tx_queues_cfg[0].use_prio = false;
|
||||
plat->rx_queues_cfg[0].use_prio = false;
|
||||
|
||||
/* Disable RX queues routing by default */
|
||||
plat->rx_queues_cfg[0].pkt_route = 0x0;
|
||||
}
|
||||
|
||||
static int stmmac_default_data(struct pci_dev *pdev,
|
||||
struct plat_stmmacenet_data *plat)
|
||||
{
|
||||
/* Set common default data first */
|
||||
common_default_data(plat);
|
||||
|
||||
plat->bus_id = 1;
|
||||
plat->phy_addr = 0;
|
||||
plat->phy_interface = PHY_INTERFACE_MODE_GMII;
|
||||
|
||||
plat->dma_cfg->pbl = 32;
|
||||
plat->dma_cfg->pblx8 = true;
|
||||
/* TODO: AXI */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct stmmac_pci_info stmmac_pci_info = {
|
||||
.setup = stmmac_default_data,
|
||||
};
|
||||
|
||||
static int snps_gmac5_default_data(struct pci_dev *pdev,
|
||||
struct plat_stmmacenet_data *plat)
|
||||
{
|
||||
int i;
|
||||
|
||||
plat->clk_csr = 5;
|
||||
plat->has_gmac4 = 1;
|
||||
plat->force_sf_dma_mode = 1;
|
||||
plat->flags |= STMMAC_FLAG_TSO_EN;
|
||||
plat->pmt = 1;
|
||||
|
||||
/* Set default value for multicast hash bins */
|
||||
plat->multicast_filter_bins = HASH_TABLE_SIZE;
|
||||
|
||||
/* Set default value for unicast filter entries */
|
||||
plat->unicast_filter_entries = 1;
|
||||
|
||||
/* Set the maxmtu to a default of JUMBO_LEN */
|
||||
plat->maxmtu = JUMBO_LEN;
|
||||
|
||||
/* Set default number of RX and TX queues to use */
|
||||
plat->tx_queues_to_use = 4;
|
||||
plat->rx_queues_to_use = 4;
|
||||
|
||||
plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR;
|
||||
for (i = 0; i < plat->tx_queues_to_use; i++) {
|
||||
plat->tx_queues_cfg[i].use_prio = false;
|
||||
plat->tx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
|
||||
plat->tx_queues_cfg[i].weight = 25;
|
||||
if (i > 0)
|
||||
plat->tx_queues_cfg[i].tbs_en = 1;
|
||||
}
|
||||
|
||||
plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
|
||||
for (i = 0; i < plat->rx_queues_to_use; i++) {
|
||||
plat->rx_queues_cfg[i].use_prio = false;
|
||||
plat->rx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
|
||||
plat->rx_queues_cfg[i].pkt_route = 0x0;
|
||||
plat->rx_queues_cfg[i].chan = i;
|
||||
}
|
||||
|
||||
plat->bus_id = 1;
|
||||
plat->phy_addr = -1;
|
||||
plat->phy_interface = PHY_INTERFACE_MODE_GMII;
|
||||
|
||||
plat->dma_cfg->pbl = 32;
|
||||
plat->dma_cfg->pblx8 = true;
|
||||
|
||||
/* Axi Configuration */
|
||||
plat->axi = devm_kzalloc(&pdev->dev, sizeof(*plat->axi), GFP_KERNEL);
|
||||
if (!plat->axi)
|
||||
return -ENOMEM;
|
||||
|
||||
plat->axi->axi_wr_osr_lmt = 31;
|
||||
plat->axi->axi_rd_osr_lmt = 31;
|
||||
|
||||
plat->axi->axi_fb = false;
|
||||
plat->axi->axi_blen[0] = 4;
|
||||
plat->axi->axi_blen[1] = 8;
|
||||
plat->axi->axi_blen[2] = 16;
|
||||
plat->axi->axi_blen[3] = 32;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct stmmac_pci_info snps_gmac5_pci_info = {
|
||||
.setup = snps_gmac5_default_data,
|
||||
};
|
||||
|
||||
/**
|
||||
* stmmac_pci_probe
|
||||
*
|
||||
* @pdev: pci device pointer
|
||||
* @id: pointer to table of device id/id's.
|
||||
*
|
||||
* Description: This probing function gets called for all PCI devices which
|
||||
* match the ID table and are not "owned" by other driver yet. This function
|
||||
* gets passed a "struct pci_dev *" for each device whose entry in the ID table
|
||||
* matches the device. The probe functions returns zero when the driver choose
|
||||
* to take "ownership" of the device or an error code(-ve no) otherwise.
|
||||
*/
|
||||
static int stmmac_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data;
|
||||
struct plat_stmmacenet_data *plat;
|
||||
struct stmmac_resources res;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
|
||||
if (!plat)
|
||||
return -ENOMEM;
|
||||
|
||||
plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*plat->mdio_bus_data),
|
||||
GFP_KERNEL);
|
||||
if (!plat->mdio_bus_data)
|
||||
return -ENOMEM;
|
||||
|
||||
plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg),
|
||||
GFP_KERNEL);
|
||||
if (!plat->dma_cfg)
|
||||
return -ENOMEM;
|
||||
|
||||
plat->safety_feat_cfg = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*plat->safety_feat_cfg),
|
||||
GFP_KERNEL);
|
||||
if (!plat->safety_feat_cfg)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Enable pci device */
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get the base address of device */
|
||||
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
|
||||
if (pci_resource_len(pdev, i) == 0)
|
||||
continue;
|
||||
ret = pcim_iomap_regions(pdev, BIT(i), pci_name(pdev));
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
ret = info->setup(pdev, plat);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memset(&res, 0, sizeof(res));
|
||||
res.addr = pcim_iomap_table(pdev)[i];
|
||||
res.wol_irq = pdev->irq;
|
||||
res.irq = pdev->irq;
|
||||
|
||||
plat->safety_feat_cfg->tsoee = 1;
|
||||
plat->safety_feat_cfg->mrxpee = 1;
|
||||
plat->safety_feat_cfg->mestee = 1;
|
||||
plat->safety_feat_cfg->mrxee = 1;
|
||||
plat->safety_feat_cfg->mtxee = 1;
|
||||
plat->safety_feat_cfg->epsi = 1;
|
||||
plat->safety_feat_cfg->edpp = 1;
|
||||
plat->safety_feat_cfg->prtyen = 1;
|
||||
plat->safety_feat_cfg->tmouten = 1;
|
||||
|
||||
return stmmac_dvr_probe(&pdev->dev, plat, &res);
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_pci_remove
|
||||
*
|
||||
* @pdev: platform device pointer
|
||||
* Description: this function calls the main to free the net resources
|
||||
* and releases the PCI resources.
|
||||
*/
|
||||
static void stmmac_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
stmmac_dvr_remove(&pdev->dev);
|
||||
|
||||
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
|
||||
if (pci_resource_len(pdev, i) == 0)
|
||||
continue;
|
||||
pcim_iounmap_regions(pdev, BIT(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int __maybe_unused stmmac_pci_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
int ret;
|
||||
|
||||
ret = stmmac_suspend(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pci_save_state(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_disable_device(pdev);
|
||||
pci_wake_from_d3(pdev, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused stmmac_pci_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
int ret;
|
||||
|
||||
pci_restore_state(pdev);
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
return stmmac_resume(dev);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume);
|
||||
|
||||
/* synthetic ID, no official vendor */
|
||||
#define PCI_VENDOR_ID_STMMAC 0x0700
|
||||
|
||||
#define PCI_DEVICE_ID_STMMAC_STMMAC 0x1108
|
||||
#define PCI_DEVICE_ID_SYNOPSYS_GMAC5_ID 0x7102
|
||||
|
||||
static const struct pci_device_id stmmac_id_table[] = {
|
||||
{ PCI_DEVICE_DATA(STMMAC, STMMAC, &stmmac_pci_info) },
|
||||
{ PCI_DEVICE_DATA(STMICRO, MAC, &stmmac_pci_info) },
|
||||
{ PCI_DEVICE_DATA(SYNOPSYS, GMAC5_ID, &snps_gmac5_pci_info) },
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, stmmac_id_table);
|
||||
|
||||
static struct pci_driver stmmac_pci_driver = {
|
||||
.name = STMMAC_RESOURCE_NAME,
|
||||
.id_table = stmmac_id_table,
|
||||
.probe = stmmac_pci_probe,
|
||||
.remove = stmmac_pci_remove,
|
||||
.driver = {
|
||||
.pm = &stmmac_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
module_pci_driver(stmmac_pci_driver);
|
||||
|
||||
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PCI driver");
|
||||
MODULE_AUTHOR("Rayagond Kokatanur <rayagond.kokatanur@vayavyalabs.com>");
|
||||
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* stmmac_pcs.h: Physical Coding Sublayer Header File
|
||||
*
|
||||
* Copyright (C) 2016 STMicroelectronics (R&D) Limited
|
||||
* Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*/
|
||||
|
||||
#ifndef __STMMAC_PCS_H__
|
||||
#define __STMMAC_PCS_H__
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include "common-6.12-ethercat.h"
|
||||
|
||||
/* PCS registers (AN/TBI/SGMII/RGMII) offsets */
|
||||
#define GMAC_AN_CTRL(x) (x) /* AN control */
|
||||
#define GMAC_AN_STATUS(x) (x + 0x4) /* AN status */
|
||||
#define GMAC_ANE_ADV(x) (x + 0x8) /* ANE Advertisement */
|
||||
#define GMAC_ANE_LPA(x) (x + 0xc) /* ANE link partener ability */
|
||||
#define GMAC_ANE_EXP(x) (x + 0x10) /* ANE expansion */
|
||||
#define GMAC_TBI(x) (x + 0x14) /* TBI extend status */
|
||||
|
||||
/* AN Configuration defines */
|
||||
#define GMAC_AN_CTRL_RAN BIT(9) /* Restart Auto-Negotiation */
|
||||
#define GMAC_AN_CTRL_ANE BIT(12) /* Auto-Negotiation Enable */
|
||||
#define GMAC_AN_CTRL_ELE BIT(14) /* External Loopback Enable */
|
||||
#define GMAC_AN_CTRL_ECD BIT(16) /* Enable Comma Detect */
|
||||
#define GMAC_AN_CTRL_LR BIT(17) /* Lock to Reference */
|
||||
#define GMAC_AN_CTRL_SGMRAL BIT(18) /* SGMII RAL Control */
|
||||
|
||||
/* AN Status defines */
|
||||
#define GMAC_AN_STATUS_LS BIT(2) /* Link Status 0:down 1:up */
|
||||
#define GMAC_AN_STATUS_ANA BIT(3) /* Auto-Negotiation Ability */
|
||||
#define GMAC_AN_STATUS_ANC BIT(5) /* Auto-Negotiation Complete */
|
||||
#define GMAC_AN_STATUS_ES BIT(8) /* Extended Status */
|
||||
|
||||
/* ADV and LPA defines */
|
||||
#define GMAC_ANE_FD BIT(5)
|
||||
#define GMAC_ANE_HD BIT(6)
|
||||
#define GMAC_ANE_PSE GENMASK(8, 7)
|
||||
#define GMAC_ANE_PSE_SHIFT 7
|
||||
#define GMAC_ANE_RFE GENMASK(13, 12)
|
||||
#define GMAC_ANE_RFE_SHIFT 12
|
||||
#define GMAC_ANE_ACK BIT(14)
|
||||
|
||||
/**
|
||||
* dwmac_pcs_isr - TBI, RTBI, or SGMII PHY ISR
|
||||
* @ioaddr: IO registers pointer
|
||||
* @reg: Base address of the AN Control Register.
|
||||
* @intr_status: GMAC core interrupt status
|
||||
* @x: pointer to log these events as stats
|
||||
* Description: it is the ISR for PCS events: Auto-Negotiation Completed and
|
||||
* Link status.
|
||||
*/
|
||||
static inline void dwmac_pcs_isr(void __iomem *ioaddr, u32 reg,
|
||||
unsigned int intr_status,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
u32 val = readl(ioaddr + GMAC_AN_STATUS(reg));
|
||||
|
||||
if (intr_status & PCS_ANE_IRQ) {
|
||||
x->irq_pcs_ane_n++;
|
||||
if (val & GMAC_AN_STATUS_ANC)
|
||||
pr_info("stmmac_pcs: ANE process completed\n");
|
||||
}
|
||||
|
||||
if (intr_status & PCS_LINK_IRQ) {
|
||||
x->irq_pcs_link_n++;
|
||||
if (val & GMAC_AN_STATUS_LS)
|
||||
pr_info("stmmac_pcs: Link Up\n");
|
||||
else
|
||||
pr_info("stmmac_pcs: Link Down\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dwmac_ctrl_ane - To program the AN Control Register.
|
||||
* @ioaddr: IO registers pointer
|
||||
* @reg: Base address of the AN Control Register.
|
||||
* @ane: to enable the auto-negotiation
|
||||
* @srgmi_ral: to manage MAC-2-MAC SGMII connections.
|
||||
* @loopback: to cause the PHY to loopback tx data into rx path.
|
||||
* Description: this is the main function to configure the AN control register
|
||||
* and init the ANE, select loopback (usually for debugging purpose) and
|
||||
* configure SGMII RAL.
|
||||
*/
|
||||
static inline void dwmac_ctrl_ane(void __iomem *ioaddr, u32 reg, bool ane,
|
||||
bool srgmi_ral, bool loopback)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_AN_CTRL(reg));
|
||||
|
||||
/* Enable and restart the Auto-Negotiation */
|
||||
if (ane)
|
||||
value |= GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_RAN;
|
||||
else
|
||||
value &= ~GMAC_AN_CTRL_ANE;
|
||||
|
||||
/* In case of MAC-2-MAC connection, block is configured to operate
|
||||
* according to MAC conf register.
|
||||
*/
|
||||
if (srgmi_ral)
|
||||
value |= GMAC_AN_CTRL_SGMRAL;
|
||||
|
||||
if (loopback)
|
||||
value |= GMAC_AN_CTRL_ELE;
|
||||
|
||||
writel(value, ioaddr + GMAC_AN_CTRL(reg));
|
||||
}
|
||||
|
||||
/**
|
||||
* dwmac_get_adv_lp - Get ADV and LP cap
|
||||
* @ioaddr: IO registers pointer
|
||||
* @reg: Base address of the AN Control Register.
|
||||
* @adv_lp: structure to store the adv,lp status
|
||||
* Description: this is to expose the ANE advertisement and Link partner ability
|
||||
* status to ethtool support.
|
||||
*/
|
||||
static inline void dwmac_get_adv_lp(void __iomem *ioaddr, u32 reg,
|
||||
struct rgmii_adv *adv_lp)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_ANE_ADV(reg));
|
||||
|
||||
if (value & GMAC_ANE_FD)
|
||||
adv_lp->duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_ANE_HD)
|
||||
adv_lp->duplex |= DUPLEX_HALF;
|
||||
|
||||
adv_lp->pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
|
||||
|
||||
value = readl(ioaddr + GMAC_ANE_LPA(reg));
|
||||
|
||||
if (value & GMAC_ANE_FD)
|
||||
adv_lp->lp_duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_ANE_HD)
|
||||
adv_lp->lp_duplex = DUPLEX_HALF;
|
||||
|
||||
adv_lp->lp_pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
|
||||
}
|
||||
#endif /* __STMMAC_PCS_H__ */
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* stmmac_pcs.h: Physical Coding Sublayer Header File
|
||||
*
|
||||
* Copyright (C) 2016 STMicroelectronics (R&D) Limited
|
||||
* Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*/
|
||||
|
||||
#ifndef __STMMAC_PCS_H__
|
||||
#define __STMMAC_PCS_H__
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include "common.h"
|
||||
|
||||
/* PCS registers (AN/TBI/SGMII/RGMII) offsets */
|
||||
#define GMAC_AN_CTRL(x) (x) /* AN control */
|
||||
#define GMAC_AN_STATUS(x) (x + 0x4) /* AN status */
|
||||
#define GMAC_ANE_ADV(x) (x + 0x8) /* ANE Advertisement */
|
||||
#define GMAC_ANE_LPA(x) (x + 0xc) /* ANE link partener ability */
|
||||
#define GMAC_ANE_EXP(x) (x + 0x10) /* ANE expansion */
|
||||
#define GMAC_TBI(x) (x + 0x14) /* TBI extend status */
|
||||
|
||||
/* AN Configuration defines */
|
||||
#define GMAC_AN_CTRL_RAN BIT(9) /* Restart Auto-Negotiation */
|
||||
#define GMAC_AN_CTRL_ANE BIT(12) /* Auto-Negotiation Enable */
|
||||
#define GMAC_AN_CTRL_ELE BIT(14) /* External Loopback Enable */
|
||||
#define GMAC_AN_CTRL_ECD BIT(16) /* Enable Comma Detect */
|
||||
#define GMAC_AN_CTRL_LR BIT(17) /* Lock to Reference */
|
||||
#define GMAC_AN_CTRL_SGMRAL BIT(18) /* SGMII RAL Control */
|
||||
|
||||
/* AN Status defines */
|
||||
#define GMAC_AN_STATUS_LS BIT(2) /* Link Status 0:down 1:up */
|
||||
#define GMAC_AN_STATUS_ANA BIT(3) /* Auto-Negotiation Ability */
|
||||
#define GMAC_AN_STATUS_ANC BIT(5) /* Auto-Negotiation Complete */
|
||||
#define GMAC_AN_STATUS_ES BIT(8) /* Extended Status */
|
||||
|
||||
/* ADV and LPA defines */
|
||||
#define GMAC_ANE_FD BIT(5)
|
||||
#define GMAC_ANE_HD BIT(6)
|
||||
#define GMAC_ANE_PSE GENMASK(8, 7)
|
||||
#define GMAC_ANE_PSE_SHIFT 7
|
||||
#define GMAC_ANE_RFE GENMASK(13, 12)
|
||||
#define GMAC_ANE_RFE_SHIFT 12
|
||||
#define GMAC_ANE_ACK BIT(14)
|
||||
|
||||
/**
|
||||
* dwmac_pcs_isr - TBI, RTBI, or SGMII PHY ISR
|
||||
* @ioaddr: IO registers pointer
|
||||
* @reg: Base address of the AN Control Register.
|
||||
* @intr_status: GMAC core interrupt status
|
||||
* @x: pointer to log these events as stats
|
||||
* Description: it is the ISR for PCS events: Auto-Negotiation Completed and
|
||||
* Link status.
|
||||
*/
|
||||
static inline void dwmac_pcs_isr(void __iomem *ioaddr, u32 reg,
|
||||
unsigned int intr_status,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
u32 val = readl(ioaddr + GMAC_AN_STATUS(reg));
|
||||
|
||||
if (intr_status & PCS_ANE_IRQ) {
|
||||
x->irq_pcs_ane_n++;
|
||||
if (val & GMAC_AN_STATUS_ANC)
|
||||
pr_info("stmmac_pcs: ANE process completed\n");
|
||||
}
|
||||
|
||||
if (intr_status & PCS_LINK_IRQ) {
|
||||
x->irq_pcs_link_n++;
|
||||
if (val & GMAC_AN_STATUS_LS)
|
||||
pr_info("stmmac_pcs: Link Up\n");
|
||||
else
|
||||
pr_info("stmmac_pcs: Link Down\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dwmac_ctrl_ane - To program the AN Control Register.
|
||||
* @ioaddr: IO registers pointer
|
||||
* @reg: Base address of the AN Control Register.
|
||||
* @ane: to enable the auto-negotiation
|
||||
* @srgmi_ral: to manage MAC-2-MAC SGMII connections.
|
||||
* @loopback: to cause the PHY to loopback tx data into rx path.
|
||||
* Description: this is the main function to configure the AN control register
|
||||
* and init the ANE, select loopback (usually for debugging purpose) and
|
||||
* configure SGMII RAL.
|
||||
*/
|
||||
static inline void dwmac_ctrl_ane(void __iomem *ioaddr, u32 reg, bool ane,
|
||||
bool srgmi_ral, bool loopback)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_AN_CTRL(reg));
|
||||
|
||||
/* Enable and restart the Auto-Negotiation */
|
||||
if (ane)
|
||||
value |= GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_RAN;
|
||||
else
|
||||
value &= ~GMAC_AN_CTRL_ANE;
|
||||
|
||||
/* In case of MAC-2-MAC connection, block is configured to operate
|
||||
* according to MAC conf register.
|
||||
*/
|
||||
if (srgmi_ral)
|
||||
value |= GMAC_AN_CTRL_SGMRAL;
|
||||
|
||||
if (loopback)
|
||||
value |= GMAC_AN_CTRL_ELE;
|
||||
|
||||
writel(value, ioaddr + GMAC_AN_CTRL(reg));
|
||||
}
|
||||
|
||||
/**
|
||||
* dwmac_get_adv_lp - Get ADV and LP cap
|
||||
* @ioaddr: IO registers pointer
|
||||
* @reg: Base address of the AN Control Register.
|
||||
* @adv_lp: structure to store the adv,lp status
|
||||
* Description: this is to expose the ANE advertisement and Link partner ability
|
||||
* status to ethtool support.
|
||||
*/
|
||||
static inline void dwmac_get_adv_lp(void __iomem *ioaddr, u32 reg,
|
||||
struct rgmii_adv *adv_lp)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_ANE_ADV(reg));
|
||||
|
||||
if (value & GMAC_ANE_FD)
|
||||
adv_lp->duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_ANE_HD)
|
||||
adv_lp->duplex |= DUPLEX_HALF;
|
||||
|
||||
adv_lp->pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
|
||||
|
||||
value = readl(ioaddr + GMAC_ANE_LPA(reg));
|
||||
|
||||
if (value & GMAC_ANE_FD)
|
||||
adv_lp->lp_duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_ANE_HD)
|
||||
adv_lp->lp_duplex = DUPLEX_HALF;
|
||||
|
||||
adv_lp->lp_pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
|
||||
}
|
||||
#endif /* __STMMAC_PCS_H__ */
|
||||
|
|
@ -0,0 +1,341 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
PTP 1588 clock using the STMMAC.
|
||||
|
||||
Copyright (C) 2013 Vayavya Labs Pvt Ltd
|
||||
|
||||
|
||||
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
|
||||
*******************************************************************************/
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
#include "stmmac_ptp-6.12-ethercat.h"
|
||||
#include "dwmac4-6.12-ethercat.h"
|
||||
|
||||
/**
|
||||
* stmmac_adjust_freq
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @scaled_ppm: desired period change in scaled parts per million
|
||||
*
|
||||
* Description: this function will adjust the frequency of hardware clock.
|
||||
*
|
||||
* Scaled parts per million is ppm with a 16-bit binary fractional field.
|
||||
*/
|
||||
static int stmmac_adjust_freq(struct ptp_clock_info *ptp, long scaled_ppm)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
u32 addend;
|
||||
|
||||
addend = adjust_by_scaled_ppm(priv->default_addend, scaled_ppm);
|
||||
|
||||
write_lock_irqsave(&priv->ptp_lock, flags);
|
||||
stmmac_config_addend(priv, priv->ptpaddr, addend);
|
||||
write_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_adjust_time
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @delta: desired change in nanoseconds
|
||||
*
|
||||
* Description: this function will shift/adjust the hardware clock time.
|
||||
*/
|
||||
static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
u32 sec, nsec;
|
||||
u32 quotient, reminder;
|
||||
int neg_adj = 0;
|
||||
bool xmac, est_rst = false;
|
||||
int ret;
|
||||
|
||||
xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac;
|
||||
|
||||
if (delta < 0) {
|
||||
neg_adj = 1;
|
||||
delta = -delta;
|
||||
}
|
||||
|
||||
quotient = div_u64_rem(delta, 1000000000ULL, &reminder);
|
||||
sec = quotient;
|
||||
nsec = reminder;
|
||||
|
||||
/* If EST is enabled, disabled it before adjust ptp time. */
|
||||
if (priv->est && priv->est->enable) {
|
||||
est_rst = true;
|
||||
mutex_lock(&priv->est_lock);
|
||||
priv->est->enable = false;
|
||||
stmmac_est_configure(priv, priv, priv->est,
|
||||
priv->plat->clk_ptp_rate);
|
||||
mutex_unlock(&priv->est_lock);
|
||||
}
|
||||
|
||||
write_lock_irqsave(&priv->ptp_lock, flags);
|
||||
stmmac_adjust_systime(priv, priv->ptpaddr, sec, nsec, neg_adj, xmac);
|
||||
write_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
/* Calculate new basetime and re-configured EST after PTP time adjust. */
|
||||
if (est_rst) {
|
||||
struct timespec64 current_time, time;
|
||||
ktime_t current_time_ns, basetime;
|
||||
u64 cycle_time;
|
||||
|
||||
mutex_lock(&priv->est_lock);
|
||||
priv->ptp_clock_ops.gettime64(&priv->ptp_clock_ops, ¤t_time);
|
||||
current_time_ns = timespec64_to_ktime(current_time);
|
||||
time.tv_nsec = priv->est->btr_reserve[0];
|
||||
time.tv_sec = priv->est->btr_reserve[1];
|
||||
basetime = timespec64_to_ktime(time);
|
||||
cycle_time = (u64)priv->est->ctr[1] * NSEC_PER_SEC +
|
||||
priv->est->ctr[0];
|
||||
time = stmmac_calc_tas_basetime(basetime,
|
||||
current_time_ns,
|
||||
cycle_time);
|
||||
|
||||
priv->est->btr[0] = (u32)time.tv_nsec;
|
||||
priv->est->btr[1] = (u32)time.tv_sec;
|
||||
priv->est->enable = true;
|
||||
ret = stmmac_est_configure(priv, priv, priv->est,
|
||||
priv->plat->clk_ptp_rate);
|
||||
mutex_unlock(&priv->est_lock);
|
||||
if (ret)
|
||||
netdev_err(priv->dev, "failed to configure EST\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_get_time
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @ts: pointer to hold time/result
|
||||
*
|
||||
* Description: this function will read the current time from the
|
||||
* hardware clock and store it in @ts.
|
||||
*/
|
||||
static int stmmac_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
u64 ns = 0;
|
||||
|
||||
read_lock_irqsave(&priv->ptp_lock, flags);
|
||||
stmmac_get_systime(priv, priv->ptpaddr, &ns);
|
||||
read_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
*ts = ns_to_timespec64(ns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_set_time
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @ts: time value to set
|
||||
*
|
||||
* Description: this function will set the current time on the
|
||||
* hardware clock.
|
||||
*/
|
||||
static int stmmac_set_time(struct ptp_clock_info *ptp,
|
||||
const struct timespec64 *ts)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
|
||||
write_lock_irqsave(&priv->ptp_lock, flags);
|
||||
stmmac_init_systime(priv, priv->ptpaddr, ts->tv_sec, ts->tv_nsec);
|
||||
write_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_enable(struct ptp_clock_info *ptp,
|
||||
struct ptp_clock_request *rq, int on)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
void __iomem *ptpaddr = priv->ptpaddr;
|
||||
struct stmmac_pps_cfg *cfg;
|
||||
int ret = -EOPNOTSUPP;
|
||||
unsigned long flags;
|
||||
u32 acr_value;
|
||||
|
||||
switch (rq->type) {
|
||||
case PTP_CLK_REQ_PEROUT:
|
||||
/* Reject requests with unsupported flags */
|
||||
if (rq->perout.flags)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
cfg = &priv->pps[rq->perout.index];
|
||||
|
||||
cfg->start.tv_sec = rq->perout.start.sec;
|
||||
cfg->start.tv_nsec = rq->perout.start.nsec;
|
||||
cfg->period.tv_sec = rq->perout.period.sec;
|
||||
cfg->period.tv_nsec = rq->perout.period.nsec;
|
||||
|
||||
write_lock_irqsave(&priv->ptp_lock, flags);
|
||||
ret = stmmac_flex_pps_config(priv, priv->ioaddr,
|
||||
rq->perout.index, cfg, on,
|
||||
priv->sub_second_inc,
|
||||
priv->systime_flags);
|
||||
write_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
break;
|
||||
case PTP_CLK_REQ_EXTTS: {
|
||||
u8 channel;
|
||||
|
||||
mutex_lock(&priv->aux_ts_lock);
|
||||
acr_value = readl(ptpaddr + PTP_ACR);
|
||||
channel = ilog2(FIELD_GET(PTP_ACR_MASK, acr_value));
|
||||
acr_value &= ~PTP_ACR_MASK;
|
||||
|
||||
if (on) {
|
||||
if (FIELD_GET(PTP_ACR_MASK, acr_value)) {
|
||||
netdev_err(priv->dev,
|
||||
"Cannot enable auxiliary snapshot %d as auxiliary snapshot %d is already enabled",
|
||||
rq->extts.index, channel);
|
||||
mutex_unlock(&priv->aux_ts_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
priv->plat->flags |= STMMAC_FLAG_EXT_SNAPSHOT_EN;
|
||||
|
||||
/* Enable External snapshot trigger */
|
||||
acr_value |= PTP_ACR_ATSEN(rq->extts.index);
|
||||
acr_value |= PTP_ACR_ATSFC;
|
||||
} else {
|
||||
priv->plat->flags &= ~STMMAC_FLAG_EXT_SNAPSHOT_EN;
|
||||
}
|
||||
netdev_dbg(priv->dev, "Auxiliary Snapshot %d %s.\n",
|
||||
rq->extts.index, on ? "enabled" : "disabled");
|
||||
writel(acr_value, ptpaddr + PTP_ACR);
|
||||
mutex_unlock(&priv->aux_ts_lock);
|
||||
/* wait for auxts fifo clear to finish */
|
||||
ret = readl_poll_timeout(ptpaddr + PTP_ACR, acr_value,
|
||||
!(acr_value & PTP_ACR_ATSFC),
|
||||
10, 10000);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_get_syncdevicetime
|
||||
* @device: current device time
|
||||
* @system: system counter value read synchronously with device time
|
||||
* @ctx: context provided by timekeeping code
|
||||
* Description: Read device and system clock simultaneously and return the
|
||||
* corrected clock values in ns.
|
||||
**/
|
||||
static int stmmac_get_syncdevicetime(ktime_t *device,
|
||||
struct system_counterval_t *system,
|
||||
void *ctx)
|
||||
{
|
||||
struct stmmac_priv *priv = (struct stmmac_priv *)ctx;
|
||||
|
||||
if (priv->plat->crosststamp)
|
||||
return priv->plat->crosststamp(device, system, ctx);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int stmmac_getcrosststamp(struct ptp_clock_info *ptp,
|
||||
struct system_device_crosststamp *xtstamp)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
|
||||
return get_device_system_crosststamp(stmmac_get_syncdevicetime,
|
||||
priv, NULL, xtstamp);
|
||||
}
|
||||
|
||||
/* structure describing a PTP hardware clock */
|
||||
static struct ptp_clock_info stmmac_ptp_clock_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "stmmac ptp",
|
||||
.max_adj = 62500000,
|
||||
.n_alarm = 0,
|
||||
.n_ext_ts = 0, /* will be overwritten in stmmac_ptp_register */
|
||||
.n_per_out = 0, /* will be overwritten in stmmac_ptp_register */
|
||||
.n_pins = 0,
|
||||
.pps = 0,
|
||||
.adjfine = stmmac_adjust_freq,
|
||||
.adjtime = stmmac_adjust_time,
|
||||
.gettime64 = stmmac_get_time,
|
||||
.settime64 = stmmac_set_time,
|
||||
.enable = stmmac_enable,
|
||||
.getcrosststamp = stmmac_getcrosststamp,
|
||||
};
|
||||
|
||||
/**
|
||||
* stmmac_ptp_register
|
||||
* @priv: driver private structure
|
||||
* Description: this function will register the ptp clock driver
|
||||
* to kernel. It also does some house keeping work.
|
||||
*/
|
||||
void stmmac_ptp_register(struct stmmac_priv *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->dma_cap.pps_out_num; i++) {
|
||||
if (i >= STMMAC_PPS_MAX)
|
||||
break;
|
||||
priv->pps[i].available = true;
|
||||
}
|
||||
|
||||
if (priv->plat->ptp_max_adj)
|
||||
stmmac_ptp_clock_ops.max_adj = priv->plat->ptp_max_adj;
|
||||
|
||||
/* Calculate the clock domain crossing (CDC) error if necessary */
|
||||
priv->plat->cdc_error_adj = 0;
|
||||
if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate)
|
||||
priv->plat->cdc_error_adj = (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate;
|
||||
|
||||
stmmac_ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num;
|
||||
stmmac_ptp_clock_ops.n_ext_ts = priv->dma_cap.aux_snapshot_n;
|
||||
|
||||
rwlock_init(&priv->ptp_lock);
|
||||
mutex_init(&priv->aux_ts_lock);
|
||||
priv->ptp_clock_ops = stmmac_ptp_clock_ops;
|
||||
|
||||
priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
|
||||
priv->device);
|
||||
if (IS_ERR(priv->ptp_clock)) {
|
||||
netdev_err(priv->dev, "ptp_clock_register failed\n");
|
||||
priv->ptp_clock = NULL;
|
||||
} else if (priv->ptp_clock)
|
||||
netdev_info(priv->dev, "registered PTP clock\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_ptp_unregister
|
||||
* @priv: driver private structure
|
||||
* Description: this function will remove/unregister the ptp clock driver
|
||||
* from the kernel.
|
||||
*/
|
||||
void stmmac_ptp_unregister(struct stmmac_priv *priv)
|
||||
{
|
||||
if (priv->ptp_clock) {
|
||||
ptp_clock_unregister(priv->ptp_clock);
|
||||
priv->ptp_clock = NULL;
|
||||
pr_debug("Removed PTP HW clock successfully on %s\n",
|
||||
priv->dev->name);
|
||||
}
|
||||
|
||||
mutex_destroy(&priv->aux_ts_lock);
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/******************************************************************************
|
||||
PTP Header file
|
||||
|
||||
Copyright (C) 2013 Vayavya Labs Pvt Ltd
|
||||
|
||||
|
||||
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __STMMAC_PTP_H__
|
||||
#define __STMMAC_PTP_H__
|
||||
|
||||
#define PTP_XGMAC_OFFSET 0xd00
|
||||
#define PTP_GMAC4_OFFSET 0xb00
|
||||
#define PTP_GMAC3_X_OFFSET 0x700
|
||||
|
||||
/* IEEE 1588 PTP register offsets */
|
||||
#define PTP_TCR 0x00 /* Timestamp Control Reg */
|
||||
#define PTP_SSIR 0x04 /* Sub-Second Increment Reg */
|
||||
#define PTP_STSR 0x08 /* System Time – Seconds Regr */
|
||||
#define PTP_STNSR 0x0c /* System Time – Nanoseconds Reg */
|
||||
#define PTP_STSUR 0x10 /* System Time – Seconds Update Reg */
|
||||
#define PTP_STNSUR 0x14 /* System Time – Nanoseconds Update Reg */
|
||||
#define PTP_TAR 0x18 /* Timestamp Addend Reg */
|
||||
#define PTP_ACR 0x40 /* Auxiliary Control Reg */
|
||||
#define PTP_ATNR 0x48 /* Auxiliary Timestamp - Nanoseconds Reg */
|
||||
#define PTP_ATSR 0x4c /* Auxiliary Timestamp - Seconds Reg */
|
||||
#define PTP_TS_INGR_CORR_NS 0x58 /* Ingress timestamp correction nanoseconds */
|
||||
#define PTP_TS_EGR_CORR_NS 0x5C /* Egress timestamp correction nanoseconds*/
|
||||
#define PTP_TS_INGR_CORR_SNS 0x60 /* Ingress timestamp correction subnanoseconds */
|
||||
#define PTP_TS_EGR_CORR_SNS 0x64 /* Egress timestamp correction subnanoseconds */
|
||||
#define PTP_TS_INGR_LAT 0x68 /* MAC internal Ingress Latency */
|
||||
#define PTP_TS_EGR_LAT 0x6c /* MAC internal Egress Latency */
|
||||
|
||||
#define PTP_STNSUR_ADDSUB_SHIFT 31
|
||||
#define PTP_DIGITAL_ROLLOVER_MODE 0x3B9ACA00 /* 10e9-1 ns */
|
||||
#define PTP_BINARY_ROLLOVER_MODE 0x80000000 /* ~0.466 ns */
|
||||
|
||||
/* PTP Timestamp control register defines */
|
||||
#define PTP_TCR_TSENA BIT(0) /* Timestamp Enable */
|
||||
#define PTP_TCR_TSCFUPDT BIT(1) /* Timestamp Fine/Coarse Update */
|
||||
#define PTP_TCR_TSINIT BIT(2) /* Timestamp Initialize */
|
||||
#define PTP_TCR_TSUPDT BIT(3) /* Timestamp Update */
|
||||
#define PTP_TCR_TSTRIG BIT(4) /* Timestamp Interrupt Trigger Enable */
|
||||
#define PTP_TCR_TSADDREG BIT(5) /* Addend Reg Update */
|
||||
#define PTP_TCR_TSENALL BIT(8) /* Enable Timestamp for All Frames */
|
||||
#define PTP_TCR_TSCTRLSSR BIT(9) /* Digital or Binary Rollover Control */
|
||||
/* Enable PTP packet Processing for Version 2 Format */
|
||||
#define PTP_TCR_TSVER2ENA BIT(10)
|
||||
/* Enable Processing of PTP over Ethernet Frames */
|
||||
#define PTP_TCR_TSIPENA BIT(11)
|
||||
/* Enable Processing of PTP Frames Sent over IPv6-UDP */
|
||||
#define PTP_TCR_TSIPV6ENA BIT(12)
|
||||
/* Enable Processing of PTP Frames Sent over IPv4-UDP */
|
||||
#define PTP_TCR_TSIPV4ENA BIT(13)
|
||||
/* Enable Timestamp Snapshot for Event Messages */
|
||||
#define PTP_TCR_TSEVNTENA BIT(14)
|
||||
/* Enable Snapshot for Messages Relevant to Master */
|
||||
#define PTP_TCR_TSMSTRENA BIT(15)
|
||||
/* Select PTP packets for Taking Snapshots
|
||||
* On gmac4 specifically:
|
||||
* Enable SYNC, Pdelay_Req, Pdelay_Resp when TSEVNTENA is enabled.
|
||||
* or
|
||||
* Enable SYNC, Follow_Up, Delay_Req, Delay_Resp, Pdelay_Req, Pdelay_Resp,
|
||||
* Pdelay_Resp_Follow_Up if TSEVNTENA is disabled
|
||||
*/
|
||||
#define PTP_TCR_SNAPTYPSEL_1 BIT(16)
|
||||
/* Enable MAC address for PTP Frame Filtering */
|
||||
#define PTP_TCR_TSENMACADDR BIT(18)
|
||||
|
||||
/* SSIR defines */
|
||||
#define PTP_SSIR_SSINC_MAX 0xff
|
||||
#define GMAC4_PTP_SSIR_SSINC_SHIFT 16
|
||||
|
||||
/* Auxiliary Control defines */
|
||||
#define PTP_ACR_ATSFC BIT(0) /* Auxiliary Snapshot FIFO Clear */
|
||||
#define PTP_ACR_ATSEN0 BIT(4) /* Auxiliary Snapshot 0 Enable */
|
||||
#define PTP_ACR_ATSEN1 BIT(5) /* Auxiliary Snapshot 1 Enable */
|
||||
#define PTP_ACR_ATSEN2 BIT(6) /* Auxiliary Snapshot 2 Enable */
|
||||
#define PTP_ACR_ATSEN3 BIT(7) /* Auxiliary Snapshot 3 Enable */
|
||||
#define PTP_ACR_ATSEN(index) (PTP_ACR_ATSEN0 << (index))
|
||||
#define PTP_ACR_MASK GENMASK(7, 4) /* Aux Snapshot Mask */
|
||||
#define PMC_ART_VALUE0 0x01 /* PMC_ART[15:0] timer value */
|
||||
#define PMC_ART_VALUE1 0x02 /* PMC_ART[31:16] timer value */
|
||||
#define PMC_ART_VALUE2 0x03 /* PMC_ART[47:32] timer value */
|
||||
#define PMC_ART_VALUE3 0x04 /* PMC_ART[63:48] timer value */
|
||||
#define GMAC4_ART_TIME_SHIFT 16 /* ART TIME 16-bits shift */
|
||||
|
||||
enum aux_snapshot {
|
||||
AUX_SNAPSHOT0 = 0x10,
|
||||
AUX_SNAPSHOT1 = 0x20,
|
||||
AUX_SNAPSHOT2 = 0x40,
|
||||
AUX_SNAPSHOT3 = 0x80,
|
||||
};
|
||||
|
||||
#endif /* __STMMAC_PTP_H__ */
|
||||
|
|
@ -0,0 +1,341 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*******************************************************************************
|
||||
PTP 1588 clock using the STMMAC.
|
||||
|
||||
Copyright (C) 2013 Vayavya Labs Pvt Ltd
|
||||
|
||||
|
||||
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
|
||||
*******************************************************************************/
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_ptp.h"
|
||||
#include "dwmac4.h"
|
||||
|
||||
/**
|
||||
* stmmac_adjust_freq
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @scaled_ppm: desired period change in scaled parts per million
|
||||
*
|
||||
* Description: this function will adjust the frequency of hardware clock.
|
||||
*
|
||||
* Scaled parts per million is ppm with a 16-bit binary fractional field.
|
||||
*/
|
||||
static int stmmac_adjust_freq(struct ptp_clock_info *ptp, long scaled_ppm)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
u32 addend;
|
||||
|
||||
addend = adjust_by_scaled_ppm(priv->default_addend, scaled_ppm);
|
||||
|
||||
write_lock_irqsave(&priv->ptp_lock, flags);
|
||||
stmmac_config_addend(priv, priv->ptpaddr, addend);
|
||||
write_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_adjust_time
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @delta: desired change in nanoseconds
|
||||
*
|
||||
* Description: this function will shift/adjust the hardware clock time.
|
||||
*/
|
||||
static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
u32 sec, nsec;
|
||||
u32 quotient, reminder;
|
||||
int neg_adj = 0;
|
||||
bool xmac, est_rst = false;
|
||||
int ret;
|
||||
|
||||
xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac;
|
||||
|
||||
if (delta < 0) {
|
||||
neg_adj = 1;
|
||||
delta = -delta;
|
||||
}
|
||||
|
||||
quotient = div_u64_rem(delta, 1000000000ULL, &reminder);
|
||||
sec = quotient;
|
||||
nsec = reminder;
|
||||
|
||||
/* If EST is enabled, disabled it before adjust ptp time. */
|
||||
if (priv->est && priv->est->enable) {
|
||||
est_rst = true;
|
||||
mutex_lock(&priv->est_lock);
|
||||
priv->est->enable = false;
|
||||
stmmac_est_configure(priv, priv, priv->est,
|
||||
priv->plat->clk_ptp_rate);
|
||||
mutex_unlock(&priv->est_lock);
|
||||
}
|
||||
|
||||
write_lock_irqsave(&priv->ptp_lock, flags);
|
||||
stmmac_adjust_systime(priv, priv->ptpaddr, sec, nsec, neg_adj, xmac);
|
||||
write_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
/* Calculate new basetime and re-configured EST after PTP time adjust. */
|
||||
if (est_rst) {
|
||||
struct timespec64 current_time, time;
|
||||
ktime_t current_time_ns, basetime;
|
||||
u64 cycle_time;
|
||||
|
||||
mutex_lock(&priv->est_lock);
|
||||
priv->ptp_clock_ops.gettime64(&priv->ptp_clock_ops, ¤t_time);
|
||||
current_time_ns = timespec64_to_ktime(current_time);
|
||||
time.tv_nsec = priv->est->btr_reserve[0];
|
||||
time.tv_sec = priv->est->btr_reserve[1];
|
||||
basetime = timespec64_to_ktime(time);
|
||||
cycle_time = (u64)priv->est->ctr[1] * NSEC_PER_SEC +
|
||||
priv->est->ctr[0];
|
||||
time = stmmac_calc_tas_basetime(basetime,
|
||||
current_time_ns,
|
||||
cycle_time);
|
||||
|
||||
priv->est->btr[0] = (u32)time.tv_nsec;
|
||||
priv->est->btr[1] = (u32)time.tv_sec;
|
||||
priv->est->enable = true;
|
||||
ret = stmmac_est_configure(priv, priv, priv->est,
|
||||
priv->plat->clk_ptp_rate);
|
||||
mutex_unlock(&priv->est_lock);
|
||||
if (ret)
|
||||
netdev_err(priv->dev, "failed to configure EST\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_get_time
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @ts: pointer to hold time/result
|
||||
*
|
||||
* Description: this function will read the current time from the
|
||||
* hardware clock and store it in @ts.
|
||||
*/
|
||||
static int stmmac_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
u64 ns = 0;
|
||||
|
||||
read_lock_irqsave(&priv->ptp_lock, flags);
|
||||
stmmac_get_systime(priv, priv->ptpaddr, &ns);
|
||||
read_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
*ts = ns_to_timespec64(ns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_set_time
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @ts: time value to set
|
||||
*
|
||||
* Description: this function will set the current time on the
|
||||
* hardware clock.
|
||||
*/
|
||||
static int stmmac_set_time(struct ptp_clock_info *ptp,
|
||||
const struct timespec64 *ts)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
|
||||
write_lock_irqsave(&priv->ptp_lock, flags);
|
||||
stmmac_init_systime(priv, priv->ptpaddr, ts->tv_sec, ts->tv_nsec);
|
||||
write_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_enable(struct ptp_clock_info *ptp,
|
||||
struct ptp_clock_request *rq, int on)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
void __iomem *ptpaddr = priv->ptpaddr;
|
||||
struct stmmac_pps_cfg *cfg;
|
||||
int ret = -EOPNOTSUPP;
|
||||
unsigned long flags;
|
||||
u32 acr_value;
|
||||
|
||||
switch (rq->type) {
|
||||
case PTP_CLK_REQ_PEROUT:
|
||||
/* Reject requests with unsupported flags */
|
||||
if (rq->perout.flags)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
cfg = &priv->pps[rq->perout.index];
|
||||
|
||||
cfg->start.tv_sec = rq->perout.start.sec;
|
||||
cfg->start.tv_nsec = rq->perout.start.nsec;
|
||||
cfg->period.tv_sec = rq->perout.period.sec;
|
||||
cfg->period.tv_nsec = rq->perout.period.nsec;
|
||||
|
||||
write_lock_irqsave(&priv->ptp_lock, flags);
|
||||
ret = stmmac_flex_pps_config(priv, priv->ioaddr,
|
||||
rq->perout.index, cfg, on,
|
||||
priv->sub_second_inc,
|
||||
priv->systime_flags);
|
||||
write_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
break;
|
||||
case PTP_CLK_REQ_EXTTS: {
|
||||
u8 channel;
|
||||
|
||||
mutex_lock(&priv->aux_ts_lock);
|
||||
acr_value = readl(ptpaddr + PTP_ACR);
|
||||
channel = ilog2(FIELD_GET(PTP_ACR_MASK, acr_value));
|
||||
acr_value &= ~PTP_ACR_MASK;
|
||||
|
||||
if (on) {
|
||||
if (FIELD_GET(PTP_ACR_MASK, acr_value)) {
|
||||
netdev_err(priv->dev,
|
||||
"Cannot enable auxiliary snapshot %d as auxiliary snapshot %d is already enabled",
|
||||
rq->extts.index, channel);
|
||||
mutex_unlock(&priv->aux_ts_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
priv->plat->flags |= STMMAC_FLAG_EXT_SNAPSHOT_EN;
|
||||
|
||||
/* Enable External snapshot trigger */
|
||||
acr_value |= PTP_ACR_ATSEN(rq->extts.index);
|
||||
acr_value |= PTP_ACR_ATSFC;
|
||||
} else {
|
||||
priv->plat->flags &= ~STMMAC_FLAG_EXT_SNAPSHOT_EN;
|
||||
}
|
||||
netdev_dbg(priv->dev, "Auxiliary Snapshot %d %s.\n",
|
||||
rq->extts.index, on ? "enabled" : "disabled");
|
||||
writel(acr_value, ptpaddr + PTP_ACR);
|
||||
mutex_unlock(&priv->aux_ts_lock);
|
||||
/* wait for auxts fifo clear to finish */
|
||||
ret = readl_poll_timeout(ptpaddr + PTP_ACR, acr_value,
|
||||
!(acr_value & PTP_ACR_ATSFC),
|
||||
10, 10000);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_get_syncdevicetime
|
||||
* @device: current device time
|
||||
* @system: system counter value read synchronously with device time
|
||||
* @ctx: context provided by timekeeping code
|
||||
* Description: Read device and system clock simultaneously and return the
|
||||
* corrected clock values in ns.
|
||||
**/
|
||||
static int stmmac_get_syncdevicetime(ktime_t *device,
|
||||
struct system_counterval_t *system,
|
||||
void *ctx)
|
||||
{
|
||||
struct stmmac_priv *priv = (struct stmmac_priv *)ctx;
|
||||
|
||||
if (priv->plat->crosststamp)
|
||||
return priv->plat->crosststamp(device, system, ctx);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int stmmac_getcrosststamp(struct ptp_clock_info *ptp,
|
||||
struct system_device_crosststamp *xtstamp)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
|
||||
return get_device_system_crosststamp(stmmac_get_syncdevicetime,
|
||||
priv, NULL, xtstamp);
|
||||
}
|
||||
|
||||
/* structure describing a PTP hardware clock */
|
||||
static struct ptp_clock_info stmmac_ptp_clock_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "stmmac ptp",
|
||||
.max_adj = 62500000,
|
||||
.n_alarm = 0,
|
||||
.n_ext_ts = 0, /* will be overwritten in stmmac_ptp_register */
|
||||
.n_per_out = 0, /* will be overwritten in stmmac_ptp_register */
|
||||
.n_pins = 0,
|
||||
.pps = 0,
|
||||
.adjfine = stmmac_adjust_freq,
|
||||
.adjtime = stmmac_adjust_time,
|
||||
.gettime64 = stmmac_get_time,
|
||||
.settime64 = stmmac_set_time,
|
||||
.enable = stmmac_enable,
|
||||
.getcrosststamp = stmmac_getcrosststamp,
|
||||
};
|
||||
|
||||
/**
|
||||
* stmmac_ptp_register
|
||||
* @priv: driver private structure
|
||||
* Description: this function will register the ptp clock driver
|
||||
* to kernel. It also does some house keeping work.
|
||||
*/
|
||||
void stmmac_ptp_register(struct stmmac_priv *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->dma_cap.pps_out_num; i++) {
|
||||
if (i >= STMMAC_PPS_MAX)
|
||||
break;
|
||||
priv->pps[i].available = true;
|
||||
}
|
||||
|
||||
if (priv->plat->ptp_max_adj)
|
||||
stmmac_ptp_clock_ops.max_adj = priv->plat->ptp_max_adj;
|
||||
|
||||
/* Calculate the clock domain crossing (CDC) error if necessary */
|
||||
priv->plat->cdc_error_adj = 0;
|
||||
if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate)
|
||||
priv->plat->cdc_error_adj = (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate;
|
||||
|
||||
stmmac_ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num;
|
||||
stmmac_ptp_clock_ops.n_ext_ts = priv->dma_cap.aux_snapshot_n;
|
||||
|
||||
rwlock_init(&priv->ptp_lock);
|
||||
mutex_init(&priv->aux_ts_lock);
|
||||
priv->ptp_clock_ops = stmmac_ptp_clock_ops;
|
||||
|
||||
priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
|
||||
priv->device);
|
||||
if (IS_ERR(priv->ptp_clock)) {
|
||||
netdev_err(priv->dev, "ptp_clock_register failed\n");
|
||||
priv->ptp_clock = NULL;
|
||||
} else if (priv->ptp_clock)
|
||||
netdev_info(priv->dev, "registered PTP clock\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_ptp_unregister
|
||||
* @priv: driver private structure
|
||||
* Description: this function will remove/unregister the ptp clock driver
|
||||
* from the kernel.
|
||||
*/
|
||||
void stmmac_ptp_unregister(struct stmmac_priv *priv)
|
||||
{
|
||||
if (priv->ptp_clock) {
|
||||
ptp_clock_unregister(priv->ptp_clock);
|
||||
priv->ptp_clock = NULL;
|
||||
pr_debug("Removed PTP HW clock successfully on %s\n",
|
||||
priv->dev->name);
|
||||
}
|
||||
|
||||
mutex_destroy(&priv->aux_ts_lock);
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/******************************************************************************
|
||||
PTP Header file
|
||||
|
||||
Copyright (C) 2013 Vayavya Labs Pvt Ltd
|
||||
|
||||
|
||||
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __STMMAC_PTP_H__
|
||||
#define __STMMAC_PTP_H__
|
||||
|
||||
#define PTP_XGMAC_OFFSET 0xd00
|
||||
#define PTP_GMAC4_OFFSET 0xb00
|
||||
#define PTP_GMAC3_X_OFFSET 0x700
|
||||
|
||||
/* IEEE 1588 PTP register offsets */
|
||||
#define PTP_TCR 0x00 /* Timestamp Control Reg */
|
||||
#define PTP_SSIR 0x04 /* Sub-Second Increment Reg */
|
||||
#define PTP_STSR 0x08 /* System Time – Seconds Regr */
|
||||
#define PTP_STNSR 0x0c /* System Time – Nanoseconds Reg */
|
||||
#define PTP_STSUR 0x10 /* System Time – Seconds Update Reg */
|
||||
#define PTP_STNSUR 0x14 /* System Time – Nanoseconds Update Reg */
|
||||
#define PTP_TAR 0x18 /* Timestamp Addend Reg */
|
||||
#define PTP_ACR 0x40 /* Auxiliary Control Reg */
|
||||
#define PTP_ATNR 0x48 /* Auxiliary Timestamp - Nanoseconds Reg */
|
||||
#define PTP_ATSR 0x4c /* Auxiliary Timestamp - Seconds Reg */
|
||||
#define PTP_TS_INGR_CORR_NS 0x58 /* Ingress timestamp correction nanoseconds */
|
||||
#define PTP_TS_EGR_CORR_NS 0x5C /* Egress timestamp correction nanoseconds*/
|
||||
#define PTP_TS_INGR_CORR_SNS 0x60 /* Ingress timestamp correction subnanoseconds */
|
||||
#define PTP_TS_EGR_CORR_SNS 0x64 /* Egress timestamp correction subnanoseconds */
|
||||
#define PTP_TS_INGR_LAT 0x68 /* MAC internal Ingress Latency */
|
||||
#define PTP_TS_EGR_LAT 0x6c /* MAC internal Egress Latency */
|
||||
|
||||
#define PTP_STNSUR_ADDSUB_SHIFT 31
|
||||
#define PTP_DIGITAL_ROLLOVER_MODE 0x3B9ACA00 /* 10e9-1 ns */
|
||||
#define PTP_BINARY_ROLLOVER_MODE 0x80000000 /* ~0.466 ns */
|
||||
|
||||
/* PTP Timestamp control register defines */
|
||||
#define PTP_TCR_TSENA BIT(0) /* Timestamp Enable */
|
||||
#define PTP_TCR_TSCFUPDT BIT(1) /* Timestamp Fine/Coarse Update */
|
||||
#define PTP_TCR_TSINIT BIT(2) /* Timestamp Initialize */
|
||||
#define PTP_TCR_TSUPDT BIT(3) /* Timestamp Update */
|
||||
#define PTP_TCR_TSTRIG BIT(4) /* Timestamp Interrupt Trigger Enable */
|
||||
#define PTP_TCR_TSADDREG BIT(5) /* Addend Reg Update */
|
||||
#define PTP_TCR_TSENALL BIT(8) /* Enable Timestamp for All Frames */
|
||||
#define PTP_TCR_TSCTRLSSR BIT(9) /* Digital or Binary Rollover Control */
|
||||
/* Enable PTP packet Processing for Version 2 Format */
|
||||
#define PTP_TCR_TSVER2ENA BIT(10)
|
||||
/* Enable Processing of PTP over Ethernet Frames */
|
||||
#define PTP_TCR_TSIPENA BIT(11)
|
||||
/* Enable Processing of PTP Frames Sent over IPv6-UDP */
|
||||
#define PTP_TCR_TSIPV6ENA BIT(12)
|
||||
/* Enable Processing of PTP Frames Sent over IPv4-UDP */
|
||||
#define PTP_TCR_TSIPV4ENA BIT(13)
|
||||
/* Enable Timestamp Snapshot for Event Messages */
|
||||
#define PTP_TCR_TSEVNTENA BIT(14)
|
||||
/* Enable Snapshot for Messages Relevant to Master */
|
||||
#define PTP_TCR_TSMSTRENA BIT(15)
|
||||
/* Select PTP packets for Taking Snapshots
|
||||
* On gmac4 specifically:
|
||||
* Enable SYNC, Pdelay_Req, Pdelay_Resp when TSEVNTENA is enabled.
|
||||
* or
|
||||
* Enable SYNC, Follow_Up, Delay_Req, Delay_Resp, Pdelay_Req, Pdelay_Resp,
|
||||
* Pdelay_Resp_Follow_Up if TSEVNTENA is disabled
|
||||
*/
|
||||
#define PTP_TCR_SNAPTYPSEL_1 BIT(16)
|
||||
/* Enable MAC address for PTP Frame Filtering */
|
||||
#define PTP_TCR_TSENMACADDR BIT(18)
|
||||
|
||||
/* SSIR defines */
|
||||
#define PTP_SSIR_SSINC_MAX 0xff
|
||||
#define GMAC4_PTP_SSIR_SSINC_SHIFT 16
|
||||
|
||||
/* Auxiliary Control defines */
|
||||
#define PTP_ACR_ATSFC BIT(0) /* Auxiliary Snapshot FIFO Clear */
|
||||
#define PTP_ACR_ATSEN0 BIT(4) /* Auxiliary Snapshot 0 Enable */
|
||||
#define PTP_ACR_ATSEN1 BIT(5) /* Auxiliary Snapshot 1 Enable */
|
||||
#define PTP_ACR_ATSEN2 BIT(6) /* Auxiliary Snapshot 2 Enable */
|
||||
#define PTP_ACR_ATSEN3 BIT(7) /* Auxiliary Snapshot 3 Enable */
|
||||
#define PTP_ACR_ATSEN(index) (PTP_ACR_ATSEN0 << (index))
|
||||
#define PTP_ACR_MASK GENMASK(7, 4) /* Aux Snapshot Mask */
|
||||
#define PMC_ART_VALUE0 0x01 /* PMC_ART[15:0] timer value */
|
||||
#define PMC_ART_VALUE1 0x02 /* PMC_ART[31:16] timer value */
|
||||
#define PMC_ART_VALUE2 0x03 /* PMC_ART[47:32] timer value */
|
||||
#define PMC_ART_VALUE3 0x04 /* PMC_ART[63:48] timer value */
|
||||
#define GMAC4_ART_TIME_SHIFT 16 /* ART TIME 16-bits shift */
|
||||
|
||||
enum aux_snapshot {
|
||||
AUX_SNAPSHOT0 = 0x10,
|
||||
AUX_SNAPSHOT1 = 0x20,
|
||||
AUX_SNAPSHOT2 = 0x40,
|
||||
AUX_SNAPSHOT3 = 0x80,
|
||||
};
|
||||
|
||||
#endif /* __STMMAC_PTP_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,141 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2021, Intel Corporation. */
|
||||
|
||||
#include <net/xdp_sock_drv.h>
|
||||
|
||||
#include "stmmac-6.12-ethercat.h"
|
||||
#include "stmmac_xdp-6.12-ethercat.h"
|
||||
|
||||
static int stmmac_xdp_enable_pool(struct stmmac_priv *priv,
|
||||
struct xsk_buff_pool *pool, u16 queue)
|
||||
{
|
||||
struct stmmac_channel *ch = &priv->channel[queue];
|
||||
bool need_update;
|
||||
u32 frame_size;
|
||||
int err;
|
||||
|
||||
if (queue >= priv->plat->rx_queues_to_use ||
|
||||
queue >= priv->plat->tx_queues_to_use)
|
||||
return -EINVAL;
|
||||
|
||||
frame_size = xsk_pool_get_rx_frame_size(pool);
|
||||
/* XDP ZC does not span multiple frame, make sure XSK pool buffer
|
||||
* size can at least store Q-in-Q frame.
|
||||
*/
|
||||
if (frame_size < ETH_FRAME_LEN + VLAN_HLEN * 2)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
err = xsk_pool_dma_map(pool, priv->device, STMMAC_RX_DMA_ATTR);
|
||||
if (err) {
|
||||
netdev_err(priv->dev, "Failed to map xsk pool\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
need_update = netif_running(priv->dev) && stmmac_xdp_is_enabled(priv);
|
||||
|
||||
if (need_update) {
|
||||
napi_disable(&ch->rx_napi);
|
||||
napi_disable(&ch->tx_napi);
|
||||
stmmac_disable_rx_queue(priv, queue);
|
||||
stmmac_disable_tx_queue(priv, queue);
|
||||
}
|
||||
|
||||
set_bit(queue, priv->af_xdp_zc_qps);
|
||||
|
||||
if (need_update) {
|
||||
stmmac_enable_rx_queue(priv, queue);
|
||||
stmmac_enable_tx_queue(priv, queue);
|
||||
napi_enable(&ch->rxtx_napi);
|
||||
|
||||
err = stmmac_xsk_wakeup(priv->dev, queue, XDP_WAKEUP_RX);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_xdp_disable_pool(struct stmmac_priv *priv, u16 queue)
|
||||
{
|
||||
struct stmmac_channel *ch = &priv->channel[queue];
|
||||
struct xsk_buff_pool *pool;
|
||||
bool need_update;
|
||||
|
||||
if (queue >= priv->plat->rx_queues_to_use ||
|
||||
queue >= priv->plat->tx_queues_to_use)
|
||||
return -EINVAL;
|
||||
|
||||
pool = xsk_get_pool_from_qid(priv->dev, queue);
|
||||
if (!pool)
|
||||
return -EINVAL;
|
||||
|
||||
need_update = netif_running(priv->dev) && stmmac_xdp_is_enabled(priv);
|
||||
|
||||
if (need_update) {
|
||||
napi_disable(&ch->rxtx_napi);
|
||||
stmmac_disable_rx_queue(priv, queue);
|
||||
stmmac_disable_tx_queue(priv, queue);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
xsk_pool_dma_unmap(pool, STMMAC_RX_DMA_ATTR);
|
||||
|
||||
clear_bit(queue, priv->af_xdp_zc_qps);
|
||||
|
||||
if (need_update) {
|
||||
stmmac_enable_rx_queue(priv, queue);
|
||||
stmmac_enable_tx_queue(priv, queue);
|
||||
napi_enable(&ch->rx_napi);
|
||||
napi_enable(&ch->tx_napi);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmmac_xdp_setup_pool(struct stmmac_priv *priv, struct xsk_buff_pool *pool,
|
||||
u16 queue)
|
||||
{
|
||||
return pool ? stmmac_xdp_enable_pool(priv, pool, queue) :
|
||||
stmmac_xdp_disable_pool(priv, queue);
|
||||
}
|
||||
|
||||
int stmmac_xdp_set_prog(struct stmmac_priv *priv, struct bpf_prog *prog,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net_device *dev = priv->dev;
|
||||
struct bpf_prog *old_prog;
|
||||
bool need_update;
|
||||
bool if_running;
|
||||
|
||||
if_running = netif_running(dev);
|
||||
|
||||
if (prog && dev->mtu > ETH_DATA_LEN) {
|
||||
/* For now, the driver doesn't support XDP functionality with
|
||||
* jumbo frames so we return error.
|
||||
*/
|
||||
NL_SET_ERR_MSG_MOD(extack, "Jumbo frames not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!prog)
|
||||
xdp_features_clear_redirect_target(dev);
|
||||
|
||||
need_update = !!priv->xdp_prog != !!prog;
|
||||
if (if_running && need_update)
|
||||
stmmac_xdp_release(dev);
|
||||
|
||||
old_prog = xchg(&priv->xdp_prog, prog);
|
||||
if (old_prog)
|
||||
bpf_prog_put(old_prog);
|
||||
|
||||
/* Disable RX SPH for XDP operation */
|
||||
priv->sph = priv->sph_cap && !stmmac_xdp_is_enabled(priv);
|
||||
|
||||
if (if_running && need_update)
|
||||
stmmac_xdp_open(dev);
|
||||
|
||||
if (prog)
|
||||
xdp_features_set_redirect_target(dev, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2021, Intel Corporation. */
|
||||
|
||||
#ifndef _STMMAC_XDP_H_
|
||||
#define _STMMAC_XDP_H_
|
||||
|
||||
#define STMMAC_MAX_RX_BUF_SIZE(num) (((num) * PAGE_SIZE) - XDP_PACKET_HEADROOM)
|
||||
#define STMMAC_RX_DMA_ATTR (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
|
||||
|
||||
int stmmac_xdp_setup_pool(struct stmmac_priv *priv, struct xsk_buff_pool *pool,
|
||||
u16 queue);
|
||||
int stmmac_xdp_set_prog(struct stmmac_priv *priv, struct bpf_prog *prog,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
#endif /* _STMMAC_XDP_H_ */
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2021, Intel Corporation. */
|
||||
|
||||
#include <net/xdp_sock_drv.h>
|
||||
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_xdp.h"
|
||||
|
||||
static int stmmac_xdp_enable_pool(struct stmmac_priv *priv,
|
||||
struct xsk_buff_pool *pool, u16 queue)
|
||||
{
|
||||
struct stmmac_channel *ch = &priv->channel[queue];
|
||||
bool need_update;
|
||||
u32 frame_size;
|
||||
int err;
|
||||
|
||||
if (queue >= priv->plat->rx_queues_to_use ||
|
||||
queue >= priv->plat->tx_queues_to_use)
|
||||
return -EINVAL;
|
||||
|
||||
frame_size = xsk_pool_get_rx_frame_size(pool);
|
||||
/* XDP ZC does not span multiple frame, make sure XSK pool buffer
|
||||
* size can at least store Q-in-Q frame.
|
||||
*/
|
||||
if (frame_size < ETH_FRAME_LEN + VLAN_HLEN * 2)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
err = xsk_pool_dma_map(pool, priv->device, STMMAC_RX_DMA_ATTR);
|
||||
if (err) {
|
||||
netdev_err(priv->dev, "Failed to map xsk pool\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
need_update = netif_running(priv->dev) && stmmac_xdp_is_enabled(priv);
|
||||
|
||||
if (need_update) {
|
||||
napi_disable(&ch->rx_napi);
|
||||
napi_disable(&ch->tx_napi);
|
||||
stmmac_disable_rx_queue(priv, queue);
|
||||
stmmac_disable_tx_queue(priv, queue);
|
||||
}
|
||||
|
||||
set_bit(queue, priv->af_xdp_zc_qps);
|
||||
|
||||
if (need_update) {
|
||||
stmmac_enable_rx_queue(priv, queue);
|
||||
stmmac_enable_tx_queue(priv, queue);
|
||||
napi_enable(&ch->rxtx_napi);
|
||||
|
||||
err = stmmac_xsk_wakeup(priv->dev, queue, XDP_WAKEUP_RX);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_xdp_disable_pool(struct stmmac_priv *priv, u16 queue)
|
||||
{
|
||||
struct stmmac_channel *ch = &priv->channel[queue];
|
||||
struct xsk_buff_pool *pool;
|
||||
bool need_update;
|
||||
|
||||
if (queue >= priv->plat->rx_queues_to_use ||
|
||||
queue >= priv->plat->tx_queues_to_use)
|
||||
return -EINVAL;
|
||||
|
||||
pool = xsk_get_pool_from_qid(priv->dev, queue);
|
||||
if (!pool)
|
||||
return -EINVAL;
|
||||
|
||||
need_update = netif_running(priv->dev) && stmmac_xdp_is_enabled(priv);
|
||||
|
||||
if (need_update) {
|
||||
napi_disable(&ch->rxtx_napi);
|
||||
stmmac_disable_rx_queue(priv, queue);
|
||||
stmmac_disable_tx_queue(priv, queue);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
xsk_pool_dma_unmap(pool, STMMAC_RX_DMA_ATTR);
|
||||
|
||||
clear_bit(queue, priv->af_xdp_zc_qps);
|
||||
|
||||
if (need_update) {
|
||||
stmmac_enable_rx_queue(priv, queue);
|
||||
stmmac_enable_tx_queue(priv, queue);
|
||||
napi_enable(&ch->rx_napi);
|
||||
napi_enable(&ch->tx_napi);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmmac_xdp_setup_pool(struct stmmac_priv *priv, struct xsk_buff_pool *pool,
|
||||
u16 queue)
|
||||
{
|
||||
return pool ? stmmac_xdp_enable_pool(priv, pool, queue) :
|
||||
stmmac_xdp_disable_pool(priv, queue);
|
||||
}
|
||||
|
||||
int stmmac_xdp_set_prog(struct stmmac_priv *priv, struct bpf_prog *prog,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net_device *dev = priv->dev;
|
||||
struct bpf_prog *old_prog;
|
||||
bool need_update;
|
||||
bool if_running;
|
||||
|
||||
if_running = netif_running(dev);
|
||||
|
||||
if (prog && dev->mtu > ETH_DATA_LEN) {
|
||||
/* For now, the driver doesn't support XDP functionality with
|
||||
* jumbo frames so we return error.
|
||||
*/
|
||||
NL_SET_ERR_MSG_MOD(extack, "Jumbo frames not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!prog)
|
||||
xdp_features_clear_redirect_target(dev);
|
||||
|
||||
need_update = !!priv->xdp_prog != !!prog;
|
||||
if (if_running && need_update)
|
||||
stmmac_xdp_release(dev);
|
||||
|
||||
old_prog = xchg(&priv->xdp_prog, prog);
|
||||
if (old_prog)
|
||||
bpf_prog_put(old_prog);
|
||||
|
||||
/* Disable RX SPH for XDP operation */
|
||||
priv->sph = priv->sph_cap && !stmmac_xdp_is_enabled(priv);
|
||||
|
||||
if (if_running && need_update)
|
||||
stmmac_xdp_open(dev);
|
||||
|
||||
if (prog)
|
||||
xdp_features_set_redirect_target(dev, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue