summaryrefslogtreecommitdiffstats
path: root/drivers/net/designware_eqos.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/designware_eqos.c')
-rw-r--r--drivers/net/designware_eqos.c196
1 files changed, 125 insertions, 71 deletions
diff --git a/drivers/net/designware_eqos.c b/drivers/net/designware_eqos.c
index f83e5d6d9b..ccce51b6af 100644
--- a/drivers/net/designware_eqos.c
+++ b/drivers/net/designware_eqos.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016, NVIDIA CORPORATION.
* Copyright (c) 2019, Ahmad Fatoum, Pengutronix
@@ -9,7 +9,7 @@
#include <common.h>
#include <init.h>
#include <gpio.h>
-#include <gpiod.h>
+#include <linux/gpio/consumer.h>
#include <dma.h>
#include <net.h>
#include <of_net.h>
@@ -26,7 +26,8 @@
struct eqos_mac_regs {
u32 config; /* 0x000 */
u32 ext_config; /* 0x004 */
- u32 unused_004[(0x070 - 0x008) / 4]; /* 0x008 */
+ u32 packet_filter; /* 0x008 */
+ u32 unused_004[(0x070 - 0x00C) / 4]; /* 0x00C */
u32 q0_tx_flow_ctrl; /* 0x070 */
u32 unused_070[(0x090 - 0x074) / 4]; /* 0x074 */
u32 rx_flow_ctrl; /* 0x090 */
@@ -62,6 +63,9 @@ struct eqos_mac_regs {
#define EQOS_MAC_CONFIGURATION_TE BIT(1)
#define EQOS_MAC_CONFIGURATION_RE BIT(0)
+#define EQOS_MAC_PACKET_FILTER_PR BIT(0) /* Promiscuous mode */
+#define EQOS_MAC_PACKET_FILTER_PCF BIT(7) /* Pass Control Frames */
+
#define EQOS_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT 16
#define EQOS_MAC_Q0_TX_FLOW_CTRL_PT_MASK 0xffff
#define EQOS_MAC_Q0_TX_FLOW_CTRL_TFE BIT(1)
@@ -112,6 +116,8 @@ struct eqos_mtl_regs {
#define EQOS_MTL_RXQ0_OPERATION_MODE_RFA_MASK 0x3f
#define EQOS_MTL_RXQ0_OPERATION_MODE_EHFC BIT(7)
#define EQOS_MTL_RXQ0_OPERATION_MODE_RSF BIT(5)
+#define EQOS_MTL_RXQ0_OPERATION_MODE_FEP BIT(4)
+#define EQOS_MTL_RXQ0_OPERATION_MODE_FUP BIT(3)
#define EQOS_MTL_RXQ0_DEBUG_PRXQ_SHIFT 16
#define EQOS_MTL_RXQ0_DEBUG_PRXQ_MASK 0x7fff
@@ -166,8 +172,6 @@ struct eqos_dma_regs {
#define EQOS_DESCRIPTOR_SIZE (EQOS_DESCRIPTOR_WORDS * 4)
/* We assume ARCH_DMA_MINALIGN >= 16; 16 is the EQOS HW minimum */
#define EQOS_DESCRIPTOR_ALIGN 64
-#define EQOS_DESCRIPTORS_TX 4
-#define EQOS_DESCRIPTORS_RX 4
#define EQOS_DESCRIPTORS_NUM (EQOS_DESCRIPTORS_TX + EQOS_DESCRIPTORS_RX)
#define EQOS_DESCRIPTORS_SIZE ALIGN(EQOS_DESCRIPTORS_NUM * \
EQOS_DESCRIPTOR_SIZE, EQOS_DESCRIPTOR_ALIGN)
@@ -192,23 +196,23 @@ struct eqos_desc {
#define MII_BUSY (1 << 0)
-static int eqos_phy_reset(struct device_d *dev, struct eqos *eqos)
+static int eqos_phy_reset(struct device *dev, struct eqos *eqos)
{
- int phy_reset;
+ struct gpio_desc *phy_reset;
u32 delays[3] = { 0, 0, 0 };
- phy_reset = gpiod_get(dev, "snps,reset", GPIOF_OUT_INIT_ACTIVE);
-
- if (!gpio_is_valid(phy_reset))
- return 0;
-
- of_property_read_u32_array(dev->device_node,
- "snps,reset-delays-us",
- delays, ARRAY_SIZE(delays));
-
- udelay(delays[1]);
- gpio_set_active(phy_reset, false);
- udelay(delays[2]);
+ phy_reset = gpiod_get_optional(dev, "snps,reset", GPIOF_OUT_INIT_ACTIVE);
+ if (IS_ERR(phy_reset)) {
+ dev_warn(dev, "Failed to get 'snps,reset' GPIO (ignored)\n");
+ } else if (phy_reset) {
+ of_property_read_u32_array(dev->of_node,
+ "snps,reset-delays-us",
+ delays, ARRAY_SIZE(delays));
+
+ udelay(delays[1]);
+ gpiod_set_value(phy_reset, false);
+ udelay(delays[2]);
+ }
return 0;
}
@@ -345,6 +349,14 @@ int eqos_set_ethaddr(struct eth_device *edev, const unsigned char *mac)
memcpy(eqos->macaddr, mac, ETH_ALEN);
+ if (!eqos->is_started)
+ return 0;
+
+ /* mac_hi is only partially overwritten by the following code. Part of
+ * this variable is DCS (DMA Channel Select). If this variable is not
+ * zeroed, we may get some random DMA RX channel.
+ */
+ mac_hi = 0;
/* Update the MAC address */
memcpy(&mac_hi, &mac[4], 2);
memcpy(&mac_lo, &mac[0], 4);
@@ -355,6 +367,26 @@ int eqos_set_ethaddr(struct eth_device *edev, const unsigned char *mac)
return 0;
}
+static int eqos_set_promisc(struct eth_device *edev, bool enable)
+{
+ struct eqos *eqos = edev->priv;
+ u32 mask;
+
+ eqos->promisc_enabled = enable;
+
+ if (!eqos->is_started)
+ return 0;
+
+ mask = EQOS_MAC_PACKET_FILTER_PR;
+
+ if (enable)
+ setbits_le32(&eqos->mac_regs->packet_filter, mask);
+ else
+ clrbits_le32(&eqos->mac_regs->packet_filter, mask);
+
+ return 0;
+}
+
/* Get PHY out of power saving mode. If this is needed elsewhere then
* consider making it part of phy-core and adding a resume method to
* the phy device ops. */
@@ -382,7 +414,7 @@ static int eqos_start(struct eth_device *edev)
{
struct eqos *eqos = edev->priv;
u32 val, tx_fifo_sz, rx_fifo_sz, tqs, rqs, pbl;
- unsigned long last_rx_desc;
+ unsigned long last_rx_rf_desc;
unsigned long rate;
u32 mode_set;
int ret;
@@ -393,6 +425,10 @@ static int eqos_start(struct eth_device *edev)
if (ret)
return ret;
+ /* In some cases where PHY or DSA switch is the clock provider for
+ * EQOS, we need to probe and configure them before issuing software
+ * reset here.
+ */
setbits_le32(&eqos->dma_regs->mode, EQOS_DMA_MODE_SWR);
ret = readl_poll_timeout(&eqos->dma_regs->mode, mode_set,
@@ -403,8 +439,10 @@ static int eqos_start(struct eth_device *edev)
return ret;
}
- /* Reset above clears MAC address */
+ /* Reset above clears any previously made configuration */
+ eqos->is_started = true;
eqos_set_ethaddr(edev, eqos->macaddr);
+ eqos_set_promisc(edev, eqos->promisc_enabled);
/* Required for accurate time keeping with EEE counters */
rate = eqos->ops->get_csr_clk_rate(eqos);
@@ -415,9 +453,11 @@ static int eqos_start(struct eth_device *edev)
/* Before we reset the mac, we must insure the PHY is not powered down
* as the dw controller needs all clock domains to be running, including
* the PHY clock, to come out of a mac reset. */
- ret = phy_resume(edev->phydev);
- if (ret)
- return ret;
+ if (edev->phydev) {
+ ret = phy_resume(edev->phydev);
+ if (ret)
+ return ret;
+ }
/* Configure MTL */
@@ -433,7 +473,9 @@ static int eqos_start(struct eth_device *edev)
/* Enable Store and Forward mode for RX, since no jumbo frame */
setbits_le32(&eqos->mtl_regs->rxq0_operation_mode,
- EQOS_MTL_RXQ0_OPERATION_MODE_RSF);
+ EQOS_MTL_RXQ0_OPERATION_MODE_RSF |
+ EQOS_MTL_RXQ0_OPERATION_MODE_FEP |
+ EQOS_MTL_RXQ0_OPERATION_MODE_FUP);
/* Transmit/Receive queue fifo size; use all RAM for 1 queue */
val = readl(&eqos->mac_regs->hw_feature1);
@@ -582,9 +624,9 @@ static int eqos_start(struct eth_device *edev)
eqos->tx_currdescnum = eqos->rx_currdescnum = 0;
for (i = 0; i < EQOS_DESCRIPTORS_RX; i++) {
- struct eqos_desc *rx_desc = &eqos->rx_descs[i];
+ struct eqos_desc *rx_rf_desc = &eqos->rx_descs[i];
- writel(EQOS_DESC3_BUF1V | EQOS_DESC3_OWN, &rx_desc->des3);
+ writel(EQOS_DESC3_BUF1V | EQOS_DESC3_OWN, &rx_rf_desc->des3);
}
writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress);
@@ -614,12 +656,8 @@ static int eqos_start(struct eth_device *edev)
* that's not distinguishable from none of the descriptors being
* available.
*/
- last_rx_desc = (ulong)&eqos->rx_descs[(EQOS_DESCRIPTORS_RX - 1)];
- writel(last_rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer);
-
- barrier();
-
- eqos->started = true;
+ last_rx_rf_desc = (ulong)&eqos->rx_descs[(EQOS_DESCRIPTORS_RX - 1)];
+ writel(last_rx_rf_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer);
return 0;
}
@@ -629,13 +667,6 @@ static void eqos_stop(struct eth_device *edev)
struct eqos *eqos = edev->priv;
int i;
- if (!eqos->started)
- return;
-
- eqos->started = false;
-
- barrier();
-
/* Disable TX DMA */
clrbits_le32(&eqos->dma_regs->ch0_tx_control,
EQOS_DMA_CH0_TX_CONTROL_ST);
@@ -673,7 +704,6 @@ static void eqos_stop(struct eth_device *edev)
static int eqos_send(struct eth_device *edev, void *packet, int length)
{
struct eqos *eqos = edev->priv;
- struct device_d *dev = &eqos->netdev.dev;
struct eqos_desc *tx_desc;
dma_addr_t dma;
u32 des3;
@@ -683,8 +713,8 @@ static int eqos_send(struct eth_device *edev, void *packet, int length)
eqos->tx_currdescnum++;
eqos->tx_currdescnum %= EQOS_DESCRIPTORS_TX;
- dma = dma_map_single(dev, packet, length, DMA_TO_DEVICE);
- if (dma_mapping_error(dev, dma))
+ dma = dma_map_single(edev->parent, packet, length, DMA_TO_DEVICE);
+ if (dma_mapping_error(edev->parent, dma))
return -EFAULT;
tx_desc->des0 = (unsigned long)dma;
@@ -703,7 +733,7 @@ static int eqos_send(struct eth_device *edev, void *packet, int length)
!(des3 & EQOS_DESC3_OWN),
100 * USEC_PER_MSEC);
- dma_unmap_single(dev, dma, length, DMA_TO_DEVICE);
+ dma_unmap_single(edev->parent, dma, length, DMA_TO_DEVICE);
if (ret == -ETIMEDOUT)
eqos_dbg(eqos, "TX timeout\n");
@@ -714,33 +744,51 @@ static int eqos_send(struct eth_device *edev, void *packet, int length)
static int eqos_recv(struct eth_device *edev)
{
struct eqos *eqos = edev->priv;
- struct eqos_desc *rx_desc;
+ struct eqos_desc *rx_wbf_desc, *rx_rf_desc;
+ dma_addr_t dma;
void *frame;
int length;
- rx_desc = &eqos->rx_descs[eqos->rx_currdescnum];
- if (readl(&rx_desc->des3) & EQOS_DESC3_OWN)
+ /* We have two types of RX descriptors at some pointer: Read and
+ * Write-Back:
+ * All RX descriptors are prepared by the software and given to the
+ * DMA as "Normal" Descriptors with the content as shown in Receive
+ * Normal Descriptor (Read Format). The DMA reads this descriptor and
+ * after transferring a received packet (or part of) to the buffers
+ * indicated by the descriptor, the Rx DMA will close the descriptor
+ * with the corresponding packet status. The format of this status is
+ * given in the "Receive Normal Descriptor (Write-Back Format)"
+ */
+
+ /* Write-Back Format RX descriptor */
+ rx_wbf_desc = &eqos->rx_descs[eqos->rx_currdescnum];
+ if (readl(&rx_wbf_desc->des3) & EQOS_DESC3_OWN)
return 0;
- frame = phys_to_virt(rx_desc->des0);
- length = rx_desc->des3 & 0x7fff;
+ dma = eqos->dma_rx_buf[eqos->rx_currdescnum];
+ frame = phys_to_virt(dma);
+ length = rx_wbf_desc->des3 & 0x7fff;
- dma_sync_single_for_cpu((unsigned long)frame, length, DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(edev->parent, (unsigned long)frame,
+ length, DMA_FROM_DEVICE);
net_receive(edev, frame, length);
- dma_sync_single_for_device((unsigned long)frame, length, DMA_FROM_DEVICE);
-
- rx_desc->des0 = (unsigned long)frame;
- rx_desc->des1 = 0;
- rx_desc->des2 = 0;
+ dma_sync_single_for_device(edev->parent, (unsigned long)frame,
+ length, DMA_FROM_DEVICE);
+
+ /* Read Format RX descriptor */
+ rx_rf_desc = &eqos->rx_descs[eqos->rx_currdescnum];
+ rx_rf_desc->des0 = dma;
+ rx_rf_desc->des1 = 0;
+ rx_rf_desc->des2 = 0;
/*
* Make sure that if HW sees the _OWN write below, it will see all the
* writes to the rest of the descriptor too.
*/
- rx_desc->des3 |= EQOS_DESC3_BUF1V;
- rx_desc->des3 |= EQOS_DESC3_OWN;
+ rx_rf_desc->des3 |= EQOS_DESC3_BUF1V;
+ rx_rf_desc->des3 |= EQOS_DESC3_OWN;
barrier();
- writel((ulong)rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer);
+ writel((ulong)rx_rf_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer);
eqos->rx_currdescnum++;
eqos->rx_currdescnum %= EQOS_DESCRIPTORS_RX;
@@ -750,7 +798,7 @@ static int eqos_recv(struct eth_device *edev)
static int eqos_init_resources(struct eqos *eqos)
{
- struct device_d *dev = eqos->netdev.parent;
+ struct eth_device *edev = &eqos->netdev;
int ret = -ENOMEM;
void *descs;
void *p;
@@ -768,16 +816,17 @@ static int eqos_init_resources(struct eqos *eqos)
goto err_free_desc;
for (i = 0; i < EQOS_DESCRIPTORS_RX; i++) {
- struct eqos_desc *rx_desc = &eqos->rx_descs[i];
+ struct eqos_desc *rx_rf_desc = &eqos->rx_descs[i];
dma_addr_t dma;
- dma = dma_map_single(dev, p, EQOS_MAX_PACKET_SIZE, DMA_FROM_DEVICE);
- if (dma_mapping_error(dev, dma)) {
+ dma = dma_map_single(edev->parent, p, EQOS_MAX_PACKET_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(edev->parent, dma)) {
ret = -EFAULT;
goto err_free_rx_bufs;
}
- rx_desc->des0 = dma;
+ rx_rf_desc->des0 = dma;
+ eqos->dma_rx_buf[i] = dma;
p += EQOS_MAX_PACKET_SIZE;
}
@@ -793,7 +842,7 @@ err:
return ret;
}
-static int eqos_init(struct device_d *dev, struct eqos *eqos)
+static int eqos_init(struct device *dev, struct eqos *eqos)
{
int ret;
@@ -809,25 +858,26 @@ static int eqos_init(struct device_d *dev, struct eqos *eqos)
return ret;
}
-static void eqos_probe_dt(struct device_d *dev, struct eqos *eqos)
+static void eqos_probe_dt(struct device *dev, struct eqos *eqos)
{
struct device_node *child;
- eqos->interface = of_get_phy_mode(dev->device_node);
+ eqos->interface = of_get_phy_mode(dev->of_node);
eqos->phy_addr = -1;
/* Set MDIO bus device node, if present. */
- for_each_child_of_node(dev->device_node, child) {
+ for_each_child_of_node(dev->of_node, child) {
if (of_device_is_compatible(child, "snps,dwmac-mdio") ||
(child->name && !of_node_cmp(child->name, "mdio"))) {
- eqos->miibus.dev.device_node = child;
+ eqos->miibus.dev.of_node = child;
break;
}
}
}
-int eqos_probe(struct device_d *dev, const struct eqos_ops *ops, void *priv)
+int eqos_probe(struct device *dev, const struct eqos_ops *ops, void *priv)
{
+ struct device_node *np = dev->of_node;
struct mii_bus *miibus;
struct resource *iores;
struct eqos *eqos;
@@ -860,13 +910,17 @@ int eqos_probe(struct device_d *dev, const struct eqos_ops *ops, void *priv)
edev->halt = eqos_stop;
edev->get_ethaddr = ops->get_ethaddr;
edev->set_ethaddr = ops->set_ethaddr;
+ edev->set_promisc = eqos_set_promisc;
miibus = &eqos->miibus;
miibus->parent = edev->parent;
miibus->read = eqos_mdio_read;
miibus->write = eqos_mdio_write;
miibus->priv = eqos;
- miibus->dev.device_node = of_get_child_by_name(dev->device_node, "mdio");
+
+ miibus->dev.of_node = of_get_compatible_child(np, "snps,dwmac-mdio");
+ if (!miibus->dev.of_node)
+ miibus->dev.of_node = of_get_child_by_name(np, "mdio");
ret = eqos_init(dev, eqos);
if (ret)
@@ -883,7 +937,7 @@ int eqos_probe(struct device_d *dev, const struct eqos_ops *ops, void *priv)
return eth_register(edev);
}
-void eqos_remove(struct device_d *dev)
+void eqos_remove(struct device *dev)
{
struct eqos *eqos = dev->priv;