Add dwmac_intel and stmmac_pci v6.1.81

This commit is contained in:
Bjarne von Horn 2024-03-05 11:49:55 +01:00
parent 1c7f2b9bdd
commit 8aee1daee3
102 changed files with 54438 additions and 2 deletions

View File

@ -638,6 +638,80 @@ fi
AC_SUBST(KERNEL_R8169,[$kernel_r8169]) AC_SUBST(KERNEL_R8169,[$kernel_r8169])
#-----------------------------------------------------------------------------
# stmmac-pci and dwmac-intel driver
#-----------------------------------------------------------------------------
enablestmmac=0
AC_ARG_ENABLE([stmmac-pci],
AS_HELP_STRING([--enable-stmmac-pci],
[Enable stmmac driver]),
[
case "${enableval}" in
yes) enablestmmacpci=1
enablestmmac=1
;;
no) enablestmmacpci=0
;;
*) AC_MSG_ERROR([Invalid value for --enable-stmmac])
;;
esac
],
[enablestmmacpci=0] # disabled by default
)
AM_CONDITIONAL(ENABLE_STMMACPCI, test "x$enablestmmacpci" = "x1")
AC_SUBST(ENABLE_STMMACPCI,[$enablestmmacpci])
AC_ARG_ENABLE([dwmac-intel],
AS_HELP_STRING([--enable-dwmac-intel],
[Enable stmmac driver]),
[
case "${enableval}" in
yes) enabledwmacintel=1
enablestmmac=1
;;
no) enabledwmacintel=0
;;
*) AC_MSG_ERROR([Invalid value for --enable-stmmac])
;;
esac
],
[enabledwmacintel=0] # disabled by default
)
AM_CONDITIONAL(ENABLE_DWMACINTEL, test "x$enabledwmacintel" = "x1")
AC_SUBST(ENABLE_DWMACINTEL,[$enabledwmacintel])
AM_CONDITIONAL(ENABLE_STMMAC, test "x$enablestmmac" = "x1")
AC_SUBST(ENABLE_STMMAC, [$enablestmmac])
AC_ARG_WITH([stmmac-kernel],
AC_HELP_STRING(
[--with-stmmac-kernel=<X.Y.Z>],
[stmmac kernel (only if differing)]
),
[
kernelstmmac=[$withval]
],
[
kernelstmmac=$linuxversion
]
)
if test "x${enablestmmac}" = "x1"; then
AC_MSG_CHECKING([for kernel for stmmac driver])
if test ! -f "${srcdir}/devices/stmmac/stmmac-${kernelstmmac}-orig.h"; then
AC_MSG_ERROR([kernel $kernelstmmac not available for stmmac driver!])
fi
AC_MSG_RESULT([$kernelstmmac])
fi
AC_SUBST(KERNEL_STMMAC,[$kernelstmmac])
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# CCAT driver # CCAT driver
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
@ -1233,6 +1307,8 @@ AC_CONFIG_FILES([
devices/igc/Makefile devices/igc/Makefile
devices/r8169/Kbuild devices/r8169/Kbuild
devices/r8169/Makefile devices/r8169/Makefile
devices/stmmac/Kbuild
devices/stmmac/Makefile
ethercat.spec ethercat.spec
examples/Kbuild examples/Kbuild
examples/Makefile examples/Makefile

View File

@ -93,6 +93,10 @@ else
endif endif
endif endif
ifeq (@ENABLE_STMMAC@,1)
obj-m += stmmac/
endif
KBUILD_EXTRA_SYMBOLS := \ KBUILD_EXTRA_SYMBOLS := \
@abs_top_builddir@/$(LINUX_SYMVERS) \ @abs_top_builddir@/$(LINUX_SYMVERS) \
@abs_top_builddir@/master/$(LINUX_SYMVERS) @abs_top_builddir@/master/$(LINUX_SYMVERS)

View File

@ -34,7 +34,8 @@ SUBDIRS = \
genet \ genet \
igb \ igb \
igc \ igc \
r8169 r8169 \
stmmac
# using HEADERS to enable tags target # using HEADERS to enable tags target
noinst_HEADERS = \ noinst_HEADERS = \

View File

@ -34,6 +34,7 @@ from re import compile
DRIVER_MAP=( DRIVER_MAP=(
# (subdir, driver name, file prefix) # (subdir, driver name, file prefix)
(".", "8139too", "8139too"), (".", "8139too", "8139too"),
("stmmac", "dwmac_intel", "dwmac-intel"),
(".", "e100", "e100"), (".", "e100", "e100"),
("e1000", "e1000", "e1000_main"), ("e1000", "e1000", "e1000_main"),
("e1000e", "e1000e", "netdev"), ("e1000e", "e1000e", "netdev"),
@ -42,6 +43,7 @@ DRIVER_MAP=(
("igc", "igc", "igc_main"), ("igc", "igc", "igc_main"),
(".", "r8169", "r8169"), (".", "r8169", "r8169"),
("r8169", "r8169", "r8169_main"), ("r8169", "r8169", "r8169_main"),
("stmmac", "stmmac_pci", "stmmac_pci"),
) )

95
devices/stmmac/Kbuild.in Normal file
View File

@ -0,0 +1,95 @@
#-----------------------------------------------------------------------------
#
# $Id$
#
# Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
#
# This file is part of the IgH EtherCAT Master.
#
# The IgH EtherCAT Master is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
#
# The IgH EtherCAT Master is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with the IgH EtherCAT Master; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ---
#
# The license mentioned above concerns the source code only. Using the
# EtherCAT technology and brand is only permitted in compliance with the
# industrial property and similar rights of Beckhoff Automation GmbH.
#
# ---
#
# vim: syntax=make
#
#-----------------------------------------------------------------------------
TOPDIR := $(src)/../..
REV := $(shell if test -s $(TOPDIR)/revision; then \
cat $(TOPDIR)/revision; \
else \
git -C $(TOPDIR) describe 2>/dev/null || echo "unknown"; \
fi)
ifeq (@ENABLE_STMMAC@,1)
EC_STMMAC_OBJS := \
chain_mode-@KERNEL_STMMAC@-ethercat.o \
dwmac1000_core-@KERNEL_STMMAC@-ethercat.o \
dwmac1000_dma-@KERNEL_STMMAC@-ethercat.o \
dwmac100_core-@KERNEL_STMMAC@-ethercat.o \
dwmac100_dma-@KERNEL_STMMAC@-ethercat.o \
dwmac4_core-@KERNEL_STMMAC@-ethercat.o \
dwmac4_descs-@KERNEL_STMMAC@-ethercat.o \
dwmac4_dma-@KERNEL_STMMAC@-ethercat.o \
dwmac4_lib-@KERNEL_STMMAC@-ethercat.o \
dwmac5-@KERNEL_STMMAC@-ethercat.o \
dwmac_lib-@KERNEL_STMMAC@-ethercat.o \
dwxgmac2_core-@KERNEL_STMMAC@-ethercat.o \
dwxgmac2_descs-@KERNEL_STMMAC@-ethercat.o \
dwxgmac2_dma-@KERNEL_STMMAC@-ethercat.o \
enh_desc-@KERNEL_STMMAC@-ethercat.o \
hwif-@KERNEL_STMMAC@-ethercat.o \
mmc_core-@KERNEL_STMMAC@-ethercat.o \
norm_desc-@KERNEL_STMMAC@-ethercat.o \
ring_mode-@KERNEL_STMMAC@-ethercat.o \
stmmac_ethtool-@KERNEL_STMMAC@-ethercat.o \
stmmac_hwtstamp-@KERNEL_STMMAC@-ethercat.o \
stmmac_main-@KERNEL_STMMAC@-ethercat.o \
stmmac_mdio-@KERNEL_STMMAC@-ethercat.o \
stmmac_ptp-@KERNEL_STMMAC@-ethercat.o \
stmmac_tc-@KERNEL_STMMAC@-ethercat.o \
stmmac_xdp-@KERNEL_STMMAC@-ethercat.o \
$(ec_stmmac-y)
ec_stmmac-$(CONFIG_STMMAC_SELFTESTS) = \
stmmac_selftests-@KERNEL_STMMAC@-ethercat.o
ifeq (@ENABLE_DWMACINTEL@,1)
obj-m += ec_dwmac-intel.o
ec_dwmac-intel-objs := \
$(EC_STMMAC_OBJS) \
dwmac-intel-@KERNEL_STMMAC@-ethercat.o
endif
ifeq (@ENABLE_STMMACPCI@,1)
obj-m += ec_stmmac-pci.o
ec_stmmac-pci-objs := \
$(EC_STMMAC_OBJS) \
stmmac_pci-@KERNEL_STMMAC@-ethercat.o
endif
endif
KBUILD_EXTRA_SYMBOLS := \
@abs_top_builddir@/$(LINUX_SYMVERS) \
@abs_top_builddir@/master/$(LINUX_SYMVERS)
#-----------------------------------------------------------------------------

120
devices/stmmac/Makefile.am Normal file
View File

@ -0,0 +1,120 @@
#-----------------------------------------------------------------------------
#
# Copyright (C) 2006-2021 Florian Pose, Ingenieurgemeinschaft IgH
#
# This file is part of the IgH EtherCAT Master.
#
# The IgH EtherCAT Master is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
#
# The IgH EtherCAT Master is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with the IgH EtherCAT Master; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
#-----------------------------------------------------------------------------
include $(top_srcdir)/Makefile.kbuild
EXTRA_DIST = \
chain_mode-6.1-ethercat.c \
chain_mode-6.1-orig.c \
common-6.1-ethercat.h \
common-6.1-orig.h \
descs-6.1-ethercat.h \
descs-6.1-orig.h \
descs_com-6.1-ethercat.h \
descs_com-6.1-orig.h \
dwmac1000-6.1-ethercat.h \
dwmac1000-6.1-orig.h \
dwmac1000_core-6.1-ethercat.c \
dwmac1000_core-6.1-orig.c \
dwmac1000_dma-6.1-ethercat.c \
dwmac1000_dma-6.1-orig.c \
dwmac100-6.1-ethercat.h \
dwmac100-6.1-orig.h \
dwmac100_core-6.1-ethercat.c \
dwmac100_core-6.1-orig.c \
dwmac100_dma-6.1-ethercat.c \
dwmac100_dma-6.1-orig.c \
dwmac4-6.1-ethercat.h \
dwmac4-6.1-orig.h \
dwmac4_core-6.1-ethercat.c \
dwmac4_core-6.1-orig.c \
dwmac4_descs-6.1-ethercat.c \
dwmac4_descs-6.1-ethercat.h \
dwmac4_descs-6.1-orig.c \
dwmac4_descs-6.1-orig.h \
dwmac4_dma-6.1-ethercat.c \
dwmac4_dma-6.1-ethercat.h \
dwmac4_dma-6.1-orig.c \
dwmac4_dma-6.1-orig.h \
dwmac4_lib-6.1-ethercat.c \
dwmac4_lib-6.1-orig.c \
dwmac5-6.1-ethercat.c \
dwmac5-6.1-ethercat.h \
dwmac5-6.1-orig.c \
dwmac5-6.1-orig.h \
dwmac_dma-6.1-ethercat.h \
dwmac_dma-6.1-orig.h \
dwmac-intel-6.1-ethercat.c \
dwmac-intel-6.1-ethercat.h \
dwmac-intel-6.1-orig.c \
dwmac-intel-6.1-orig.h \
dwmac_lib-6.1-ethercat.c \
dwmac_lib-6.1-orig.c \
dwxgmac2-6.1-ethercat.h \
dwxgmac2-6.1-orig.h \
dwxgmac2_core-6.1-ethercat.c \
dwxgmac2_core-6.1-orig.c \
dwxgmac2_descs-6.1-ethercat.c \
dwxgmac2_descs-6.1-orig.c \
dwxgmac2_dma-6.1-ethercat.c \
dwxgmac2_dma-6.1-orig.c \
dwxlgmac2-6.1-ethercat.h \
dwxlgmac2-6.1-orig.h \
enh_desc-6.1-ethercat.c \
enh_desc-6.1-orig.c \
hwif-6.1-ethercat.c \
hwif-6.1-ethercat.h \
hwif-6.1-orig.c \
hwif-6.1-orig.h \
mmc-6.1-ethercat.h \
mmc-6.1-orig.h \
mmc_core-6.1-ethercat.c \
mmc_core-6.1-orig.c \
norm_desc-6.1-ethercat.c \
norm_desc-6.1-orig.c \
ring_mode-6.1-ethercat.c \
ring_mode-6.1-orig.c \
stmmac-6.1-ethercat.h \
stmmac-6.1-orig.h \
stmmac_ethtool-6.1-ethercat.c \
stmmac_ethtool-6.1-orig.c \
stmmac_hwtstamp-6.1-ethercat.c \
stmmac_hwtstamp-6.1-orig.c \
stmmac_main-6.1-ethercat.c \
stmmac_main-6.1-orig.c \
stmmac_mdio-6.1-ethercat.c \
stmmac_mdio-6.1-orig.c \
stmmac_pci-6.1-ethercat.c \
stmmac_pci-6.1-orig.c \
stmmac_pcs-6.1-ethercat.h \
stmmac_pcs-6.1-orig.h \
stmmac_ptp-6.1-ethercat.c \
stmmac_ptp-6.1-ethercat.h \
stmmac_ptp-6.1-orig.c \
stmmac_ptp-6.1-orig.h \
stmmac_tc-6.1-ethercat.c \
stmmac_tc-6.1-orig.c \
stmmac_xdp-6.1-ethercat.c \
stmmac_xdp-6.1-ethercat.h \
stmmac_xdp-6.1-orig.c \
stmmac_xdp-6.1-orig.h
#-----------------------------------------------------------------------------

View File

@ -0,0 +1,168 @@
// 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.1-ethercat.h"
static int jumbo_frm(void *p, struct sk_buff *skb, int csum)
{
struct stmmac_tx_queue *tx_q = (struct stmmac_tx_queue *)p;
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(void *priv_ptr, struct dma_desc *p)
{
struct stmmac_rx_queue *rx_q = (struct stmmac_rx_queue *)priv_ptr;
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(void *priv_ptr, struct dma_desc *p)
{
struct stmmac_tx_queue *tx_q = (struct stmmac_tx_queue *)priv_ptr;
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,
};

View File

@ -0,0 +1,168 @@
// 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(void *p, struct sk_buff *skb, int csum)
{
struct stmmac_tx_queue *tx_q = (struct stmmac_tx_queue *)p;
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(void *priv_ptr, struct dma_desc *p)
{
struct stmmac_rx_queue *rx_q = (struct stmmac_rx_queue *)priv_ptr;
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(void *priv_ptr, struct dma_desc *p)
{
struct stmmac_tx_queue *tx_q = (struct stmmac_tx_queue *)priv_ptr;
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,
};

View File

@ -0,0 +1,568 @@
/* 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.1-ethercat.h"
#include "hwif-6.1-ethercat.h"
#include "mmc-6.1-ethercat.h"
/* Synopsys Core versions */
#define DWMAC_CORE_3_40 0x34
#define DWMAC_CORE_3_50 0x35
#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 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_txq_stats {
unsigned long tx_pkt_n;
unsigned long tx_normal_irq_n;
};
struct stmmac_rxq_stats {
unsigned long rx_pkt_n;
unsigned long rx_normal_irq_n;
};
/* 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;
/* 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 tx_pkt_n;
unsigned long rx_pkt_n;
unsigned long normal_irq_n;
unsigned long rx_normal_irq_n;
unsigned long napi_poll;
unsigned long tx_normal_irq_n;
unsigned long tx_clean;
unsigned long tx_set_ic_bit;
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;
/* TSO */
unsigned long tx_tso_frames;
unsigned long tx_tso_nfrags;
/* 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;
/* per queue statistics */
struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES];
struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES];
};
/* 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 STMMAC_PCS_TBI (1 << 2)
#define STMMAC_PCS_RTBI (1 << 3)
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
/* DAM 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 1000
#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_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;
/* 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;
/* TSN Features */
unsigned int estwid;
unsigned int estdep;
unsigned int estsel;
unsigned int fpesel;
unsigned int tbssel;
/* Numbers of Auxiliary Snapshot Inputs */
unsigned int aux_snapshot_n;
};
/* 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 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;
struct dw_xpcs *xpcs;
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;
};
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__ */

View File

@ -0,0 +1,569 @@
/* 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_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 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_txq_stats {
unsigned long tx_pkt_n;
unsigned long tx_normal_irq_n;
};
struct stmmac_rxq_stats {
unsigned long rx_pkt_n;
unsigned long rx_normal_irq_n;
};
/* 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;
/* 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 tx_pkt_n;
unsigned long rx_pkt_n;
unsigned long normal_irq_n;
unsigned long rx_normal_irq_n;
unsigned long napi_poll;
unsigned long tx_normal_irq_n;
unsigned long tx_clean;
unsigned long tx_set_ic_bit;
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;
/* TSO */
unsigned long tx_tso_frames;
unsigned long tx_tso_nfrags;
/* 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;
/* per queue statistics */
struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES];
struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES];
};
/* 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 STMMAC_PCS_TBI (1 << 2)
#define STMMAC_PCS_RTBI (1 << 3)
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
/* DAM 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 1000
#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_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;
/* 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;
/* TSN Features */
unsigned int estwid;
unsigned int estdep;
unsigned int estsel;
unsigned int fpesel;
unsigned int tbssel;
/* Numbers of Auxiliary Snapshot Inputs */
unsigned int aux_snapshot_n;
};
/* 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 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;
struct dw_xpcs *xpcs;
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;
};
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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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

View File

@ -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

View File

@ -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__ */

