From 2734fdef5cea87281f6dcc621fa78b4f0b89ad30 Mon Sep 17 00:00:00 2001 From: Weijie Gao Date: Wed, 25 Sep 2019 17:45:32 +0800 Subject: net: mt7628-eth: remove hardcoded gpio settings and regmap-based phy reset This patch removes hardcoded gpio settings as they have been replaced by pinctrl in dts, and also replaces regmap-based phy reset with a more generic reset controller. Reviewed-by: Stefan Roese Signed-off-by: Weijie Gao --- drivers/net/mt7628-eth.c | 45 ++++++++------------------------------------- 1 file changed, 8 insertions(+), 37 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mt7628-eth.c b/drivers/net/mt7628-eth.c index 7833b2f47a..4675b0f003 100644 --- a/drivers/net/mt7628-eth.c +++ b/drivers/net/mt7628-eth.c @@ -18,23 +18,12 @@ #include #include #include -#include -#include +#include #include #include #include #include -/* System controller register */ -#define MT7628_RSTCTRL_REG 0x34 -#define RSTCTRL_EPHY_RST BIT(24) - -#define MT7628_AGPIO_CFG_REG 0x3c -#define MT7628_EPHY_GPIO_AIO_EN GENMASK(20, 17) -#define MT7628_EPHY_P0_DIS BIT(16) - -#define MT7628_GPIO2_MODE_REG 0x64 - /* Ethernet frame engine register */ #define PDMA_RELATED 0x0800 @@ -137,7 +126,6 @@ struct fe_tx_dma { struct mt7628_eth_dev { void __iomem *base; /* frame engine base address */ void __iomem *eth_sw_base; /* switch base address */ - struct regmap *sysctrl_regmap; /* system-controller reg-map */ struct mii_dev *bus; @@ -150,6 +138,8 @@ struct mt7628_eth_dev { int rx_dma_idx; /* Point to the next TXD in TXD Ring0 CPU wants to use */ int tx_dma_idx; + + struct reset_ctl rst_ephy; }; static int mdio_wait_read(struct mt7628_eth_dev *priv, u32 mask, bool mask_set) @@ -301,20 +291,9 @@ static void rt305x_esw_init(struct mt7628_eth_dev *priv) /* 1us cycle number=125 (FE's clock=125Mhz) */ writel(0x7d000000, base + MT7628_SWITCH_BMU_CTRL); - /* Configure analog GPIO setup */ - regmap_update_bits(priv->sysctrl_regmap, MT7628_AGPIO_CFG_REG, - MT7628_EPHY_P0_DIS, MT7628_EPHY_GPIO_AIO_EN); - /* Reset PHY */ - regmap_update_bits(priv->sysctrl_regmap, MT7628_RSTCTRL_REG, - 0, RSTCTRL_EPHY_RST); - regmap_update_bits(priv->sysctrl_regmap, MT7628_RSTCTRL_REG, - RSTCTRL_EPHY_RST, 0); - mdelay(10); - - /* Set P0 EPHY LED mode */ - regmap_update_bits(priv->sysctrl_regmap, MT7628_GPIO2_MODE_REG, - 0x0ffc0ffc, 0x05540554); + reset_assert(&priv->rst_ephy); + reset_deassert(&priv->rst_ephy); mdelay(10); mt7628_ephy_init(priv); @@ -558,7 +537,6 @@ static void mt7628_eth_stop(struct udevice *dev) static int mt7628_eth_probe(struct udevice *dev) { struct mt7628_eth_dev *priv = dev_get_priv(dev); - struct udevice *syscon; struct mii_dev *bus; int ret; int i; @@ -573,20 +551,13 @@ static int mt7628_eth_probe(struct udevice *dev) if (IS_ERR(priv->eth_sw_base)) return PTR_ERR(priv->eth_sw_base); - /* Get system controller regmap */ - ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, - "syscon", &syscon); + /* Reset controller */ + ret = reset_get_by_name(dev, "ephy", &priv->rst_ephy); if (ret) { - pr_err("unable to find syscon device\n"); + pr_err("unable to find reset controller for ethernet PHYs\n"); return ret; } - priv->sysctrl_regmap = syscon_get_regmap(syscon); - if (!priv->sysctrl_regmap) { - pr_err("unable to find regmap\n"); - return -ENODEV; - } - /* Put rx and tx rings into KSEG1 area (uncached) */ priv->tx_ring = (struct fe_tx_dma *) KSEG1ADDR(memalign(ARCH_DMA_MINALIGN, -- cgit v1.2.1 From f079321009841bbb7c3a357febc08441c579f3f2 Mon Sep 17 00:00:00 2001 From: Weijie Gao Date: Wed, 25 Sep 2019 17:45:33 +0800 Subject: net: mt7628-eth: make phy link up detection optional via DT The mt7628 has an embedded ethernet switch (5 phy ports + 1 cpu port). Although in IOT mode only port0 is usable, the phy0 is still connected to the switch, not the ethernet gmac directly. This patch rewrites it and makes it optional. It can be turned on by adding mediatek,poll-link-phy = explicitly into the eth node. By default the driver is switch mode with all 5 phy ports working without link detection. Signed-off-by: Weijie Gao --- drivers/net/Kconfig | 1 + drivers/net/mt7628-eth.c | 59 ++++++++++++++++++++++++------------------------ 2 files changed, 31 insertions(+), 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 2ce3092db0..eb3d7ed45f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -322,6 +322,7 @@ config MACB_ZYNQ config MT7628_ETH bool "MediaTek MT7628 Ethernet Interface" depends on SOC_MT7628 + select PHYLIB help The MediaTek MT7628 ethernet interface is used on MT7628 and MT7688 based boards. diff --git a/drivers/net/mt7628-eth.c b/drivers/net/mt7628-eth.c index 4675b0f003..abfdc75ad8 100644 --- a/drivers/net/mt7628-eth.c +++ b/drivers/net/mt7628-eth.c @@ -111,6 +111,7 @@ struct fe_tx_dma { #define NUM_RX_DESC 256 #define NUM_TX_DESC 4 +#define NUM_PHYS 5 #define PADDING_LENGTH 60 @@ -120,9 +121,6 @@ struct fe_tx_dma { #define CONFIG_DMA_STOP_TIMEOUT 100 #define CONFIG_TX_DMA_TIMEOUT 100 -#define LINK_DELAY_TIME 500 /* 500 ms */ -#define LINK_TIMEOUT 10000 /* 10 seconds */ - struct mt7628_eth_dev { void __iomem *base; /* frame engine base address */ void __iomem *eth_sw_base; /* switch base address */ @@ -140,6 +138,8 @@ struct mt7628_eth_dev { int tx_dma_idx; struct reset_ctl rst_ephy; + + struct phy_device *phy; }; static int mdio_wait_read(struct mt7628_eth_dev *priv, u32 mask, bool mask_set) @@ -437,20 +437,13 @@ static int mt7628_eth_free_pkt(struct udevice *dev, uchar *packet, int length) return 0; } -static int phy_link_up(struct mt7628_eth_dev *priv) -{ - u32 val; - - mii_mgr_read(priv, 0x00, MII_BMSR, &val); - return !!(val & BMSR_LSTATUS); -} - static int mt7628_eth_start(struct udevice *dev) { struct mt7628_eth_dev *priv = dev_get_priv(dev); void __iomem *base = priv->base; uchar packet[MTK_QDMA_PAGE_SIZE]; uchar *packetp; + int ret; int i; for (i = 0; i < NUM_RX_DESC; i++) { @@ -493,25 +486,13 @@ static int mt7628_eth_start(struct udevice *dev) wmb(); eth_dma_start(priv); - /* Check if link is not up yet */ - if (!phy_link_up(priv)) { - /* Wait for link to come up */ - - printf("Waiting for link to come up ."); - for (i = 0; i < (LINK_TIMEOUT / LINK_DELAY_TIME); i++) { - mdelay(LINK_DELAY_TIME); - if (phy_link_up(priv)) { - mdelay(100); /* Ensure all is ready */ - break; - } + if (priv->phy) { + ret = phy_startup(priv->phy); + if (ret) + return ret; - printf("."); - } - - if (phy_link_up(priv)) - printf(" done\n"); - else - printf(" timeout! Trying anyways\n"); + if (!priv->phy->link) + return -EAGAIN; } /* @@ -538,6 +519,7 @@ static int mt7628_eth_probe(struct udevice *dev) { struct mt7628_eth_dev *priv = dev_get_priv(dev); struct mii_dev *bus; + int poll_link_phy; int ret; int i; @@ -584,6 +566,25 @@ static int mt7628_eth_probe(struct udevice *dev) if (ret) return ret; + poll_link_phy = dev_read_u32_default(dev, "mediatek,poll-link-phy", -1); + if (poll_link_phy >= 0) { + if (poll_link_phy >= NUM_PHYS) { + pr_err("invalid phy %d for poll-link-phy\n", + poll_link_phy); + return ret; + } + + priv->phy = phy_connect(bus, poll_link_phy, dev, + PHY_INTERFACE_MODE_MII); + if (!priv->phy) { + pr_err("failed to probe phy %d\n", poll_link_phy); + return -ENODEV; + } + + priv->phy->advertising = priv->phy->supported; + phy_config(priv->phy); + } + /* Switch configuration */ rt305x_esw_init(priv); -- cgit v1.2.1 From c88ee3ea0a77c0547ce5297e4c2e7378a5cb29ae Mon Sep 17 00:00:00 2001 From: Weijie Gao Date: Wed, 25 Sep 2019 17:45:34 +0800 Subject: net: mt7628-eth: free rx descriptor on receiving failure When received a packet with an invalid length recorded in rx descriptor, we should free this rx descriptor to allow us to continue to receive following packets. Without doing so, u-boot will stuck in a dead loop trying to process this invalid rx descriptor. This patch adds a call to mt7628_eth_free_pkt() after received an invalid packet length. Reviewed-by: Stefan Roese Signed-off-by: Weijie Gao --- drivers/net/mt7628-eth.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/mt7628-eth.c b/drivers/net/mt7628-eth.c index abfdc75ad8..d77da26d50 100644 --- a/drivers/net/mt7628-eth.c +++ b/drivers/net/mt7628-eth.c @@ -142,6 +142,8 @@ struct mt7628_eth_dev { struct phy_device *phy; }; +static int mt7628_eth_free_pkt(struct udevice *dev, uchar *packet, int length); + static int mdio_wait_read(struct mt7628_eth_dev *priv, u32 mask, bool mask_set) { void __iomem *base = priv->eth_sw_base; @@ -403,6 +405,7 @@ static int mt7628_eth_recv(struct udevice *dev, int flags, uchar **packetp) length = FIELD_GET(RX_DMA_PLEN0, priv->rx_ring[idx].rxd2); if (length == 0 || length > MTK_QDMA_PAGE_SIZE) { printf("%s: invalid length (%d bytes)\n", __func__, length); + mt7628_eth_free_pkt(dev, NULL, 0); return -EIO; } -- cgit v1.2.1 From 877d03903c3683010e9d4307003c90e27917c313 Mon Sep 17 00:00:00 2001 From: Weijie Gao Date: Wed, 25 Sep 2019 17:45:35 +0800 Subject: net: mt7628-eth: add support to isolate LAN/WAN ports This patch add support for mt7628-eth to isolate LAN/WAN ports mainly to prevent LAN devices from getting IP address from WAN. Signed-off-by: Weijie Gao --- drivers/net/mt7628-eth.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/mt7628-eth.c b/drivers/net/mt7628-eth.c index d77da26d50..a1d12f6902 100644 --- a/drivers/net/mt7628-eth.c +++ b/drivers/net/mt7628-eth.c @@ -57,6 +57,11 @@ /* Ethernet switch register */ #define MT7628_SWITCH_FCT0 0x0008 #define MT7628_SWITCH_PFC1 0x0014 +#define MT7628_SWITCH_PVIDC0 0x0040 +#define MT7628_SWITCH_PVIDC1 0x0044 +#define MT7628_SWITCH_PVIDC2 0x0048 +#define MT7628_SWITCH_PVIDC3 0x004c +#define MT7628_SWITCH_VMSC0 0x0070 #define MT7628_SWITCH_FPA 0x0084 #define MT7628_SWITCH_SOCPC 0x008c #define MT7628_SWITCH_POC0 0x0090 @@ -140,6 +145,8 @@ struct mt7628_eth_dev { struct reset_ctl rst_ephy; struct phy_device *phy; + + int wan_port; }; static int mt7628_eth_free_pkt(struct udevice *dev, uchar *packet, int length); @@ -272,6 +279,9 @@ static void mt7628_ephy_init(struct mt7628_eth_dev *priv) static void rt305x_esw_init(struct mt7628_eth_dev *priv) { void __iomem *base = priv->eth_sw_base; + void __iomem *reg; + u32 val = 0, pvid; + int i; /* * FC_RLS_TH=200, FC_SET_TH=160 @@ -293,6 +303,25 @@ static void rt305x_esw_init(struct mt7628_eth_dev *priv) /* 1us cycle number=125 (FE's clock=125Mhz) */ writel(0x7d000000, base + MT7628_SWITCH_BMU_CTRL); + /* LAN/WAN partition, WAN port will be unusable in u-boot network */ + if (priv->wan_port >= 0 && priv->wan_port < 6) { + for (i = 0; i < 8; i++) { + pvid = i == priv->wan_port ? 2 : 1; + reg = base + MT7628_SWITCH_PVIDC0 + (i / 2) * 4; + if (i % 2 == 0) { + val = pvid; + } else { + val |= (pvid << 12); + writel(val, reg); + } + } + + val = 0xffff407f; + val |= 1 << (8 + priv->wan_port); + val &= ~(1 << priv->wan_port); + writel(val, base + MT7628_SWITCH_VMSC0); + } + /* Reset PHY */ reset_assert(&priv->rst_ephy); reset_deassert(&priv->rst_ephy); @@ -543,6 +572,9 @@ static int mt7628_eth_probe(struct udevice *dev) return ret; } + /* WAN port will be isolated from LAN ports */ + priv->wan_port = dev_read_u32_default(dev, "mediatek,wan-port", -1); + /* Put rx and tx rings into KSEG1 area (uncached) */ priv->tx_ring = (struct fe_tx_dma *) KSEG1ADDR(memalign(ARCH_DMA_MINALIGN, -- cgit v1.2.1