diff options
Diffstat (limited to 'drivers/net/designware_eqos.c')
-rw-r--r-- | drivers/net/designware_eqos.c | 182 |
1 files changed, 113 insertions, 69 deletions
diff --git a/drivers/net/designware_eqos.c b/drivers/net/designware_eqos.c index 6b372e4274..ccce51b6af 100644 --- a/drivers/net/designware_eqos.c +++ b/drivers/net/designware_eqos.c @@ -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) @@ -168,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) @@ -194,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; } @@ -347,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); @@ -357,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. */ @@ -384,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; @@ -395,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, @@ -405,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); @@ -588,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); @@ -620,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; } @@ -635,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); @@ -679,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; @@ -689,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; @@ -709,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"); @@ -720,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; @@ -756,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; @@ -774,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; } @@ -799,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; @@ -815,26 +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->device_node; + struct device_node *np = dev->of_node; struct mii_bus *miibus; struct resource *iores; struct eqos *eqos; @@ -867,6 +910,7 @@ 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; @@ -874,9 +918,9 @@ int eqos_probe(struct device_d *dev, const struct eqos_ops *ops, void *priv) miibus->write = eqos_mdio_write; miibus->priv = eqos; - miibus->dev.device_node = of_get_compatible_child(np, "snps,dwmac-mdio"); - if (!miibus->dev.device_node) - miibus->dev.device_node = of_get_child_by_name(np, "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) @@ -893,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; |