View File

@ -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.1-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__ */

View File

@ -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__ */

View File

@ -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.1-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__ */

View File

@ -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__ */

View File

@ -0,0 +1,556 @@
// 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 <asm/io.h>
#include "stmmac-6.1-ethercat.h"
#include "stmmac_pcs-6.1-ethercat.h"
#include "dwmac1000-6.1-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_rane(void __iomem *ioaddr, bool restart)
{
dwmac_rane(ioaddr, GMAC_PCS_BASE, restart);
}
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(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_rane = dwmac1000_rane,
.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.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;
}

View File

@ -0,0 +1,556 @@
// 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 <asm/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_rane(void __iomem *ioaddr, bool restart)
{
dwmac_rane(ioaddr, GMAC_PCS_BASE, restart);
}
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(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_rane = dwmac1000_rane,
.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.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;
}

View File

@ -0,0 +1,291 @@
// 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 <asm/io.h>
#include "dwmac1000-6.1-ethercat.h"
#include "dwmac_dma-6.1-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(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, int atds)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
/*
* 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 (atds)
value |= DMA_BUS_MODE_ATDS;
if (dma_cfg->aal)
value |= DMA_BUS_MODE_AAL;
writel(value, ioaddr + DMA_BUS_MODE);
/* Mask interrupts by writing to CSR7 */
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
}
static void dwmac1000_dma_init_rx(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_RCV_BASE_ADDR);
}
static void dwmac1000_dma_init_tx(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_TX_BASE_ADDR);
}
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(void __iomem *ioaddr, int mode,
u32 channel, int fifosz, u8 qmode)
{
u32 csr6 = readl(ioaddr + DMA_CONTROL);
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_CONTROL);
}
static void dwmac1000_dma_operation_mode_tx(void __iomem *ioaddr, int mode,
u32 channel, int fifosz, u8 qmode)
{
u32 csr6 = readl(ioaddr + DMA_CONTROL);
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_CONTROL);
}
static void dwmac1000_dump_dma_regs(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(void __iomem *ioaddr, u32 riwt,
u32 queue)
{
writel(riwt, ioaddr + DMA_RX_WATCHDOG);
}
const struct stmmac_dma_ops dwmac1000_dma_ops = {
.reset = dwmac_dma_reset,
.init = dwmac1000_dma_init,
.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,
};

View File

@ -0,0 +1,291 @@
// 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 <asm/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(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, int atds)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
/*
* 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 (atds)
value |= DMA_BUS_MODE_ATDS;
if (dma_cfg->aal)
value |= DMA_BUS_MODE_AAL;
writel(value, ioaddr + DMA_BUS_MODE);
/* Mask interrupts by writing to CSR7 */
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
}
static void dwmac1000_dma_init_rx(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_RCV_BASE_ADDR);
}
static void dwmac1000_dma_init_tx(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_TX_BASE_ADDR);
}
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(void __iomem *ioaddr, int mode,
u32 channel, int fifosz, u8 qmode)
{
u32 csr6 = readl(ioaddr + DMA_CONTROL);
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_CONTROL);
}
static void dwmac1000_dma_operation_mode_tx(void __iomem *ioaddr, int mode,
u32 channel, int fifosz, u8 qmode)
{
u32 csr6 = readl(ioaddr + DMA_CONTROL);
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_CONTROL);
}
static void dwmac1000_dump_dma_regs(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(void __iomem *ioaddr, u32 riwt,
u32 queue)
{
writel(riwt, ioaddr + DMA_RX_WATCHDOG);
}
const struct stmmac_dma_ops dwmac1000_dma_ops = {
.reset = dwmac_dma_reset,
.init = dwmac1000_dma_init,
.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,
};

View File

@ -0,0 +1,193 @@
// 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 <asm/io.h>
#include "stmmac-6.1-ethercat.h"
#include "dwmac100-6.1-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.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;
}

View File

@ -0,0 +1,193 @@
// 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 <asm/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.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;
}

View File

@ -0,0 +1,127 @@
// 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 <asm/io.h>
#include "dwmac100-6.1-ethercat.h"
#include "dwmac_dma-6.1-ethercat.h"
static void dwmac100_dma_init(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, int atds)
{
/* 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(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(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(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(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(void *data, struct stmmac_extra_stats *x,
void __iomem *ioaddr)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
if (unlikely(csr8)) {
if (csr8 & DMA_MISSED_FRAME_OVE) {
stats->rx_over_errors += 0x800;
x->rx_overflow_cntr += 0x800;
} else {
unsigned int ove_cntr;
ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
stats->rx_over_errors += ove_cntr;
x->rx_overflow_cntr += ove_cntr;
}
if (csr8 & DMA_MISSED_FRAME_OVE_M) {
stats->rx_missed_errors += 0xffff;
x->rx_missed_cntr += 0xffff;
} else {
unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
stats->rx_missed_errors += miss_f;
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,
};

View File

@ -0,0 +1,127 @@
// 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 <asm/io.h>
#include "dwmac100.h"
#include "dwmac_dma.h"
static void dwmac100_dma_init(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, int atds)
{
/* 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(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(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(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(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(void *data, struct stmmac_extra_stats *x,
void __iomem *ioaddr)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
if (unlikely(csr8)) {
if (csr8 & DMA_MISSED_FRAME_OVE) {
stats->rx_over_errors += 0x800;
x->rx_overflow_cntr += 0x800;
} else {
unsigned int ove_cntr;
ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
stats->rx_over_errors += ove_cntr;
x->rx_overflow_cntr += ove_cntr;
}
if (csr8 & DMA_MISSED_FRAME_OVE_M) {
stats->rx_missed_errors += 0xffff;
x->rx_missed_cntr += 0xffff;
} else {
unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
stats->rx_missed_errors += miss_f;
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,
};

View File

@ -0,0 +1,520 @@
/* 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.1-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_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)
/* 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_Q04MDMACH_MASK GENMASK(3, 0)
#define MTL_RXQ_DMA_Q04MDMACH(x) ((x) << 0)
#define MTL_RXQ_DMA_QXMDMACH_MASK(x) GENMASK(11 + (8 * ((x) - 1)), 8 * (x))
#define MTL_RXQ_DMA_QXMDMACH(chan, q) ((chan) << (8 * (q)))
#define MTL_CHAN_BASE_ADDR 0x00000d00
#define MTL_CHAN_BASE_OFFSET 0x40
#define MTL_CHANX_BASE_ADDR(x) (MTL_CHAN_BASE_ADDR + \
(x * MTL_CHAN_BASE_OFFSET))
#define MTL_CHAN_TX_OP_MODE(x) MTL_CHANX_BASE_ADDR(x)
#define MTL_CHAN_TX_DEBUG(x) (MTL_CHANX_BASE_ADDR(x) + 0x8)
#define MTL_CHAN_INT_CTRL(x) (MTL_CHANX_BASE_ADDR(x) + 0x2c)
#define MTL_CHAN_RX_OP_MODE(x) (MTL_CHANX_BASE_ADDR(x) + 0x30)
#define MTL_CHAN_RX_DEBUG(x) (MTL_CHANX_BASE_ADDR(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
#define MTL_ETSX_CTRL_BASE_ADDR(x) (MTL_ETS_CTRL_BASE_ADDR + \
((x) * MTL_ETS_CTRL_BASE_OFFSET))
#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
#define MTL_TXQX_WEIGHT_BASE_ADDR(x) (MTL_TXQ_WEIGHT_BASE_ADDR + \
((x) * MTL_TXQ_WEIGHT_BASE_OFFSET))
#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
#define MTL_SEND_SLP_CREDX_BASE_ADDR(x) (MTL_SEND_SLP_CRED_BASE_ADDR + \
((x) * MTL_SEND_SLP_CRED_OFFSET))
#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
#define MTL_HIGH_CREDX_BASE_ADDR(x) (MTL_HIGH_CRED_BASE_ADDR + \
((x) * MTL_HIGH_CRED_OFFSET))
#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
#define MTL_LOW_CREDX_BASE_ADDR(x) (MTL_LOW_CRED_BASE_ADDR + \
((x) * MTL_LOW_CRED_OFFSET))
#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)
/* LNKMOD */
#define GMAC_PHYIF_CTRLSTATUS_LNKMOD_MASK 0x1
/* 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__ */

View File

@ -0,0 +1,520 @@
/* 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_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)
/* 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_Q04MDMACH_MASK GENMASK(3, 0)
#define MTL_RXQ_DMA_Q04MDMACH(x) ((x) << 0)
#define MTL_RXQ_DMA_QXMDMACH_MASK(x) GENMASK(11 + (8 * ((x) - 1)), 8 * (x))
#define MTL_RXQ_DMA_QXMDMACH(chan, q) ((chan) << (8 * (q)))
#define MTL_CHAN_BASE_ADDR 0x00000d00
#define MTL_CHAN_BASE_OFFSET 0x40
#define MTL_CHANX_BASE_ADDR(x) (MTL_CHAN_BASE_ADDR + \
(x * MTL_CHAN_BASE_OFFSET))
#define MTL_CHAN_TX_OP_MODE(x) MTL_CHANX_BASE_ADDR(x)
#define MTL_CHAN_TX_DEBUG(x) (MTL_CHANX_BASE_ADDR(x) + 0x8)
#define MTL_CHAN_INT_CTRL(x) (MTL_CHANX_BASE_ADDR(x) + 0x2c)
#define MTL_CHAN_RX_OP_MODE(x) (MTL_CHANX_BASE_ADDR(x) + 0x30)
#define MTL_CHAN_RX_DEBUG(x) (MTL_CHANX_BASE_ADDR(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
#define MTL_ETSX_CTRL_BASE_ADDR(x) (MTL_ETS_CTRL_BASE_ADDR + \
((x) * MTL_ETS_CTRL_BASE_OFFSET))
#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
#define MTL_TXQX_WEIGHT_BASE_ADDR(x) (MTL_TXQ_WEIGHT_BASE_ADDR + \
((x) * MTL_TXQ_WEIGHT_BASE_OFFSET))
#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
#define MTL_SEND_SLP_CREDX_BASE_ADDR(x) (MTL_SEND_SLP_CRED_BASE_ADDR + \
((x) * MTL_SEND_SLP_CRED_OFFSET))
#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
#define MTL_HIGH_CREDX_BASE_ADDR(x) (MTL_HIGH_CRED_BASE_ADDR + \
((x) * MTL_HIGH_CRED_OFFSET))
#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
#define MTL_LOW_CREDX_BASE_ADDR(x) (MTL_LOW_CRED_BASE_ADDR + \
((x) * MTL_LOW_CRED_OFFSET))
#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)
/* LNKMOD */
#define GMAC_PHYIF_CTRLSTATUS_LNKMOD_MASK 0x1
/* 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

View File

@ -0,0 +1,585 @@
// 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.1-ethercat.h"
#include "dwmac4-6.1-ethercat.h"
#include "dwmac4_descs-6.1-ethercat.h"
static int dwmac4_wrback_get_tx_status(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p,
void __iomem *ioaddr)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
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++;
stats->tx_carrier_errors++;
}
if (unlikely(tdes3 & TDES3_NO_CARRIER)) {
x->tx_carrier++;
stats->tx_carrier_errors++;
}
if (unlikely((tdes3 & TDES3_LATE_COLLISION) ||
(tdes3 & TDES3_EXCESSIVE_COLLISION)))
stats->collisions +=
(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(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
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))
stats->rx_length_errors++;
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++;
stats->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)
{
p->des3 |= cpu_to_le32(RDES3_OWN | RDES3_BUFFER1_VALID_ADDR);
if (!disable_rx_ic)
p->des3 |= cpu_to_le32(RDES3_INT_ON_COMPLETION_EN);
}
static int dwmac4_get_tx_ls(struct dma_desc *p)
{
return (le32_to_cpu(p->des3) & TDES3_LAST_DESCRIPTOR)
>> TDES3_LAST_DESCRIPTOR_SHIFT;
}
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_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,
};

View File

@ -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__ */

View File

@ -0,0 +1,585 @@
// 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(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p,
void __iomem *ioaddr)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
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++;
stats->tx_carrier_errors++;
}
if (unlikely(tdes3 & TDES3_NO_CARRIER)) {
x->tx_carrier++;
stats->tx_carrier_errors++;
}
if (unlikely((tdes3 & TDES3_LATE_COLLISION) ||
(tdes3 & TDES3_EXCESSIVE_COLLISION)))
stats->collisions +=
(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(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
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))
stats->rx_length_errors++;
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++;
stats->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)
{
p->des3 |= cpu_to_le32(RDES3_OWN | RDES3_BUFFER1_VALID_ADDR);
if (!disable_rx_ic)
p->des3 |= cpu_to_le32(RDES3_INT_ON_COMPLETION_EN);
}
static int dwmac4_get_tx_ls(struct dma_desc *p)
{
return (le32_to_cpu(p->des3) & TDES3_LAST_DESCRIPTOR)
>> TDES3_LAST_DESCRIPTOR_SHIFT;
}
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_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,
};

View File

@ -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__ */

View File

@ -0,0 +1,577 @@
// 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.1-ethercat.h"
#include "dwmac4_dma-6.1-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(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
dma_addr_t dma_rx_phy, u32 chan)
{
u32 value;
u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
value = value | (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(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(chan));
writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_CHAN_RX_BASE_ADDR(chan));
}
static void dwmac4_dma_init_tx_chan(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
dma_addr_t dma_tx_phy, u32 chan)
{
u32 value;
u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(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(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(chan));
writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_CHAN_TX_BASE_ADDR(chan));
}
static void dwmac4_dma_init_channel(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, u32 chan)
{
u32 value;
/* common channel control register config */
value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
if (dma_cfg->pblx8)
value = value | DMA_BUS_MODE_PBL;
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
/* Mask interrupts by writing to CSR7 */
writel(DMA_CHAN_INTR_DEFAULT_MASK,
ioaddr + DMA_CHAN_INTR_ENA(chan));
}
static void dwmac410_dma_init_channel(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, u32 chan)
{
u32 value;
/* common channel control register config */
value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
if (dma_cfg->pblx8)
value = value | DMA_BUS_MODE_PBL;
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
/* Mask interrupts by writing to CSR7 */
writel(DMA_CHAN_INTR_DEFAULT_MASK_4_10,
ioaddr + DMA_CHAN_INTR_ENA(chan));
}
static void dwmac4_dma_init(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, int atds)
{
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(void __iomem *ioaddr, u32 channel,
u32 *reg_space)
{
reg_space[DMA_CHAN_CONTROL(channel) / 4] =
readl(ioaddr + DMA_CHAN_CONTROL(channel));
reg_space[DMA_CHAN_TX_CONTROL(channel) / 4] =
readl(ioaddr + DMA_CHAN_TX_CONTROL(channel));
reg_space[DMA_CHAN_RX_CONTROL(channel) / 4] =
readl(ioaddr + DMA_CHAN_RX_CONTROL(channel));
reg_space[DMA_CHAN_TX_BASE_ADDR(channel) / 4] =
readl(ioaddr + DMA_CHAN_TX_BASE_ADDR(channel));
reg_space[DMA_CHAN_RX_BASE_ADDR(channel) / 4] =
readl(ioaddr + DMA_CHAN_RX_BASE_ADDR(channel));
reg_space[DMA_CHAN_TX_END_ADDR(channel) / 4] =
readl(ioaddr + DMA_CHAN_TX_END_ADDR(channel));
reg_space[DMA_CHAN_RX_END_ADDR(channel) / 4] =
readl(ioaddr + DMA_CHAN_RX_END_ADDR(channel));
reg_space[DMA_CHAN_TX_RING_LEN(channel) / 4] =
readl(ioaddr + DMA_CHAN_TX_RING_LEN(channel));
reg_space[DMA_CHAN_RX_RING_LEN(channel) / 4] =
readl(ioaddr + DMA_CHAN_RX_RING_LEN(channel));
reg_space[DMA_CHAN_INTR_ENA(channel) / 4] =
readl(ioaddr + DMA_CHAN_INTR_ENA(channel));
reg_space[DMA_CHAN_RX_WATCHDOG(channel) / 4] =
readl(ioaddr + DMA_CHAN_RX_WATCHDOG(channel));
reg_space[DMA_CHAN_SLOT_CTRL_STATUS(channel) / 4] =
readl(ioaddr + DMA_CHAN_SLOT_CTRL_STATUS(channel));
reg_space[DMA_CHAN_CUR_TX_DESC(channel) / 4] =
readl(ioaddr + DMA_CHAN_CUR_TX_DESC(channel));
reg_space[DMA_CHAN_CUR_RX_DESC(channel) / 4] =
readl(ioaddr + DMA_CHAN_CUR_RX_DESC(channel));
reg_space[DMA_CHAN_CUR_TX_BUF_ADDR(channel) / 4] =
readl(ioaddr + DMA_CHAN_CUR_TX_BUF_ADDR(channel));
reg_space[DMA_CHAN_CUR_RX_BUF_ADDR(channel) / 4] =
readl(ioaddr + DMA_CHAN_CUR_RX_BUF_ADDR(channel));
reg_space[DMA_CHAN_STATUS(channel) / 4] =
readl(ioaddr + DMA_CHAN_STATUS(channel));
}
static void dwmac4_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space)
{
int i;
for (i = 0; i < DMA_CHANNEL_NB_MAX; i++)
_dwmac4_dump_dma_regs(ioaddr, i, reg_space);
}
static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 queue)
{
writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(queue));
}
static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
u32 channel, int fifosz, u8 qmode)
{
unsigned int rqs = fifosz / 256 - 1;
u32 mtl_rx_op;
mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(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(channel));
}
static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
u32 channel, int fifosz, u8 qmode)
{
u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(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(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(void __iomem *ioaddr, bool en, u32 chan)
{
u32 value;
if (en) {
/* enable TSO */
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
writel(value | DMA_CONTROL_TSE,
ioaddr + DMA_CHAN_TX_CONTROL(chan));
} else {
/* enable TSO */
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
writel(value & ~DMA_CONTROL_TSE,
ioaddr + DMA_CHAN_TX_CONTROL(chan));
}
}
static void dwmac4_qmode(void __iomem *ioaddr, u32 channel, u8 qmode)
{
u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(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(channel));
}
static void dwmac4_set_bfsize(void __iomem *ioaddr, int bfsize, u32 chan)
{
u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
value &= ~DMA_RBSZ_MASK;
value |= (bfsize << DMA_RBSZ_SHIFT) & DMA_RBSZ_MASK;
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
}
static void dwmac4_enable_sph(void __iomem *ioaddr, bool en, u32 chan)
{
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 + DMA_CHAN_CONTROL(chan));
if (en)
value |= DMA_CONTROL_SPH;
else
value &= ~DMA_CONTROL_SPH;
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
}
static int dwmac4_enable_tbs(void __iomem *ioaddr, bool en, u32 chan)
{
u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
if (en)
value |= DMA_CONTROL_EDSE;
else
value &= ~DMA_CONTROL_EDSE;
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(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,
};

View File

@ -0,0 +1,238 @@
/* 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 chanels oriented */
#define DMA_CHAN_BASE_ADDR 0x00001100
#define DMA_CHAN_BASE_OFFSET 0x80
#define DMA_CHANX_BASE_ADDR(x) (DMA_CHAN_BASE_ADDR + \
(x * DMA_CHAN_BASE_OFFSET))
#define DMA_CHAN_REG_NUMBER 17
#define DMA_CHAN_CONTROL(x) DMA_CHANX_BASE_ADDR(x)
#define DMA_CHAN_TX_CONTROL(x) (DMA_CHANX_BASE_ADDR(x) + 0x4)
#define DMA_CHAN_RX_CONTROL(x) (DMA_CHANX_BASE_ADDR(x) + 0x8)
#define DMA_CHAN_TX_BASE_ADDR_HI(x) (DMA_CHANX_BASE_ADDR(x) + 0x10)
#define DMA_CHAN_TX_BASE_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x14)
#define DMA_CHAN_RX_BASE_ADDR_HI(x) (DMA_CHANX_BASE_ADDR(x) + 0x18)
#define DMA_CHAN_RX_BASE_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x1c)
#define DMA_CHAN_TX_END_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x20)
#define DMA_CHAN_RX_END_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x28)
#define DMA_CHAN_TX_RING_LEN(x) (DMA_CHANX_BASE_ADDR(x) + 0x2c)
#define DMA_CHAN_RX_RING_LEN(x) (DMA_CHANX_BASE_ADDR(x) + 0x30)
#define DMA_CHAN_INTR_ENA(x) (DMA_CHANX_BASE_ADDR(x) + 0x34)
#define DMA_CHAN_RX_WATCHDOG(x) (DMA_CHANX_BASE_ADDR(x) + 0x38)
#define DMA_CHAN_SLOT_CTRL_STATUS(x) (DMA_CHANX_BASE_ADDR(x) + 0x3c)
#define DMA_CHAN_CUR_TX_DESC(x) (DMA_CHANX_BASE_ADDR(x) + 0x44)
#define DMA_CHAN_CUR_RX_DESC(x) (DMA_CHANX_BASE_ADDR(x) + 0x4c)
#define DMA_CHAN_CUR_TX_BUF_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x54)
#define DMA_CHAN_CUR_RX_BUF_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x5c)
#define DMA_CHAN_STATUS(x) (DMA_CHANX_BASE_ADDR(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(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac410_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac4_dma_start_tx(void __iomem *ioaddr, u32 chan);
void dwmac4_dma_stop_tx(void __iomem *ioaddr, u32 chan);
void dwmac4_dma_start_rx(void __iomem *ioaddr, u32 chan);
void dwmac4_dma_stop_rx(void __iomem *ioaddr, u32 chan);
int dwmac4_dma_interrupt(void __iomem *ioaddr,
struct stmmac_extra_stats *x, u32 chan, u32 dir);
void dwmac4_set_rx_ring_len(void __iomem *ioaddr, u32 len, u32 chan);
void dwmac4_set_tx_ring_len(void __iomem *ioaddr, u32 len, u32 chan);
void dwmac4_set_rx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
void dwmac4_set_tx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
#endif /* __DWMAC4_DMA_H__ */

View File

@ -0,0 +1,577 @@
// 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"
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(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
dma_addr_t dma_rx_phy, u32 chan)
{
u32 value;
u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
value = value | (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(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(chan));
writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_CHAN_RX_BASE_ADDR(chan));
}
static void dwmac4_dma_init_tx_chan(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
dma_addr_t dma_tx_phy, u32 chan)
{
u32 value;
u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(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(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(chan));
writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_CHAN_TX_BASE_ADDR(chan));
}
static void dwmac4_dma_init_channel(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, u32 chan)
{
u32 value;
/* common channel control register config */
value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
if (dma_cfg->pblx8)
value = value | DMA_BUS_MODE_PBL;
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
/* Mask interrupts by writing to CSR7 */
writel(DMA_CHAN_INTR_DEFAULT_MASK,
ioaddr + DMA_CHAN_INTR_ENA(chan));
}
static void dwmac410_dma_init_channel(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, u32 chan)
{
u32 value;
/* common channel control register config */
value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
if (dma_cfg->pblx8)
value = value | DMA_BUS_MODE_PBL;
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
/* Mask interrupts by writing to CSR7 */
writel(DMA_CHAN_INTR_DEFAULT_MASK_4_10,
ioaddr + DMA_CHAN_INTR_ENA(chan));
}
static void dwmac4_dma_init(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, int atds)
{
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(void __iomem *ioaddr, u32 channel,
u32 *reg_space)
{
reg_space[DMA_CHAN_CONTROL(channel) / 4] =
readl(ioaddr + DMA_CHAN_CONTROL(channel));
reg_space[DMA_CHAN_TX_CONTROL(channel) / 4] =
readl(ioaddr + DMA_CHAN_TX_CONTROL(channel));
reg_space[DMA_CHAN_RX_CONTROL(channel) / 4] =
readl(ioaddr + DMA_CHAN_RX_CONTROL(channel));
reg_space[DMA_CHAN_TX_BASE_ADDR(channel) / 4] =
readl(ioaddr + DMA_CHAN_TX_BASE_ADDR(channel));
reg_space[DMA_CHAN_RX_BASE_ADDR(channel) / 4] =
readl(ioaddr + DMA_CHAN_RX_BASE_ADDR(channel));
reg_space[DMA_CHAN_TX_END_ADDR(channel) / 4] =
readl(ioaddr + DMA_CHAN_TX_END_ADDR(channel));
reg_space[DMA_CHAN_RX_END_ADDR(channel) / 4] =
readl(ioaddr + DMA_CHAN_RX_END_ADDR(channel));
reg_space[DMA_CHAN_TX_RING_LEN(channel) / 4] =
readl(ioaddr + DMA_CHAN_TX_RING_LEN(channel));
reg_space[DMA_CHAN_RX_RING_LEN(channel) / 4] =
readl(ioaddr + DMA_CHAN_RX_RING_LEN(channel));
reg_space[DMA_CHAN_INTR_ENA(channel) / 4] =
readl(ioaddr + DMA_CHAN_INTR_ENA(channel));
reg_space[DMA_CHAN_RX_WATCHDOG(channel) / 4] =
readl(ioaddr + DMA_CHAN_RX_WATCHDOG(channel));
reg_space[DMA_CHAN_SLOT_CTRL_STATUS(channel) / 4] =
readl(ioaddr + DMA_CHAN_SLOT_CTRL_STATUS(channel));
reg_space[DMA_CHAN_CUR_TX_DESC(channel) / 4] =
readl(ioaddr + DMA_CHAN_CUR_TX_DESC(channel));
reg_space[DMA_CHAN_CUR_RX_DESC(channel) / 4] =
readl(ioaddr + DMA_CHAN_CUR_RX_DESC(channel));
reg_space[DMA_CHAN_CUR_TX_BUF_ADDR(channel) / 4] =
readl(ioaddr + DMA_CHAN_CUR_TX_BUF_ADDR(channel));
reg_space[DMA_CHAN_CUR_RX_BUF_ADDR(channel) / 4] =
readl(ioaddr + DMA_CHAN_CUR_RX_BUF_ADDR(channel));
reg_space[DMA_CHAN_STATUS(channel) / 4] =
readl(ioaddr + DMA_CHAN_STATUS(channel));
}
static void dwmac4_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space)
{
int i;
for (i = 0; i < DMA_CHANNEL_NB_MAX; i++)
_dwmac4_dump_dma_regs(ioaddr, i, reg_space);
}
static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 queue)
{
writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(queue));
}
static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
u32 channel, int fifosz, u8 qmode)
{
unsigned int rqs = fifosz / 256 - 1;
u32 mtl_rx_op;
mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(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(channel));
}
static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
u32 channel, int fifosz, u8 qmode)
{
u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(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(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(void __iomem *ioaddr, bool en, u32 chan)
{
u32 value;
if (en) {
/* enable TSO */
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
writel(value | DMA_CONTROL_TSE,
ioaddr + DMA_CHAN_TX_CONTROL(chan));
} else {
/* enable TSO */
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
writel(value & ~DMA_CONTROL_TSE,
ioaddr + DMA_CHAN_TX_CONTROL(chan));
}
}
static void dwmac4_qmode(void __iomem *ioaddr, u32 channel, u8 qmode)
{
u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(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(channel));
}
static void dwmac4_set_bfsize(void __iomem *ioaddr, int bfsize, u32 chan)
{
u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
value &= ~DMA_RBSZ_MASK;
value |= (bfsize << DMA_RBSZ_SHIFT) & DMA_RBSZ_MASK;
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
}
static void dwmac4_enable_sph(void __iomem *ioaddr, bool en, u32 chan)
{
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 + DMA_CHAN_CONTROL(chan));
if (en)
value |= DMA_CONTROL_SPH;
else
value &= ~DMA_CONTROL_SPH;
writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
}
static int dwmac4_enable_tbs(void __iomem *ioaddr, bool en, u32 chan)
{
u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
if (en)
value |= DMA_CONTROL_EDSE;
else
value &= ~DMA_CONTROL_EDSE;
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
value = readl(ioaddr + DMA_CHAN_TX_CONTROL(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,
};

View File

@ -0,0 +1,238 @@
/* 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 chanels oriented */
#define DMA_CHAN_BASE_ADDR 0x00001100
#define DMA_CHAN_BASE_OFFSET 0x80
#define DMA_CHANX_BASE_ADDR(x) (DMA_CHAN_BASE_ADDR + \
(x * DMA_CHAN_BASE_OFFSET))
#define DMA_CHAN_REG_NUMBER 17
#define DMA_CHAN_CONTROL(x) DMA_CHANX_BASE_ADDR(x)
#define DMA_CHAN_TX_CONTROL(x) (DMA_CHANX_BASE_ADDR(x) + 0x4)
#define DMA_CHAN_RX_CONTROL(x) (DMA_CHANX_BASE_ADDR(x) + 0x8)
#define DMA_CHAN_TX_BASE_ADDR_HI(x) (DMA_CHANX_BASE_ADDR(x) + 0x10)
#define DMA_CHAN_TX_BASE_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x14)
#define DMA_CHAN_RX_BASE_ADDR_HI(x) (DMA_CHANX_BASE_ADDR(x) + 0x18)
#define DMA_CHAN_RX_BASE_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x1c)
#define DMA_CHAN_TX_END_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x20)
#define DMA_CHAN_RX_END_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x28)
#define DMA_CHAN_TX_RING_LEN(x) (DMA_CHANX_BASE_ADDR(x) + 0x2c)
#define DMA_CHAN_RX_RING_LEN(x) (DMA_CHANX_BASE_ADDR(x) + 0x30)
#define DMA_CHAN_INTR_ENA(x) (DMA_CHANX_BASE_ADDR(x) + 0x34)
#define DMA_CHAN_RX_WATCHDOG(x) (DMA_CHANX_BASE_ADDR(x) + 0x38)
#define DMA_CHAN_SLOT_CTRL_STATUS(x) (DMA_CHANX_BASE_ADDR(x) + 0x3c)
#define DMA_CHAN_CUR_TX_DESC(x) (DMA_CHANX_BASE_ADDR(x) + 0x44)
#define DMA_CHAN_CUR_RX_DESC(x) (DMA_CHANX_BASE_ADDR(x) + 0x4c)
#define DMA_CHAN_CUR_TX_BUF_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x54)
#define DMA_CHAN_CUR_RX_BUF_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x5c)
#define DMA_CHAN_STATUS(x) (DMA_CHANX_BASE_ADDR(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(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac410_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac4_dma_start_tx(void __iomem *ioaddr, u32 chan);
void dwmac4_dma_stop_tx(void __iomem *ioaddr, u32 chan);
void dwmac4_dma_start_rx(void __iomem *ioaddr, u32 chan);
void dwmac4_dma_stop_rx(void __iomem *ioaddr, u32 chan);
int dwmac4_dma_interrupt(void __iomem *ioaddr,
struct stmmac_extra_stats *x, u32 chan, u32 dir);
void dwmac4_set_rx_ring_len(void __iomem *ioaddr, u32 len, u32 chan);
void dwmac4_set_tx_ring_len(void __iomem *ioaddr, u32 len, u32 chan);
void dwmac4_set_rx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
void dwmac4_set_tx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
#endif /* __DWMAC4_DMA_H__ */

View File

@ -0,0 +1,237 @@
// 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.1-ethercat.h"
#include "dwmac4_dma-6.1-ethercat.h"
#include "dwmac4-6.1-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(void __iomem *ioaddr, u32 tail_ptr, u32 chan)
{
writel(tail_ptr, ioaddr + DMA_CHAN_RX_END_ADDR(chan));
}
void dwmac4_set_tx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan)
{
writel(tail_ptr, ioaddr + DMA_CHAN_TX_END_ADDR(chan));
}
void dwmac4_dma_start_tx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
value |= DMA_CONTROL_ST;
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
value = readl(ioaddr + GMAC_CONFIG);
value |= GMAC_CONFIG_TE;
writel(value, ioaddr + GMAC_CONFIG);
}
void dwmac4_dma_stop_tx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
value &= ~DMA_CONTROL_ST;
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
}
void dwmac4_dma_start_rx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
value |= DMA_CONTROL_SR;
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
value = readl(ioaddr + GMAC_CONFIG);
value |= GMAC_CONFIG_RE;
writel(value, ioaddr + GMAC_CONFIG);
}
void dwmac4_dma_stop_rx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
value &= ~DMA_CONTROL_SR;
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
}
void dwmac4_set_tx_ring_len(void __iomem *ioaddr, u32 len, u32 chan)
{
writel(len, ioaddr + DMA_CHAN_TX_RING_LEN(chan));
}
void dwmac4_set_rx_ring_len(void __iomem *ioaddr, u32 len, u32 chan)
{
writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(chan));
}
void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
if (rx)
value |= DMA_CHAN_INTR_DEFAULT_RX;
if (tx)
value |= DMA_CHAN_INTR_DEFAULT_TX;
writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
}
void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(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(chan));
}
void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
if (rx)
value &= ~DMA_CHAN_INTR_DEFAULT_RX;
if (tx)
value &= ~DMA_CHAN_INTR_DEFAULT_TX;
writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
}
void dwmac410_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(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(chan));
}
int dwmac4_dma_interrupt(void __iomem *ioaddr,
struct stmmac_extra_stats *x, u32 chan, u32 dir)
{
u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(chan));
u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
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_NIS))
x->normal_irq_n++;
if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
x->rx_normal_irq_n++;
x->rxq_stats[chan].rx_normal_irq_n++;
ret |= handle_rx;
}
if (likely(intr_status & DMA_CHAN_STATUS_TI)) {
x->tx_normal_irq_n++;
x->txq_stats[chan].tx_normal_irq_n++;
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(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;
}

View File

@ -0,0 +1,237 @@
// 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"
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(void __iomem *ioaddr, u32 tail_ptr, u32 chan)
{
writel(tail_ptr, ioaddr + DMA_CHAN_RX_END_ADDR(chan));
}
void dwmac4_set_tx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan)
{
writel(tail_ptr, ioaddr + DMA_CHAN_TX_END_ADDR(chan));
}
void dwmac4_dma_start_tx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
value |= DMA_CONTROL_ST;
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
value = readl(ioaddr + GMAC_CONFIG);
value |= GMAC_CONFIG_TE;
writel(value, ioaddr + GMAC_CONFIG);
}
void dwmac4_dma_stop_tx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
value &= ~DMA_CONTROL_ST;
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
}
void dwmac4_dma_start_rx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
value |= DMA_CONTROL_SR;
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
value = readl(ioaddr + GMAC_CONFIG);
value |= GMAC_CONFIG_RE;
writel(value, ioaddr + GMAC_CONFIG);
}
void dwmac4_dma_stop_rx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
value &= ~DMA_CONTROL_SR;
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
}
void dwmac4_set_tx_ring_len(void __iomem *ioaddr, u32 len, u32 chan)
{
writel(len, ioaddr + DMA_CHAN_TX_RING_LEN(chan));
}
void dwmac4_set_rx_ring_len(void __iomem *ioaddr, u32 len, u32 chan)
{
writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(chan));
}
void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
if (rx)
value |= DMA_CHAN_INTR_DEFAULT_RX;
if (tx)
value |= DMA_CHAN_INTR_DEFAULT_TX;
writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
}
void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(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(chan));
}
void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
if (rx)
value &= ~DMA_CHAN_INTR_DEFAULT_RX;
if (tx)
value &= ~DMA_CHAN_INTR_DEFAULT_TX;
writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
}
void dwmac410_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(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(chan));
}
int dwmac4_dma_interrupt(void __iomem *ioaddr,
struct stmmac_extra_stats *x, u32 chan, u32 dir)
{
u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(chan));
u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
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_NIS))
x->normal_irq_n++;
if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
x->rx_normal_irq_n++;
x->rxq_stats[chan].rx_normal_irq_n++;
ret |= handle_rx;
}
if (likely(intr_status & DMA_CHAN_STATUS_TI)) {
x->tx_normal_irq_n++;
x->txq_stats[chan].tx_normal_irq_n++;
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(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;
}

View File

@ -0,0 +1,777 @@
// 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.1-ethercat.h"
#include "dwmac4-6.1-ethercat.h"
#include "dwmac5-6.1-ethercat.h"
#include "stmmac-6.1-ethercat.h"
#include "stmmac_ptp-6.1-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;
}
static int dwmac5_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl)
{
u32 ctrl;
writel(val, ioaddr + MTL_EST_GCL_DATA);
ctrl = (reg << ADDR_SHIFT);
ctrl |= gcl ? 0 : GCRR;
writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
ctrl |= SRWO;
writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
return readl_poll_timeout(ioaddr + MTL_EST_GCL_CONTROL,
ctrl, !(ctrl & SRWO), 100, 5000);
}
int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
unsigned int ptp_rate)
{
int i, ret = 0x0;
u32 ctrl;
ret |= dwmac5_est_write(ioaddr, BTR_LOW, cfg->btr[0], false);
ret |= dwmac5_est_write(ioaddr, BTR_HIGH, cfg->btr[1], false);
ret |= dwmac5_est_write(ioaddr, TER, cfg->ter, false);
ret |= dwmac5_est_write(ioaddr, LLR, cfg->gcl_size, false);
ret |= dwmac5_est_write(ioaddr, CTR_LOW, cfg->ctr[0], false);
ret |= dwmac5_est_write(ioaddr, CTR_HIGH, cfg->ctr[1], false);
if (ret)
return ret;
for (i = 0; i < cfg->gcl_size; i++) {
ret = dwmac5_est_write(ioaddr, i, cfg->gcl[i], true);
if (ret)
return ret;
}
ctrl = readl(ioaddr + MTL_EST_CONTROL);
ctrl &= ~PTOV;
ctrl |= ((1000000000 / ptp_rate) * 6) << PTOV_SHIFT;
if (cfg->enable)
ctrl |= EEST | SSWL;
else
ctrl &= ~EEST;
writel(ctrl, ioaddr + MTL_EST_CONTROL);
/* Configure EST interrupt */
if (cfg->enable)
ctrl = (IECGCE | IEHS | IEHF | IEBE | IECC);
else
ctrl = 0;
writel(ctrl, ioaddr + MTL_EST_INT_EN);
return 0;
}
void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
struct stmmac_extra_stats *x, u32 txqcnt)
{
u32 status, value, feqn, hbfq, hbfs, btrl;
u32 txqcnt_mask = (1 << txqcnt) - 1;
status = readl(ioaddr + MTL_EST_STATUS);
value = (CGCE | HLBS | HLBF | BTRE | SWLC);
/* Return if there is no error */
if (!(status & value))
return;
if (status & CGCE) {
/* Clear Interrupt */
writel(CGCE, ioaddr + MTL_EST_STATUS);
x->mtl_est_cgce++;
}
if (status & HLBS) {
value = readl(ioaddr + MTL_EST_SCH_ERR);
value &= txqcnt_mask;
x->mtl_est_hlbs++;
/* Clear Interrupt */
writel(value, ioaddr + MTL_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 & HLBF) {
value = readl(ioaddr + MTL_EST_FRM_SZ_ERR);
feqn = value & txqcnt_mask;
value = readl(ioaddr + MTL_EST_FRM_SZ_CAP);
hbfq = (value & SZ_CAP_HBFQ_MASK(txqcnt)) >> SZ_CAP_HBFQ_SHIFT;
hbfs = value & SZ_CAP_HBFS_MASK;
x->mtl_est_hlbf++;
/* Clear Interrupt */
writel(feqn, ioaddr + MTL_EST_FRM_SZ_ERR);
if (net_ratelimit())
netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n",
hbfq, hbfs);
}
if (status & BTRE) {
if ((status & BTRL) == BTRL_MAX)
x->mtl_est_btrlm++;
else
x->mtl_est_btre++;
btrl = (status & BTRL) >> BTRL_SHIFT;
if (net_ratelimit())
netdev_info(dev, "EST: BTR Error Loop Count %u\n",
btrl);
writel(BTRE, ioaddr + MTL_EST_STATUS);
}
if (status & SWLC) {
writel(SWLC, ioaddr + MTL_EST_STATUS);
netdev_info(dev, "EST: SWOL has been switched\n");
}
}
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool enable)
{
u32 value;
if (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);
}
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_info(dev, "FPE: Respond mPacket is transmitted\n");
}
if (value & TVER) {
status |= FPE_EVENT_TVER;
netdev_info(dev, "FPE: Verify mPacket is transmitted\n");
}
if (value & RRSP) {
status |= FPE_EVENT_RRSP;
netdev_info(dev, "FPE: Respond mPacket is received\n");
}
if (value & RVER) {
status |= FPE_EVENT_RVER;
netdev_info(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);
}

View File

@ -0,0 +1,164 @@
/* 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_EST_CONTROL 0x00000c50
#define PTOV GENMASK(31, 24)
#define PTOV_SHIFT 24
#define SSWL BIT(1)
#define EEST BIT(0)
#define MTL_EST_STATUS 0x00000c58
#define BTRL GENMASK(11, 8)
#define BTRL_SHIFT 8
#define BTRL_MAX (0xF << BTRL_SHIFT)
#define SWOL BIT(7)
#define SWOL_SHIFT 7
#define CGCE BIT(4)
#define HLBS BIT(3)
#define HLBF BIT(2)
#define BTRE BIT(1)
#define SWLC BIT(0)
#define MTL_EST_SCH_ERR 0x00000c60
#define MTL_EST_FRM_SZ_ERR 0x00000c64
#define MTL_EST_FRM_SZ_CAP 0x00000c68
#define SZ_CAP_HBFS_MASK GENMASK(14, 0)
#define SZ_CAP_HBFQ_SHIFT 16
#define SZ_CAP_HBFQ_MASK(_val) ({ typeof(_val) (val) = (_val); \
((val) > 4 ? GENMASK(18, 16) : \
(val) > 2 ? GENMASK(17, 16) : \
BIT(16)); })
#define MTL_EST_INT_EN 0x00000c70
#define IECGCE CGCE
#define IEHS HLBS
#define IEHF HLBF
#define IEBE BTRE
#define IECC SWLC
#define MTL_EST_GCL_CONTROL 0x00000c80
#define BTR_LOW 0x0
#define BTR_HIGH 0x1
#define CTR_LOW 0x2
#define CTR_HIGH 0x3
#define TER 0x4
#define LLR 0x5
#define ADDR_SHIFT 8
#define GCRR BIT(2)
#define SRWO BIT(0)
#define MTL_EST_GCL_DATA 0x00000c84
#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);
int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
unsigned int ptp_rate);
void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
struct stmmac_extra_stats *x, u32 txqcnt);
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool 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);
#endif /* __DWMAC5_H__ */

View File

@ -0,0 +1,777 @@
// 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;
}
static int dwmac5_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl)
{
u32 ctrl;
writel(val, ioaddr + MTL_EST_GCL_DATA);
ctrl = (reg << ADDR_SHIFT);
ctrl |= gcl ? 0 : GCRR;
writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
ctrl |= SRWO;
writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
return readl_poll_timeout(ioaddr + MTL_EST_GCL_CONTROL,
ctrl, !(ctrl & SRWO), 100, 5000);
}
int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
unsigned int ptp_rate)
{
int i, ret = 0x0;
u32 ctrl;
ret |= dwmac5_est_write(ioaddr, BTR_LOW, cfg->btr[0], false);
ret |= dwmac5_est_write(ioaddr, BTR_HIGH, cfg->btr[1], false);
ret |= dwmac5_est_write(ioaddr, TER, cfg->ter, false);
ret |= dwmac5_est_write(ioaddr, LLR, cfg->gcl_size, false);
ret |= dwmac5_est_write(ioaddr, CTR_LOW, cfg->ctr[0], false);
ret |= dwmac5_est_write(ioaddr, CTR_HIGH, cfg->ctr[1], false);
if (ret)
return ret;
for (i = 0; i < cfg->gcl_size; i++) {
ret = dwmac5_est_write(ioaddr, i, cfg->gcl[i], true);
if (ret)
return ret;
}
ctrl = readl(ioaddr + MTL_EST_CONTROL);
ctrl &= ~PTOV;
ctrl |= ((1000000000 / ptp_rate) * 6) << PTOV_SHIFT;
if (cfg->enable)
ctrl |= EEST | SSWL;
else
ctrl &= ~EEST;
writel(ctrl, ioaddr + MTL_EST_CONTROL);
/* Configure EST interrupt */
if (cfg->enable)
ctrl = (IECGCE | IEHS | IEHF | IEBE | IECC);
else
ctrl = 0;
writel(ctrl, ioaddr + MTL_EST_INT_EN);
return 0;
}
void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
struct stmmac_extra_stats *x, u32 txqcnt)
{
u32 status, value, feqn, hbfq, hbfs, btrl;
u32 txqcnt_mask = (1 << txqcnt) - 1;
status = readl(ioaddr + MTL_EST_STATUS);
value = (CGCE | HLBS | HLBF | BTRE | SWLC);
/* Return if there is no error */
if (!(status & value))
return;
if (status & CGCE) {
/* Clear Interrupt */
writel(CGCE, ioaddr + MTL_EST_STATUS);
x->mtl_est_cgce++;
}
if (status & HLBS) {
value = readl(ioaddr + MTL_EST_SCH_ERR);
value &= txqcnt_mask;
x->mtl_est_hlbs++;
/* Clear Interrupt */
writel(value, ioaddr + MTL_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 & HLBF) {
value = readl(ioaddr + MTL_EST_FRM_SZ_ERR);
feqn = value & txqcnt_mask;
value = readl(ioaddr + MTL_EST_FRM_SZ_CAP);
hbfq = (value & SZ_CAP_HBFQ_MASK(txqcnt)) >> SZ_CAP_HBFQ_SHIFT;
hbfs = value & SZ_CAP_HBFS_MASK;
x->mtl_est_hlbf++;
/* Clear Interrupt */
writel(feqn, ioaddr + MTL_EST_FRM_SZ_ERR);
if (net_ratelimit())
netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n",
hbfq, hbfs);
}
if (status & BTRE) {
if ((status & BTRL) == BTRL_MAX)
x->mtl_est_btrlm++;
else
x->mtl_est_btre++;
btrl = (status & BTRL) >> BTRL_SHIFT;
if (net_ratelimit())
netdev_info(dev, "EST: BTR Error Loop Count %u\n",
btrl);
writel(BTRE, ioaddr + MTL_EST_STATUS);
}
if (status & SWLC) {
writel(SWLC, ioaddr + MTL_EST_STATUS);
netdev_info(dev, "EST: SWOL has been switched\n");
}
}
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool enable)
{
u32 value;
if (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);
}
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_info(dev, "FPE: Respond mPacket is transmitted\n");
}
if (value & TVER) {
status |= FPE_EVENT_TVER;
netdev_info(dev, "FPE: Verify mPacket is transmitted\n");
}
if (value & RRSP) {
status |= FPE_EVENT_RRSP;
netdev_info(dev, "FPE: Respond mPacket is received\n");
}
if (value & RVER) {
status |= FPE_EVENT_RVER;
netdev_info(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);
}

View File

@ -0,0 +1,164 @@
/* 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_EST_CONTROL 0x00000c50
#define PTOV GENMASK(31, 24)
#define PTOV_SHIFT 24
#define SSWL BIT(1)
#define EEST BIT(0)
#define MTL_EST_STATUS 0x00000c58
#define BTRL GENMASK(11, 8)
#define BTRL_SHIFT 8
#define BTRL_MAX (0xF << BTRL_SHIFT)
#define SWOL BIT(7)
#define SWOL_SHIFT 7
#define CGCE BIT(4)
#define HLBS BIT(3)
#define HLBF BIT(2)
#define BTRE BIT(1)
#define SWLC BIT(0)
#define MTL_EST_SCH_ERR 0x00000c60
#define MTL_EST_FRM_SZ_ERR 0x00000c64
#define MTL_EST_FRM_SZ_CAP 0x00000c68
#define SZ_CAP_HBFS_MASK GENMASK(14, 0)
#define SZ_CAP_HBFQ_SHIFT 16
#define SZ_CAP_HBFQ_MASK(_val) ({ typeof(_val) (val) = (_val); \
((val) > 4 ? GENMASK(18, 16) : \
(val) > 2 ? GENMASK(17, 16) : \
BIT(16)); })
#define MTL_EST_INT_EN 0x00000c70
#define IECGCE CGCE
#define IEHS HLBS
#define IEHF HLBF
#define IEBE BTRE
#define IECC SWLC
#define MTL_EST_GCL_CONTROL 0x00000c80
#define BTR_LOW 0x0
#define BTR_HIGH 0x1
#define CTR_LOW 0x2
#define CTR_HIGH 0x3
#define TER 0x4
#define LLR 0x5
#define ADDR_SHIFT 8
#define GCRR BIT(2)
#define SRWO BIT(0)
#define MTL_EST_GCL_DATA 0x00000c84
#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);
int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
unsigned int ptp_rate);
void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
struct stmmac_extra_stats *x, u32 txqcnt);
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool 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);
#endif /* __DWMAC5_H__ */

View File

@ -0,0 +1,166 @@
/* 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 */
/* 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);
void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan);
void dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan);
void dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan);
void dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan);
int dwmac_dma_interrupt(void __iomem *ioaddr, struct stmmac_extra_stats *x,
u32 chan, u32 dir);
int dwmac_dma_reset(void __iomem *ioaddr);
#endif /* __DWMAC_DMA_H__ */

View File

@ -0,0 +1,166 @@
/* 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 */
/* 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);
void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan);
void dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan);
void dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan);
void dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan);
int dwmac_dma_interrupt(void __iomem *ioaddr, struct stmmac_extra_stats *x,
u32 chan, u32 dir);
int dwmac_dma_reset(void __iomem *ioaddr);
#endif /* __DWMAC_DMA_H__ */

View File

@ -0,0 +1,290 @@
// 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.1-ethercat.h"
#include "dwmac_dma-6.1-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)
{
writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
}
void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
u32 value = readl(ioaddr + DMA_INTR_ENA);
if (rx)
value |= DMA_INTR_DEFAULT_RX;
if (tx)
value |= DMA_INTR_DEFAULT_TX;
writel(value, ioaddr + DMA_INTR_ENA);
}
void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
u32 value = readl(ioaddr + DMA_INTR_ENA);
if (rx)
value &= ~DMA_INTR_DEFAULT_RX;
if (tx)
value &= ~DMA_INTR_DEFAULT_TX;
writel(value, ioaddr + DMA_INTR_ENA);
}
void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CONTROL);
value |= DMA_CONTROL_ST;
writel(value, ioaddr + DMA_CONTROL);
}
void dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CONTROL);
value &= ~DMA_CONTROL_ST;
writel(value, ioaddr + DMA_CONTROL);
}
void dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CONTROL);
value |= DMA_CONTROL_SR;
writel(value, ioaddr + DMA_CONTROL);
}
void dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CONTROL);
value &= ~DMA_CONTROL_SR;
writel(value, ioaddr + DMA_CONTROL);
}
#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(void __iomem *ioaddr,
struct stmmac_extra_stats *x, u32 chan, u32 dir)
{
int ret = 0;
/* read the status register (CSR5) */
u32 intr_status = readl(ioaddr + DMA_STATUS);
#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)) {
x->normal_irq_n++;
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)) {
x->rx_normal_irq_n++;
ret |= handle_rx;
}
}
if (likely(intr_status & DMA_STATUS_TI)) {
x->tx_normal_irq_n++;
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;
}

View File

@ -0,0 +1,292 @@
// 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"
#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)
{
writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
}
void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
u32 value = readl(ioaddr + DMA_INTR_ENA);
if (rx)
value |= DMA_INTR_DEFAULT_RX;
if (tx)
value |= DMA_INTR_DEFAULT_TX;
writel(value, ioaddr + DMA_INTR_ENA);
}
void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
u32 value = readl(ioaddr + DMA_INTR_ENA);
if (rx)
value &= ~DMA_INTR_DEFAULT_RX;
if (tx)
value &= ~DMA_INTR_DEFAULT_TX;
writel(value, ioaddr + DMA_INTR_ENA);
}
void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CONTROL);
value |= DMA_CONTROL_ST;
writel(value, ioaddr + DMA_CONTROL);
}
void dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CONTROL);
value &= ~DMA_CONTROL_ST;
writel(value, ioaddr + DMA_CONTROL);
}
void dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CONTROL);
value |= DMA_CONTROL_SR;
writel(value, ioaddr + DMA_CONTROL);
}
void dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan)
{
u32 value = readl(ioaddr + DMA_CONTROL);
value &= ~DMA_CONTROL_SR;
writel(value, ioaddr + DMA_CONTROL);
}
#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(void __iomem *ioaddr,
struct stmmac_extra_stats *x, u32 chan, u32 dir)
{
int ret = 0;
/* read the status register (CSR5) */
u32 intr_status = readl(ioaddr + DMA_STATUS);
#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)) {
x->normal_irq_n++;
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)) {
x->rx_normal_irq_n++;
ret |= handle_rx;
}
}
if (likely(intr_status & DMA_STATUS_TI)) {
x->tx_normal_irq_n++;
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);

View File

@ -0,0 +1,477 @@
/* 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.1-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_RQ GENMASK(7, 4)
#define XGMAC_RQ_SHIFT 4
#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_SAVLANINS BIT(27)
#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_VLHASH BIT(4)
#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_RSSEN BIT(20)
#define XGMAC_HWFEAT_TSOEN BIT(18)
#define XGMAC_HWFEAT_SPHEN BIT(17)
#define XGMAC_HWFEAT_ADDR64 GENMASK(15, 14)
#define XGMAC_HWFEAT_TXFIFOSIZE GENMASK(10, 6)
#define XGMAC_HWFEAT_RXFIFOSIZE GENMASK(4, 0)
#define XGMAC_HW_FEATURE2 0x00000124
#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_TBSSEL BIT(27)
#define XGMAC_HWFEAT_FPESEL BIT(26)
#define XGMAC_HWFEAT_ESTWID GENMASK(24, 23)
#define XGMAC_HWFEAT_ESTDEP GENMASK(22, 20)
#define XGMAC_HWFEAT_ESTSEL BIT(19)
#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_FRPSEL BIT(3)
#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(15, 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_EST_CONTROL 0x00001050
#define XGMAC_PTOV GENMASK(31, 23)
#define XGMAC_PTOV_SHIFT 23
#define XGMAC_SSWL BIT(1)
#define XGMAC_EEST BIT(0)
#define XGMAC_MTL_EST_GCL_CONTROL 0x00001080
#define XGMAC_BTR_LOW 0x0
#define XGMAC_BTR_HIGH 0x1
#define XGMAC_CTR_LOW 0x2
#define XGMAC_CTR_HIGH 0x3
#define XGMAC_TER 0x4
#define XGMAC_LLR 0x5
#define XGMAC_ADDR_SHIFT 8
#define XGMAC_GCRR BIT(2)
#define XGMAC_SRWO BIT(0)
#define XGMAC_MTL_EST_GCL_DATA 0x00001084
#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__ */

View File

@ -0,0 +1,477 @@
/* 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_RQ GENMASK(7, 4)
#define XGMAC_RQ_SHIFT 4
#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_SAVLANINS BIT(27)
#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_VLHASH BIT(4)
#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_RSSEN BIT(20)
#define XGMAC_HWFEAT_TSOEN BIT(18)
#define XGMAC_HWFEAT_SPHEN BIT(17)
#define XGMAC_HWFEAT_ADDR64 GENMASK(15, 14)
#define XGMAC_HWFEAT_TXFIFOSIZE GENMASK(10, 6)
#define XGMAC_HWFEAT_RXFIFOSIZE GENMASK(4, 0)
#define XGMAC_HW_FEATURE2 0x00000124
#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_TBSSEL BIT(27)
#define XGMAC_HWFEAT_FPESEL BIT(26)
#define XGMAC_HWFEAT_ESTWID GENMASK(24, 23)
#define XGMAC_HWFEAT_ESTDEP GENMASK(22, 20)
#define XGMAC_HWFEAT_ESTSEL BIT(19)
#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_FRPSEL BIT(3)
#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(15, 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_EST_CONTROL 0x00001050
#define XGMAC_PTOV GENMASK(31, 23)
#define XGMAC_PTOV_SHIFT 23
#define XGMAC_SSWL BIT(1)
#define XGMAC_EEST BIT(0)
#define XGMAC_MTL_EST_GCL_CONTROL 0x00001080
#define XGMAC_BTR_LOW 0x0
#define XGMAC_BTR_HIGH 0x1
#define XGMAC_CTR_LOW 0x2
#define XGMAC_CTR_HIGH 0x3
#define XGMAC_TER 0x4
#define XGMAC_LLR 0x5
#define XGMAC_ADDR_SHIFT 8
#define XGMAC_GCRR BIT(2)
#define XGMAC_SRWO BIT(0)
#define XGMAC_MTL_EST_GCL_DATA 0x00001084
#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

View File

@ -0,0 +1,373 @@
// 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.1-ethercat.h"
#include "dwxgmac2-6.1-ethercat.h"
static int dwxgmac2_get_tx_status(void *data, 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(void *data, 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)
{
p->des3 |= cpu_to_le32(XGMAC_RDES3_OWN);
if (!disable_rx_ic)
p->des3 |= cpu_to_le32(XGMAC_RDES3_IOC);
}
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,
};

View File

@ -0,0 +1,373 @@
// 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(void *data, 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(void *data, 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)
{
p->des3 |= cpu_to_le32(XGMAC_RDES3_OWN);
if (!disable_rx_ic)
p->des3 |= cpu_to_le32(XGMAC_RDES3_IOC);
}
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,
};

View File

@ -0,0 +1,582 @@
// 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.1-ethercat.h"
#include "dwxgmac2-6.1-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, int atds)
{
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(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(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(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(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(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(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(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(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(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(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(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(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(void __iomem *ioaddr,
struct stmmac_extra_stats *x, u32 chan,
u32 dir)
{
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)) {
x->normal_irq_n++;
if (likely(intr_status & XGMAC_RI)) {
x->rx_normal_irq_n++;
ret |= handle_rx;
}
if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) {
x->tx_normal_irq_n++;
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->vlins = (hw_cap & XGMAC_HWFEAT_SAVLANINS) >> 27;
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->vlhash = (hw_cap & XGMAC_HWFEAT_VLHASH) >> 4;
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;
dma_cap->hash_tb_sz = (hw_cap & XGMAC_HWFEAT_HASHTBLSZ) >> 24;
dma_cap->rssen = (hw_cap & XGMAC_HWFEAT_RSSEN) >> 20;
dma_cap->tsoen = (hw_cap & XGMAC_HWFEAT_TSOEN) >> 18;
dma_cap->sphen = (hw_cap & XGMAC_HWFEAT_SPHEN) >> 17;
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->tx_fifo_size =
128 << ((hw_cap & XGMAC_HWFEAT_TXFIFOSIZE) >> 6);
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->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->tbssel = (hw_cap & XGMAC_HWFEAT_TBSSEL) >> 27;
dma_cap->fpesel = (hw_cap & XGMAC_HWFEAT_FPESEL) >> 26;
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->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->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3;
return 0;
}
static void dwxgmac2_rx_watchdog(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(void __iomem *ioaddr, u32 len, u32 chan)
{
writel(len, ioaddr + XGMAC_DMA_CH_RxDESC_RING_LEN(chan));
}
static void dwxgmac2_set_tx_ring_len(void __iomem *ioaddr, u32 len, u32 chan)
{
writel(len, ioaddr + XGMAC_DMA_CH_TxDESC_RING_LEN(chan));
}
static void dwxgmac2_set_rx_tail_ptr(void __iomem *ioaddr, u32 ptr, u32 chan)
{
writel(ptr, ioaddr + XGMAC_DMA_CH_RxDESC_TAIL_LPTR(chan));
}
static void dwxgmac2_set_tx_tail_ptr(void __iomem *ioaddr, u32 ptr, u32 chan)
{
writel(ptr, ioaddr + XGMAC_DMA_CH_TxDESC_TAIL_LPTR(chan));
}
static void dwxgmac2_enable_tso(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(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(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(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(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,
};

View File

@ -0,0 +1,582 @@
// 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, int atds)
{
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(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(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(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(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(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(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(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(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(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(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(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(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(void __iomem *ioaddr,
struct stmmac_extra_stats *x, u32 chan,
u32 dir)
{
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)) {
x->normal_irq_n++;
if (likely(intr_status & XGMAC_RI)) {
x->rx_normal_irq_n++;
ret |= handle_rx;
}
if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) {
x->tx_normal_irq_n++;
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->vlins = (hw_cap & XGMAC_HWFEAT_SAVLANINS) >> 27;
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->vlhash = (hw_cap & XGMAC_HWFEAT_VLHASH) >> 4;
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;
dma_cap->hash_tb_sz = (hw_cap & XGMAC_HWFEAT_HASHTBLSZ) >> 24;
dma_cap->rssen = (hw_cap & XGMAC_HWFEAT_RSSEN) >> 20;
dma_cap->tsoen = (hw_cap & XGMAC_HWFEAT_TSOEN) >> 18;
dma_cap->sphen = (hw_cap & XGMAC_HWFEAT_SPHEN) >> 17;
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->tx_fifo_size =
128 << ((hw_cap & XGMAC_HWFEAT_TXFIFOSIZE) >> 6);
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->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->tbssel = (hw_cap & XGMAC_HWFEAT_TBSSEL) >> 27;
dma_cap->fpesel = (hw_cap & XGMAC_HWFEAT_FPESEL) >> 26;
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->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->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3;
return 0;
}
static void dwxgmac2_rx_watchdog(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(void __iomem *ioaddr, u32 len, u32 chan)
{
writel(len, ioaddr + XGMAC_DMA_CH_RxDESC_RING_LEN(chan));
}
static void dwxgmac2_set_tx_ring_len(void __iomem *ioaddr, u32 len, u32 chan)
{
writel(len, ioaddr + XGMAC_DMA_CH_TxDESC_RING_LEN(chan));
}
static void dwxgmac2_set_rx_tail_ptr(void __iomem *ioaddr, u32 ptr, u32 chan)
{
writel(ptr, ioaddr + XGMAC_DMA_CH_RxDESC_TAIL_LPTR(chan));
}
static void dwxgmac2_set_tx_tail_ptr(void __iomem *ioaddr, u32 ptr, u32 chan)
{
writel(ptr, ioaddr + XGMAC_DMA_CH_TxDESC_TAIL_LPTR(chan));
}
static void dwxgmac2_enable_tso(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(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(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(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(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,
};

View File

@ -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__ */

View File

@ -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__ */

View File

@ -0,0 +1,475 @@
// 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.1-ethercat.h"
#include "descs_com-6.1-ethercat.h"
static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
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++;
stats->tx_carrier_errors++;
}
if (unlikely(tdes0 & ETDES0_NO_CARRIER)) {
x->tx_carrier++;
stats->tx_carrier_errors++;
}
if (unlikely((tdes0 & ETDES0_LATE_COLLISION) ||
(tdes0 & ETDES0_EXCESSIVE_COLLISIONS)))
stats->collisions +=
(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(void *data, 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(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
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))) {
stats->rx_length_errors++;
return discard_frame;
}
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) {
x->rx_desc++;
stats->rx_length_errors++;
}
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))
stats->collisions++;
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++;
stats->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,
};

View File

@ -0,0 +1,475 @@
// 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(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
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++;
stats->tx_carrier_errors++;
}
if (unlikely(tdes0 & ETDES0_NO_CARRIER)) {
x->tx_carrier++;
stats->tx_carrier_errors++;
}
if (unlikely((tdes0 & ETDES0_LATE_COLLISION) ||
(tdes0 & ETDES0_EXCESSIVE_COLLISIONS)))
stats->collisions +=
(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(void *data, 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(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
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))) {
stats->rx_length_errors++;
return discard_frame;
}
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) {
x->rx_desc++;
stats->rx_length_errors++;
}
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))
stats->collisions++;
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++;
stats->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,
};

View File

@ -0,0 +1,342 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
* stmmac HW Interface Handling
*/
#include "common-6.1-ethercat.h"
#include "stmmac-6.1-ethercat.h"
#include "stmmac_ptp-6.1-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;
}
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;
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,
},
.desc = &dwmac4_desc_ops,
.dma = &dwmac4_dma_ops,
.mac = &dwmac4_ops,
.hwtimestamp = &stmmac_ptp,
.mode = NULL,
.tc = &dwmac510_tc_ops,
.mmc = &dwmac_mmc_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,
},
.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,
.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,
},
.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,
.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,
},
.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,
.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,
},
.desc = &dwxgmac210_desc_ops,
.dma = &dwxgmac210_dma_ops,
.mac = &dwxgmac210_ops,
.hwtimestamp = &stmmac_ptp,
.mode = NULL,
.tc = &dwmac510_tc_ops,
.mmc = &dwxgmac_mmc_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,
},
.desc = &dwxgmac210_desc_ops,
.dma = &dwxgmac210_dma_ops,
.mac = &dwxlgmac2_ops,
.hwtimestamp = &stmmac_ptp,
.mode = NULL,
.tc = &dwmac510_tc_ops,
.mmc = &dwxgmac_mmc_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);
/* 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;
priv->hw = mac;
priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
priv->mmcaddr = priv->ioaddr + entry->regs.mmc_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;
}

View File

@ -0,0 +1,642 @@
/* 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>
#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_safety_stats;
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);
/* Return the transmit status looking at the TDES1 */
int (*tx_status)(void *data, 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)(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p);
void (*rx_extended_status)(void *data, 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_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,
int atds);
void (*init_chan)(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, u32 chan);
void (*init_rx_chan)(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
dma_addr_t phy, u32 chan);
void (*init_tx_chan)(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)(void __iomem *ioaddr, u32 *reg_space);
void (*dma_rx_mode)(void __iomem *ioaddr, int mode, u32 channel,
int fifosz, u8 qmode);
void (*dma_tx_mode)(void __iomem *ioaddr, int mode, u32 channel,
int fifosz, u8 qmode);
/* To track extra statistic (if supported) */
void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
void __iomem *ioaddr);
void (*enable_dma_transmission) (void __iomem *ioaddr);
void (*enable_dma_irq)(void __iomem *ioaddr, u32 chan,
bool rx, bool tx);
void (*disable_dma_irq)(void __iomem *ioaddr, u32 chan,
bool rx, bool tx);
void (*start_tx)(void __iomem *ioaddr, u32 chan);
void (*stop_tx)(void __iomem *ioaddr, u32 chan);
void (*start_rx)(void __iomem *ioaddr, u32 chan);
void (*stop_rx)(void __iomem *ioaddr, u32 chan);
int (*dma_interrupt) (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)(void __iomem *ioaddr, u32 riwt, u32 queue);
void (*set_tx_ring_len)(void __iomem *ioaddr, u32 len, u32 chan);
void (*set_rx_ring_len)(void __iomem *ioaddr, u32 len, u32 chan);
void (*set_rx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
void (*set_tx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
void (*enable_tso)(void __iomem *ioaddr, bool en, u32 chan);
void (*qmode)(void __iomem *ioaddr, u32 channel, u8 qmode);
void (*set_bfsize)(void __iomem *ioaddr, int bfsize, u32 chan);
void (*enable_sph)(void __iomem *ioaddr, bool en, u32 chan);
int (*enable_tbs)(void __iomem *ioaddr, bool en, u32 chan);
};
#define stmmac_reset(__priv, __args...) \
stmmac_do_callback(__priv, dma, reset, __args)
#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, __args)
#define stmmac_init_rx_chan(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, init_rx_chan, __args)
#define stmmac_init_tx_chan(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, init_tx_chan, __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, __args)
#define stmmac_dma_rx_mode(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, dma_rx_mode, __args)
#define stmmac_dma_tx_mode(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, dma_tx_mode, __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, __args)
#define stmmac_disable_dma_irq(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, disable_dma_irq, __args)
#define stmmac_start_tx(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, start_tx, __args)
#define stmmac_stop_tx(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, stop_tx, __args)
#define stmmac_start_rx(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, start_rx, __args)
#define stmmac_stop_rx(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, stop_rx, __args)
#define stmmac_dma_interrupt_status(__priv, __args...) \
stmmac_do_callback(__priv, dma, dma_interrupt, __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, __args)
#define stmmac_set_tx_ring_len(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, set_tx_ring_len, __args)
#define stmmac_set_rx_ring_len(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, set_rx_ring_len, __args)
#define stmmac_set_rx_tail_ptr(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, set_rx_tail_ptr, __args)
#define stmmac_set_tx_tail_ptr(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, set_tx_tail_ptr, __args)
#define stmmac_enable_tso(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, enable_tso, __args)
#define stmmac_dma_qmode(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, qmode, __args)
#define stmmac_set_dma_bfsize(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, set_bfsize, __args)
#define stmmac_enable_sph(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, enable_sph, __args)
#define stmmac_enable_tbs(__priv, __args...) \
stmmac_do_callback(__priv, dma, enable_tbs, __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);
/* 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 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 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 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)(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_rane)(void __iomem *ioaddr, bool restart);
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,
__le16 perfect_match, bool is_double);
void (*enable_vlan)(struct mac_device_info *hw, u32 type);
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);
int (*est_configure)(void __iomem *ioaddr, struct stmmac_est *cfg,
unsigned int ptp_rate);
void (*est_irq_status)(void __iomem *ioaddr, struct net_device *dev,
struct stmmac_extra_stats *x, u32 txqcnt);
void (*fpe_configure)(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool 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);
};
#define stmmac_core_init(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, core_init, __args)
#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, __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, __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, __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, __args)
#define stmmac_pcs_ctrl_ane(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, pcs_ctrl_ane, __args)
#define stmmac_pcs_rane(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, pcs_rane, __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_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_est_configure(__priv, __args...) \
stmmac_do_callback(__priv, mac, est_configure, __args)
#define stmmac_est_irq_status(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, est_irq_status, __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)
struct stmmac_priv;
/* 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);
};
#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)
/* 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)(void *priv, struct sk_buff *skb, int csum);
int (*set_16kib_bfsize)(int mtu);
void (*init_desc3)(struct dma_desc *p);
void (*refill_desc3) (void *priv, struct dma_desc *p);
void (*clean_desc3) (void *priv, 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 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);
};
#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)
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_regs_off {
u32 ptp_off;
u32 mmc_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 dwmac510_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;
#define GMAC_VERSION 0x00000020 /* GMAC CORE Version */
#define GMAC4_VERSION 0x00000110 /* GMAC4+ CORE Version */
int stmmac_hwif_init(struct stmmac_priv *priv);
#endif /* __STMMAC_HWIF_H__ */

View File

@ -0,0 +1,342 @@
// 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"
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;
}
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;
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,
},
.desc = &dwmac4_desc_ops,
.dma = &dwmac4_dma_ops,
.mac = &dwmac4_ops,
.hwtimestamp = &stmmac_ptp,
.mode = NULL,
.tc = &dwmac510_tc_ops,
.mmc = &dwmac_mmc_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,
},
.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,
.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,
},
.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,
.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,
},
.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,
.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,
},
.desc = &dwxgmac210_desc_ops,
.dma = &dwxgmac210_dma_ops,
.mac = &dwxgmac210_ops,
.hwtimestamp = &stmmac_ptp,
.mode = NULL,
.tc = &dwmac510_tc_ops,
.mmc = &dwxgmac_mmc_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,
},
.desc = &dwxgmac210_desc_ops,
.dma = &dwxgmac210_dma_ops,
.mac = &dwxlgmac2_ops,
.hwtimestamp = &stmmac_ptp,
.mode = NULL,
.tc = &dwmac510_tc_ops,
.mmc = &dwxgmac_mmc_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);
/* 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;
priv->hw = mac;
priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
priv->mmcaddr = priv->ioaddr + entry->regs.mmc_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;
}

View File

@ -0,0 +1,642 @@
/* 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>
#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_safety_stats;
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);
/* Return the transmit status looking at the TDES1 */
int (*tx_status)(void *data, 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)(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p);
void (*rx_extended_status)(void *data, 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_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,
int atds);
void (*init_chan)(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg, u32 chan);
void (*init_rx_chan)(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
dma_addr_t phy, u32 chan);
void (*init_tx_chan)(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)(void __iomem *ioaddr, u32 *reg_space);
void (*dma_rx_mode)(void __iomem *ioaddr, int mode, u32 channel,
int fifosz, u8 qmode);
void (*dma_tx_mode)(void __iomem *ioaddr, int mode, u32 channel,
int fifosz, u8 qmode);
/* To track extra statistic (if supported) */
void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
void __iomem *ioaddr);
void (*enable_dma_transmission) (void __iomem *ioaddr);
void (*enable_dma_irq)(void __iomem *ioaddr, u32 chan,
bool rx, bool tx);
void (*disable_dma_irq)(void __iomem *ioaddr, u32 chan,
bool rx, bool tx);
void (*start_tx)(void __iomem *ioaddr, u32 chan);
void (*stop_tx)(void __iomem *ioaddr, u32 chan);
void (*start_rx)(void __iomem *ioaddr, u32 chan);
void (*stop_rx)(void __iomem *ioaddr, u32 chan);
int (*dma_interrupt) (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)(void __iomem *ioaddr, u32 riwt, u32 queue);
void (*set_tx_ring_len)(void __iomem *ioaddr, u32 len, u32 chan);
void (*set_rx_ring_len)(void __iomem *ioaddr, u32 len, u32 chan);
void (*set_rx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
void (*set_tx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
void (*enable_tso)(void __iomem *ioaddr, bool en, u32 chan);
void (*qmode)(void __iomem *ioaddr, u32 channel, u8 qmode);
void (*set_bfsize)(void __iomem *ioaddr, int bfsize, u32 chan);
void (*enable_sph)(void __iomem *ioaddr, bool en, u32 chan);
int (*enable_tbs)(void __iomem *ioaddr, bool en, u32 chan);
};
#define stmmac_reset(__priv, __args...) \
stmmac_do_callback(__priv, dma, reset, __args)
#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, __args)
#define stmmac_init_rx_chan(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, init_rx_chan, __args)
#define stmmac_init_tx_chan(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, init_tx_chan, __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, __args)
#define stmmac_dma_rx_mode(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, dma_rx_mode, __args)
#define stmmac_dma_tx_mode(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, dma_tx_mode, __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, __args)
#define stmmac_disable_dma_irq(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, disable_dma_irq, __args)
#define stmmac_start_tx(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, start_tx, __args)
#define stmmac_stop_tx(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, stop_tx, __args)
#define stmmac_start_rx(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, start_rx, __args)
#define stmmac_stop_rx(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, stop_rx, __args)
#define stmmac_dma_interrupt_status(__priv, __args...) \
stmmac_do_callback(__priv, dma, dma_interrupt, __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, __args)
#define stmmac_set_tx_ring_len(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, set_tx_ring_len, __args)
#define stmmac_set_rx_ring_len(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, set_rx_ring_len, __args)
#define stmmac_set_rx_tail_ptr(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, set_rx_tail_ptr, __args)
#define stmmac_set_tx_tail_ptr(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, set_tx_tail_ptr, __args)
#define stmmac_enable_tso(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, enable_tso, __args)
#define stmmac_dma_qmode(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, qmode, __args)
#define stmmac_set_dma_bfsize(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, set_bfsize, __args)
#define stmmac_enable_sph(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, enable_sph, __args)
#define stmmac_enable_tbs(__priv, __args...) \
stmmac_do_callback(__priv, dma, enable_tbs, __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);
/* 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 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 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 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)(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_rane)(void __iomem *ioaddr, bool restart);
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,
__le16 perfect_match, bool is_double);
void (*enable_vlan)(struct mac_device_info *hw, u32 type);
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);
int (*est_configure)(void __iomem *ioaddr, struct stmmac_est *cfg,
unsigned int ptp_rate);
void (*est_irq_status)(void __iomem *ioaddr, struct net_device *dev,
struct stmmac_extra_stats *x, u32 txqcnt);
void (*fpe_configure)(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool 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);
};
#define stmmac_core_init(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, core_init, __args)
#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, __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, __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, __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, __args)
#define stmmac_pcs_ctrl_ane(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, pcs_ctrl_ane, __args)
#define stmmac_pcs_rane(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, pcs_rane, __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_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_est_configure(__priv, __args...) \
stmmac_do_callback(__priv, mac, est_configure, __args)
#define stmmac_est_irq_status(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, est_irq_status, __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)
struct stmmac_priv;
/* 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);
};
#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)
/* 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)(void *priv, struct sk_buff *skb, int csum);
int (*set_16kib_bfsize)(int mtu);
void (*init_desc3)(struct dma_desc *p);
void (*refill_desc3) (void *priv, struct dma_desc *p);
void (*clean_desc3) (void *priv, 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 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);
};
#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)
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_regs_off {
u32 ptp_off;
u32 mmc_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 dwmac510_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;
#define GMAC_VERSION 0x00000020 /* GMAC CORE Version */
#define GMAC4_VERSION 0x00000110 /* GMAC4+ CORE Version */
int stmmac_hwif_init(struct stmmac_priv *priv);
#endif /* __STMMAC_HWIF_H__ */

View File

@ -0,0 +1,130 @@
/* 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;
/* 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;
/* IPC */
unsigned int mmc_rx_ipc_intr_mask;
unsigned int mmc_rx_ipc_intr;
/* 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;
/* FPE */
unsigned int mmc_tx_fpe_fragment_cntr;
unsigned int mmc_tx_hold_req_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__ */

View File

@ -0,0 +1,130 @@
/* 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;
/* 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;
/* IPC */
unsigned int mmc_rx_ipc_intr_mask;
unsigned int mmc_rx_ipc_intr;
/* 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;
/* FPE */
unsigned int mmc_tx_fpe_fragment_cntr;
unsigned int mmc_tx_hold_req_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__ */

View File

@ -0,0 +1,479 @@
// 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.1-ethercat.h"
#include "mmc-6.1-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
/* 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
/* 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_TX_FPE_INTR_MASK 0x204
#define MMC_XGMAC_TX_FPE_FRAG 0x208
#define MMC_XGMAC_TX_HOLD_REQ 0x20c
#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
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 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);
/* IPC */
mmc->mmc_rx_ipc_intr_mask += readl(mmcaddr + MMC_RX_IPC_INTR_MASK);
mmc->mmc_rx_ipc_intr += readl(mmcaddr + MMC_RX_IPC_INTR);
/* 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 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_tx_fpe_fragment_cntr += readl(mmcaddr + MMC_XGMAC_TX_FPE_FRAG);
mmc->mmc_tx_hold_req_cntr += readl(mmcaddr + MMC_XGMAC_TX_HOLD_REQ);
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);
}
const struct stmmac_mmc_ops dwxgmac_mmc_ops = {
.ctrl = dwxgmac_mmc_ctrl,
.intr_all_mask = dwxgmac_mmc_intr_all_mask,
.read = dwxgmac_mmc_read,
};

View File

@ -0,0 +1,479 @@
// 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
/* 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
/* 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_TX_FPE_INTR_MASK 0x204
#define MMC_XGMAC_TX_FPE_FRAG 0x208
#define MMC_XGMAC_TX_HOLD_REQ 0x20c
#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
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 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);
/* IPC */
mmc->mmc_rx_ipc_intr_mask += readl(mmcaddr + MMC_RX_IPC_INTR_MASK);
mmc->mmc_rx_ipc_intr += readl(mmcaddr + MMC_RX_IPC_INTR);
/* 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 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_tx_fpe_fragment_cntr += readl(mmcaddr + MMC_XGMAC_TX_FPE_FRAG);
mmc->mmc_tx_hold_req_cntr += readl(mmcaddr + MMC_XGMAC_TX_HOLD_REQ);
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);
}
const struct stmmac_mmc_ops dwxgmac_mmc_ops = {
.ctrl = dwxgmac_mmc_ctrl,
.intr_all_mask = dwxgmac_mmc_intr_all_mask,
.read = dwxgmac_mmc_read,
};

View File

@ -0,0 +1,326 @@
// 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.1-ethercat.h"
#include "descs_com-6.1-ethercat.h"
static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
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++;
stats->tx_fifo_errors++;
}
if (unlikely(tdes0 & TDES0_NO_CARRIER)) {
x->tx_carrier++;
stats->tx_carrier_errors++;
}
if (unlikely(tdes0 & TDES0_LOSS_CARRIER)) {
x->tx_losscarrier++;
stats->tx_carrier_errors++;
}
if (unlikely((tdes0 & TDES0_EXCESSIVE_DEFERRAL) ||
(tdes0 & TDES0_EXCESSIVE_COLLISIONS) ||
(tdes0 & TDES0_LATE_COLLISION))) {
unsigned int collisions;
collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3;
stats->collisions += 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(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p)
{
int ret = good_frame;
unsigned int rdes0 = le32_to_cpu(p->des0);
struct net_device_stats *stats = (struct net_device_stats *)data;
if (unlikely(rdes0 & RDES0_OWN))
return dma_own;
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
stats->rx_length_errors++;
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++;
stats->collisions++;
}
if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
x->rx_crc_errors++;
stats->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,
};

View File

@ -0,0 +1,326 @@
// 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(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr)
{
struct net_device_stats *stats = (struct net_device_stats *)data;
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++;
stats->tx_fifo_errors++;
}
if (unlikely(tdes0 & TDES0_NO_CARRIER)) {
x->tx_carrier++;
stats->tx_carrier_errors++;
}
if (unlikely(tdes0 & TDES0_LOSS_CARRIER)) {
x->tx_losscarrier++;
stats->tx_carrier_errors++;
}
if (unlikely((tdes0 & TDES0_EXCESSIVE_DEFERRAL) ||
(tdes0 & TDES0_EXCESSIVE_COLLISIONS) ||
(tdes0 & TDES0_LATE_COLLISION))) {
unsigned int collisions;
collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3;
stats->collisions += 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(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p)
{
int ret = good_frame;
unsigned int rdes0 = le32_to_cpu(p->des0);
struct net_device_stats *stats = (struct net_device_stats *)data;
if (unlikely(rdes0 & RDES0_OWN))
return dma_own;
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
stats->rx_length_errors++;
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++;
stats->collisions++;
}
if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
x->rx_crc_errors++;
stats->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,
};

View File

@ -0,0 +1,148 @@
// 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.1-ethercat.h"
static int jumbo_frm(void *p, struct sk_buff *skb, int csum)
{
struct stmmac_tx_queue *tx_q = (struct stmmac_tx_queue *)p;
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(void *priv_ptr, struct dma_desc *p)
{
struct stmmac_rx_queue *rx_q = priv_ptr;
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(void *priv_ptr, struct dma_desc *p)
{
struct stmmac_tx_queue *tx_q = (struct stmmac_tx_queue *)priv_ptr;
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,
};

View File

@ -0,0 +1,148 @@
// 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(void *p, struct sk_buff *skb, int csum)
{
struct stmmac_tx_queue *tx_q = (struct stmmac_tx_queue *)p;
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(void *priv_ptr, struct dma_desc *p)
{
struct stmmac_rx_queue *rx_q = priv_ptr;
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(void *priv_ptr, struct dma_desc *p)
{
struct stmmac_tx_queue *tx_q = (struct stmmac_tx_queue *)priv_ptr;
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,
};

View File

@ -0,0 +1,416 @@
/* 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.1-ethercat.h"
#include <linux/ptp_clock_kernel.h>
#include <linux/net_tstamp.h>
#include <linux/reset.h>
#include <net/page_pool.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_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;
};
#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_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;
};
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;
};
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;
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;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
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_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;
/* Workqueue for handling FPE hand-shaking */
unsigned long fpe_task_state;
struct workqueue_struct *fpe_wq;
struct work_struct fpe_task;
char wq_name[IFNAMSIZ + 4];
/* 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;
};
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_xpcs_setup(struct mii_bus *mii);
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);
int 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_handshake(struct stmmac_priv *priv, bool enable);
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__ */

View File

@ -0,0 +1,404 @@
/* 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.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_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;
};
#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_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;
};
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;
};
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;
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;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
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_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;
/* Workqueue for handling FPE hand-shaking */
unsigned long fpe_task_state;
struct workqueue_struct *fpe_wq;
struct work_struct fpe_task;
char wq_name[IFNAMSIZ + 4];
/* 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_xpcs_setup(struct mii_bus *mii);
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);
int 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_handshake(struct stmmac_priv *priv, bool enable);
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__ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,224 @@
// 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.1-ethercat.h"
#include "stmmac_ptp-6.1-ethercat.h"
#include "dwmac4-6.1-ethercat.h"
#include "stmmac-6.1-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 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;
unsigned long flags;
u64 ptp_time;
int i;
if (priv->plat->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->ext_snapshot_en)
return;
num_snapshot = (ts_status & GMAC_TIMESTAMP_ATSNS_MASK) >>
GMAC_TIMESTAMP_ATSNS_SHIFT;
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 = 0;
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,
};

View File

@ -0,0 +1,224 @@
// 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 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;
unsigned long flags;
u64 ptp_time;
int i;
if (priv->plat->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->ext_snapshot_en)
return;
num_snapshot = (ts_status & GMAC_TIMESTAMP_ATSNS_MASK) >>
GMAC_TIMESTAMP_ATSNS_SHIFT;
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 = 0;
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,
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,584 @@
// 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.1-ethercat.h"
#include "stmmac-6.1-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 int stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr,
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 |= (phyreg >> MII_DEVADDR_C45_SHIFT) << MII_XGMAC_DA_SHIFT;
return 0;
}
static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr,
int phyreg, u32 *hw_addr)
{
u32 tmp;
/* HW does not support C22 addr >= 4 */
if (phyaddr > MII_XGMAC_MAX_C22ADDR)
return -ENODEV;
/* Set port as Clause 22 */
tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
tmp &= ~MII_XGMAC_C22P_MASK;
tmp |= BIT(phyaddr);
writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
*hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f);
return 0;
}
static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
{
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
u32 tmp, addr, value = MII_XGMAC_BUSY;
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;
}
if (phyreg & MII_ADDR_C45) {
phyreg &= ~MII_ADDR_C45;
ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
if (ret)
goto err_disable_clks;
} else {
ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
if (ret)
goto err_disable_clks;
value |= MII_XGMAC_SADDR;
}
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_write(struct mii_bus *bus, int phyaddr,
int phyreg, u16 phydata)
{
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
u32 addr, tmp, value = MII_XGMAC_BUSY;
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;
}
if (phyreg & MII_ADDR_C45) {
phyreg &= ~MII_ADDR_C45;
ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
if (ret)
goto err_disable_clks;
} else {
ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
if (ret)
goto err_disable_clks;
value |= MII_XGMAC_SADDR;
}
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;
}
/**
* stmmac_mdio_read
* @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(struct mii_bus *bus, int phyaddr, int phyreg)
{
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
u32 value = MII_BUSY;
int data = 0;
u32 v;
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;
if (phyreg & MII_ADDR_C45) {
value |= MII_GMAC4_C45E;
value &= ~priv->hw->mii.reg_mask;
value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) <<
priv->hw->mii.reg_shift) &
priv->hw->mii.reg_mask;
data |= (phyreg & MII_REGADDR_C45_MASK) <<
MII_GMAC4_REG_ADDR_SHIFT;
}
}
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
100, 30000)) {
data = -EBUSY;
goto err_disable_clks;
}
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)) {
data = -EBUSY;
goto err_disable_clks;
}
/* Read the data from the MII data register */
data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
err_disable_clks:
pm_runtime_put(priv->device);
return data;
}
/**
* stmmac_mdio_write
* @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(struct mii_bus *bus, int phyaddr, int phyreg,
u16 phydata)
{
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
int ret, data = phydata;
u32 value = MII_BUSY;
u32 v;
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;
if (phyreg & MII_ADDR_C45) {
value |= MII_GMAC4_C45E;
value &= ~priv->hw->mii.reg_mask;
value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) <<
priv->hw->mii.reg_shift) &
priv->hw->mii.reg_mask;
data |= (phyreg & MII_REGADDR_C45_MASK) <<
MII_GMAC4_REG_ADDR_SHIFT;
}
} else {
value |= MII_WRITE;
}
/* Wait until any existing MII operation is complete */
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
100, 30000)) {
ret = -EBUSY;
goto err_disable_clks;
}
/* 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 */
ret = readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
100, 30000);
err_disable_clks:
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_xpcs_setup(struct mii_bus *bus)
{
struct net_device *ndev = bus->priv;
struct mdio_device *mdiodev;
struct stmmac_priv *priv;
struct dw_xpcs *xpcs;
int mode, addr;
priv = netdev_priv(ndev);
mode = priv->plat->phy_interface;
/* Try to probe the XPCS by scanning all addresses. */
for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
mdiodev = mdio_device_create(bus, addr);
if (IS_ERR(mdiodev))
continue;
xpcs = xpcs_create(mdiodev, mode);
if (IS_ERR_OR_NULL(xpcs)) {
mdio_device_free(mdiodev);
continue;
}
priv->hw->xpcs = xpcs;
break;
}
if (!priv->hw->xpcs) {
dev_warn(priv->device, "No xPCS found\n");
return -ENODEV;
}
return 0;
}
/**
* 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 fwnode_handle *fwnode = of_fwnode_handle(priv->plat->phylink_node);
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;
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_gmac4)
new_bus->probe_capabilities = MDIOBUS_C22_C45;
if (priv->plat->has_xgmac) {
new_bus->read = &stmmac_xgmac2_mdio_read;
new_bus->write = &stmmac_xgmac2_mdio_write;
/* 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 {
new_bus->read = &stmmac_mdio_read;
new_bus->write = &stmmac_mdio_write;
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;
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(new_bus, 0, MII_ADDR_C45);
/* If fixed-link is set, skip PHY scanning */
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;
if (priv->hw->xpcs) {
mdio_device_free(priv->hw->xpcs->mdiodev);
xpcs_destroy(priv->hw->xpcs);
}
mdiobus_unregister(priv->mii);
priv->mii->priv = NULL;
mdiobus_free(priv->mii);
priv->mii = NULL;
return 0;
}

View File

@ -0,0 +1,584 @@
// 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 int stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr,
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 |= (phyreg >> MII_DEVADDR_C45_SHIFT) << MII_XGMAC_DA_SHIFT;
return 0;
}
static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr,
int phyreg, u32 *hw_addr)
{
u32 tmp;
/* HW does not support C22 addr >= 4 */
if (phyaddr > MII_XGMAC_MAX_C22ADDR)
return -ENODEV;
/* Set port as Clause 22 */
tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
tmp &= ~MII_XGMAC_C22P_MASK;
tmp |= BIT(phyaddr);
writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
*hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f);
return 0;
}
static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
{
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
u32 tmp, addr, value = MII_XGMAC_BUSY;
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;
}
if (phyreg & MII_ADDR_C45) {
phyreg &= ~MII_ADDR_C45;
ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
if (ret)
goto err_disable_clks;
} else {
ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
if (ret)
goto err_disable_clks;
value |= MII_XGMAC_SADDR;
}
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_write(struct mii_bus *bus, int phyaddr,
int phyreg, u16 phydata)
{
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
u32 addr, tmp, value = MII_XGMAC_BUSY;
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;
}
if (phyreg & MII_ADDR_C45) {
phyreg &= ~MII_ADDR_C45;
ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
if (ret)
goto err_disable_clks;
} else {
ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
if (ret)
goto err_disable_clks;
value |= MII_XGMAC_SADDR;
}
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;
}
/**
* stmmac_mdio_read
* @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(struct mii_bus *bus, int phyaddr, int phyreg)
{
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
u32 value = MII_BUSY;
int data = 0;
u32 v;
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;
if (phyreg & MII_ADDR_C45) {
value |= MII_GMAC4_C45E;
value &= ~priv->hw->mii.reg_mask;
value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) <<
priv->hw->mii.reg_shift) &
priv->hw->mii.reg_mask;
data |= (phyreg & MII_REGADDR_C45_MASK) <<
MII_GMAC4_REG_ADDR_SHIFT;
}
}
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
100, 10000)) {
data = -EBUSY;
goto err_disable_clks;
}
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)) {
data = -EBUSY;
goto err_disable_clks;
}
/* Read the data from the MII data register */
data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
err_disable_clks:
pm_runtime_put(priv->device);
return data;
}
/**
* stmmac_mdio_write
* @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(struct mii_bus *bus, int phyaddr, int phyreg,
u16 phydata)
{
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
int ret, data = phydata;
u32 value = MII_BUSY;
u32 v;
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;
if (phyreg & MII_ADDR_C45) {
value |= MII_GMAC4_C45E;
value &= ~priv->hw->mii.reg_mask;
value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) <<
priv->hw->mii.reg_shift) &
priv->hw->mii.reg_mask;
data |= (phyreg & MII_REGADDR_C45_MASK) <<
MII_GMAC4_REG_ADDR_SHIFT;
}
} else {
value |= MII_WRITE;
}
/* Wait until any existing MII operation is complete */
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
100, 10000)) {
ret = -EBUSY;
goto err_disable_clks;
}
/* 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 */
ret = readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
100, 10000);
err_disable_clks:
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_xpcs_setup(struct mii_bus *bus)
{
struct net_device *ndev = bus->priv;
struct mdio_device *mdiodev;
struct stmmac_priv *priv;
struct dw_xpcs *xpcs;
int mode, addr;
priv = netdev_priv(ndev);
mode = priv->plat->phy_interface;
/* Try to probe the XPCS by scanning all addresses. */
for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
mdiodev = mdio_device_create(bus, addr);
if (IS_ERR(mdiodev))
continue;
xpcs = xpcs_create(mdiodev, mode);
if (IS_ERR_OR_NULL(xpcs)) {
mdio_device_free(mdiodev);
continue;
}
priv->hw->xpcs = xpcs;
break;
}
if (!priv->hw->xpcs) {
dev_warn(priv->device, "No xPCS found\n");
return -ENODEV;
}
return 0;
}
/**
* 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 fwnode_handle *fwnode = of_fwnode_handle(priv->plat->phylink_node);
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;
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_gmac4)
new_bus->probe_capabilities = MDIOBUS_C22_C45;
if (priv->plat->has_xgmac) {
new_bus->read = &stmmac_xgmac2_mdio_read;
new_bus->write = &stmmac_xgmac2_mdio_write;
/* 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 {
new_bus->read = &stmmac_mdio_read;
new_bus->write = &stmmac_mdio_write;
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;
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(new_bus, 0, MII_ADDR_C45);
/* If fixed-link is set, skip PHY scanning */
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;
if (priv->hw->xpcs) {
mdio_device_free(priv->hw->xpcs->mdiodev);
xpcs_destroy(priv->hw->xpcs);
}
mdiobus_unregister(priv->mii);
priv->mii->priv = NULL;
mdiobus_free(priv->mii);
priv->mii = NULL;
return 0;
}

View File

@ -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.1-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->tso_en = 1;
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");

View File

@ -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->tso_en = 1;
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");

View File

@ -0,0 +1,155 @@
/* 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.1-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_rane - To restart ANE
* @ioaddr: IO registers pointer
* @reg: Base address of the AN Control Register.
* @restart: to restart ANE
* Description: this is to just restart the Auto-Negotiation.
*/
static inline void dwmac_rane(void __iomem *ioaddr, u32 reg, bool restart)
{
u32 value = readl(ioaddr + GMAC_AN_CTRL(reg));
if (restart)
value |= GMAC_AN_CTRL_RAN;
writel(value, ioaddr + GMAC_AN_CTRL(reg));
}
/**
* 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;
/* 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__ */

View File

@ -0,0 +1,155 @@
/* 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_rane - To restart ANE
* @ioaddr: IO registers pointer
* @reg: Base address of the AN Control Register.
* @restart: to restart ANE
* Description: this is to just restart the Auto-Negotiation.
*/
static inline void dwmac_rane(void __iomem *ioaddr, u32 reg, bool restart)
{
u32 value = readl(ioaddr + GMAC_AN_CTRL(reg));
if (restart)
value |= GMAC_AN_CTRL_RAN;
writel(value, ioaddr + GMAC_AN_CTRL(reg));
}
/**
* 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;
/* 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__ */

View File

@ -0,0 +1,339 @@
// 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.1-ethercat.h"
#include "stmmac_ptp-6.1-ethercat.h"
#include "dwmac4-6.1-ethercat.h"
/**
* stmmac_adjust_freq
*
* @ptp: pointer to ptp_clock_info structure
* @ppb: desired period change in parts ber billion
*
* Description: this function will adjust the frequency of hardware clock.
*/
static int stmmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
{
struct stmmac_priv *priv =
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
unsigned long flags;
u32 diff, addend;
int neg_adj = 0;
u64 adj;
if (ppb < 0) {
neg_adj = 1;
ppb = -ppb;
}
addend = priv->default_addend;
adj = addend;
adj *= ppb;
diff = div_u64(adj, 1000000000ULL);
addend = neg_adj ? (addend - diff) : (addend + diff);
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->plat->est && priv->plat->est->enable) {
est_rst = true;
mutex_lock(&priv->plat->est->lock);
priv->plat->est->enable = false;
stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->plat->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);
/* Caculate 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->plat->est->lock);
priv->ptp_clock_ops.gettime64(&priv->ptp_clock_ops, &current_time);
current_time_ns = timespec64_to_ktime(current_time);
time.tv_nsec = priv->plat->est->btr_reserve[0];
time.tv_sec = priv->plat->est->btr_reserve[1];
basetime = timespec64_to_ktime(time);
cycle_time = (u64)priv->plat->est->ctr[1] * NSEC_PER_SEC +
priv->plat->est->ctr[0];
time = stmmac_calc_tas_basetime(basetime,
current_time_ns,
cycle_time);
priv->plat->est->btr[0] = (u32)time.tv_nsec;
priv->plat->est->btr[1] = (u32)time.tv_sec;
priv->plat->est->enable = true;
ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->plat->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:
priv->plat->ext_snapshot_en = on;
mutex_lock(&priv->aux_ts_lock);
acr_value = readl(ptpaddr + PTP_ACR);
acr_value &= ~PTP_ACR_MASK;
if (on) {
/* Enable External snapshot trigger */
acr_value |= priv->plat->ext_snapshot_num;
acr_value |= PTP_ACR_ATSFC;
netdev_dbg(priv->dev, "Auxiliary Snapshot %d enabled.\n",
priv->plat->ext_snapshot_num >>
PTP_ACR_ATSEN_SHIFT);
} else {
netdev_dbg(priv->dev, "Auxiliary Snapshot %d disabled.\n",
priv->plat->ext_snapshot_num >>
PTP_ACR_ATSEN_SHIFT);
}
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,
.adjfreq = 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);
}

View File

@ -0,0 +1,91 @@
/* 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_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_SHIFT 5 /* Auxiliary Snapshot shift */
#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__ */

View File

@ -0,0 +1,339 @@
// 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
* @ppb: desired period change in parts ber billion
*
* Description: this function will adjust the frequency of hardware clock.
*/
static int stmmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
{
struct stmmac_priv *priv =
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
unsigned long flags;
u32 diff, addend;
int neg_adj = 0;
u64 adj;
if (ppb < 0) {
neg_adj = 1;
ppb = -ppb;
}
addend = priv->default_addend;
adj = addend;
adj *= ppb;
diff = div_u64(adj, 1000000000ULL);
addend = neg_adj ? (addend - diff) : (addend + diff);
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->plat->est && priv->plat->est->enable) {
est_rst = true;
mutex_lock(&priv->plat->est->lock);
priv->plat->est->enable = false;
stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->plat->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);
/* Caculate 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->plat->est->lock);
priv->ptp_clock_ops.gettime64(&priv->ptp_clock_ops, &current_time);
current_time_ns = timespec64_to_ktime(current_time);
time.tv_nsec = priv->plat->est->btr_reserve[0];
time.tv_sec = priv->plat->est->btr_reserve[1];
basetime = timespec64_to_ktime(time);
cycle_time = (u64)priv->plat->est->ctr[1] * NSEC_PER_SEC +
priv->plat->est->ctr[0];
time = stmmac_calc_tas_basetime(basetime,
current_time_ns,
cycle_time);
priv->plat->est->btr[0] = (u32)time.tv_nsec;
priv->plat->est->btr[1] = (u32)time.tv_sec;
priv->plat->est->enable = true;
ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->plat->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:
priv->plat->ext_snapshot_en = on;
mutex_lock(&priv->aux_ts_lock);
acr_value = readl(ptpaddr + PTP_ACR);
acr_value &= ~PTP_ACR_MASK;
if (on) {
/* Enable External snapshot trigger */
acr_value |= priv->plat->ext_snapshot_num;
acr_value |= PTP_ACR_ATSFC;
netdev_dbg(priv->dev, "Auxiliary Snapshot %d enabled.\n",
priv->plat->ext_snapshot_num >>
PTP_ACR_ATSEN_SHIFT);
} else {
netdev_dbg(priv->dev, "Auxiliary Snapshot %d disabled.\n",
priv->plat->ext_snapshot_num >>
PTP_ACR_ATSEN_SHIFT);
}
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,
.adjfreq = 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);
}

View File

@ -0,0 +1,91 @@
/* 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_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_SHIFT 5 /* Auxiliary Snapshot shift */
#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

View File

@ -0,0 +1,135 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2021, Intel Corporation. */
#include <net/xdp_sock_drv.h>
#include "stmmac-6.1-ethercat.h"
#include "stmmac_xdp-6.1-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;
}
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);
return 0;
}

View File

@ -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_ */

View File

@ -0,0 +1,135 @@
// 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;
}
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);
return 0;
}

View File

@ -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_ */

Some files were not shown because too many files have changed in this diff Show More