Commit b8fc9f30 authored by René van Dorst's avatar René van Dorst Committed by David S. Miller

net: ethernet: mediatek: Add basic PHYLINK support

This convert the basics to PHYLINK API.
SGMII support is not in this patch.
Signed-off-by: default avatarRené van Dorst <opensource@vdorst.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cb6ec975
...@@ -9,7 +9,7 @@ if NET_VENDOR_MEDIATEK ...@@ -9,7 +9,7 @@ if NET_VENDOR_MEDIATEK
config NET_MEDIATEK_SOC config NET_MEDIATEK_SOC
tristate "MediaTek SoC Gigabit Ethernet support" tristate "MediaTek SoC Gigabit Ethernet support"
select PHYLIB select PHYLINK
---help--- ---help---
This driver supports the gigabit ethernet MACs in the This driver supports the gigabit ethernet MACs in the
MediaTek SoC family. MediaTek SoC family.
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/tcp.h> #include <linux/tcp.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/pinctrl/devinfo.h> #include <linux/pinctrl/devinfo.h>
#include <linux/phylink.h>
#include "mtk_eth_soc.h" #include "mtk_eth_soc.h"
...@@ -186,168 +187,224 @@ static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth, int speed) ...@@ -186,168 +187,224 @@ static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth, int speed)
mtk_w32(eth, val, TRGMII_TCK_CTRL); mtk_w32(eth, val, TRGMII_TCK_CTRL);
} }
static void mtk_phy_link_adjust(struct net_device *dev) static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state)
{ {
struct mtk_mac *mac = netdev_priv(dev); struct mtk_mac *mac = container_of(config, struct mtk_mac,
u16 lcl_adv = 0, rmt_adv = 0; phylink_config);
u8 flowctrl; struct mtk_eth *eth = mac->hw;
u32 mcr = MAC_MCR_MAX_RX_1536 | MAC_MCR_IPG_CFG | u32 mcr_cur, mcr_new;
MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN | int val, ge_mode = 0;
MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN |
MAC_MCR_BACKPR_EN; /* MT76x8 has no hardware settings between for the MAC */
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) &&
if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) mac->interface != state->interface) {
return; /* Setup soc pin functions */
switch (state->interface) {
switch (dev->phydev->speed) { case PHY_INTERFACE_MODE_TRGMII:
case SPEED_1000: if (mac->id)
mcr |= MAC_MCR_SPEED_1000; goto err_phy;
if (!MTK_HAS_CAPS(mac->hw->soc->caps,
MTK_GMAC1_TRGMII))
goto err_phy;
/* fall through */
case PHY_INTERFACE_MODE_GMII:
case PHY_INTERFACE_MODE_RGMII_TXID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII:
break; break;
case SPEED_100: case PHY_INTERFACE_MODE_MII:
mcr |= MAC_MCR_SPEED_100; ge_mode = 1;
break; break;
case PHY_INTERFACE_MODE_REVMII:
ge_mode = 2;
break;
case PHY_INTERFACE_MODE_RMII:
if (mac->id)
goto err_phy;
ge_mode = 3;
break;
default:
goto err_phy;
} }
if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII) && !mac->id) { /* Setup clock for 1st gmac */
if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII_MT7621_CLK)) { if (!mac->id &&
MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII)) {
if (MTK_HAS_CAPS(mac->hw->soc->caps,
MTK_TRGMII_MT7621_CLK)) {
if (mt7621_gmac0_rgmii_adjust(mac->hw, if (mt7621_gmac0_rgmii_adjust(mac->hw,
dev->phydev->interface)) state->interface))
return; goto err_phy;
} else { } else {
if (!mac->trgmii) if (state->interface !=
PHY_INTERFACE_MODE_TRGMII)
mtk_gmac0_rgmii_adjust(mac->hw, mtk_gmac0_rgmii_adjust(mac->hw,
dev->phydev->speed); state->speed);
} }
} }
if (dev->phydev->link) /* put the gmac into the right mode */
mcr |= MAC_MCR_FORCE_LINK; regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, mac->id);
if (dev->phydev->duplex) { val |= SYSCFG0_GE_MODE(ge_mode, mac->id);
mcr |= MAC_MCR_FORCE_DPX; regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val);
if (dev->phydev->pause)
rmt_adv = LPA_PAUSE_CAP;
if (dev->phydev->asym_pause)
rmt_adv |= LPA_PAUSE_ASYM;
lcl_adv = linkmode_adv_to_lcl_adv_t(dev->phydev->advertising); mac->interface = state->interface;
flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); }
if (flowctrl & FLOW_CTRL_TX) /* Setup gmac */
mcr |= MAC_MCR_FORCE_TX_FC; mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
if (flowctrl & FLOW_CTRL_RX) mcr_new = mcr_cur;
mcr |= MAC_MCR_FORCE_RX_FC; mcr_new &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 |
MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC |
MAC_MCR_FORCE_RX_FC);
mcr_new |= MAC_MCR_MAX_RX_1536 | MAC_MCR_IPG_CFG | MAC_MCR_FORCE_MODE |
MAC_MCR_BACKOFF_EN | MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_LINK;
netif_dbg(mac->hw, link, dev, "rx pause %s, tx pause %s\n", switch (state->speed) {
flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled", case SPEED_1000:
flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled"); mcr_new |= MAC_MCR_SPEED_1000;
break;
case SPEED_100:
mcr_new |= MAC_MCR_SPEED_100;
break;
}
if (state->duplex == DUPLEX_FULL) {
mcr_new |= MAC_MCR_FORCE_DPX;
if (state->pause & MLO_PAUSE_TX)
mcr_new |= MAC_MCR_FORCE_TX_FC;
if (state->pause & MLO_PAUSE_RX)
mcr_new |= MAC_MCR_FORCE_RX_FC;
} }
mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); /* Only update control register when needed! */
if (mcr_new != mcr_cur)
mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id));
if (!of_phy_is_fixed_link(mac->of_node)) return;
phy_print_status(dev->phydev);
err_phy:
dev_err(eth->dev, "%s: GMAC%d mode %s not supported!\n", __func__,
mac->id, phy_modes(state->interface));
} }
static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac, static int mtk_mac_link_state(struct phylink_config *config,
struct device_node *phy_node) struct phylink_link_state *state)
{ {
struct phy_device *phydev; struct mtk_mac *mac = container_of(config, struct mtk_mac,
int phy_mode; phylink_config);
u32 pmsr = mtk_r32(mac->hw, MTK_MAC_MSR(mac->id));
phy_mode = of_get_phy_mode(phy_node); state->link = (pmsr & MAC_MSR_LINK);
if (phy_mode < 0) { state->duplex = (pmsr & MAC_MSR_DPX) >> 1;
dev_err(eth->dev, "incorrect phy-mode %d\n", phy_mode);
return -EINVAL;
}
phydev = of_phy_connect(eth->netdev[mac->id], phy_node, switch (pmsr & (MAC_MSR_SPEED_1000 | MAC_MSR_SPEED_100)) {
mtk_phy_link_adjust, 0, phy_mode); case 0:
if (!phydev) { state->speed = SPEED_10;
dev_err(eth->dev, "could not connect to PHY\n"); break;
return -ENODEV; case MAC_MSR_SPEED_100:
state->speed = SPEED_100;
break;
case MAC_MSR_SPEED_1000:
state->speed = SPEED_1000;
break;
default:
state->speed = SPEED_UNKNOWN;
break;
} }
dev_info(eth->dev, state->pause &= (MLO_PAUSE_RX | MLO_PAUSE_TX);
"connected mac %d to PHY at %s [uid=%08x, driver=%s]\n", if (pmsr & MAC_MSR_RX_FC)
mac->id, phydev_name(phydev), phydev->phy_id, state->pause |= MLO_PAUSE_RX;
phydev->drv->name); if (pmsr & MAC_MSR_TX_FC)
state->pause |= MLO_PAUSE_TX;
return 0; return 1;
} }
static int mtk_phy_connect(struct net_device *dev) static void mtk_mac_an_restart(struct phylink_config *config)
{ {
struct mtk_mac *mac = netdev_priv(dev); /* Do nothing */
struct mtk_eth *eth; }
struct device_node *np;
u32 val;
int err;
eth = mac->hw; static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode,
np = of_parse_phandle(mac->of_node, "phy-handle", 0); phy_interface_t interface)
if (!np && of_phy_is_fixed_link(mac->of_node)) {
if (!of_phy_register_fixed_link(mac->of_node)) struct mtk_mac *mac = container_of(config, struct mtk_mac,
np = of_node_get(mac->of_node); phylink_config);
if (!np) u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
return -ENODEV;
err = mtk_setup_hw_path(eth, mac->id, of_get_phy_mode(np)); mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN);
if (err) mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
goto err_phy; }
mac->ge_mode = 0; static void mtk_mac_link_up(struct phylink_config *config, unsigned int mode,
switch (of_get_phy_mode(np)) { phy_interface_t interface,
case PHY_INTERFACE_MODE_TRGMII: struct phy_device *phy)
mac->trgmii = true; {
case PHY_INTERFACE_MODE_RGMII_TXID: struct mtk_mac *mac = container_of(config, struct mtk_mac,
case PHY_INTERFACE_MODE_RGMII_RXID: phylink_config);
case PHY_INTERFACE_MODE_RGMII_ID: u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_SGMII:
break;
case PHY_INTERFACE_MODE_MII:
case PHY_INTERFACE_MODE_GMII:
mac->ge_mode = 1;
break;
case PHY_INTERFACE_MODE_REVMII:
mac->ge_mode = 2;
break;
case PHY_INTERFACE_MODE_RMII:
if (!mac->id)
goto err_phy;
mac->ge_mode = 3;
break;
default:
goto err_phy;
}
/* No MT7628/88 support for now */ mcr |= MAC_MCR_TX_EN | MAC_MCR_RX_EN;
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
/* put the gmac into the right mode */ }
regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, mac->id); static void mtk_validate(struct phylink_config *config,
val |= SYSCFG0_GE_MODE(mac->ge_mode, mac->id); unsigned long *supported,
regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val); struct phylink_link_state *state)
{
struct mtk_mac *mac = container_of(config, struct mtk_mac,
phylink_config);
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
if (state->interface != PHY_INTERFACE_MODE_NA &&
state->interface != PHY_INTERFACE_MODE_MII &&
state->interface != PHY_INTERFACE_MODE_GMII &&
!(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII) &&
phy_interface_mode_is_rgmii(state->interface)) &&
!(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII) &&
!mac->id && state->interface == PHY_INTERFACE_MODE_TRGMII)) {
linkmode_zero(supported);
return;
} }
/* couple phydev to net_device */ phylink_set_port_modes(mask);
if (mtk_phy_connect_node(eth, mac, np)) phylink_set(mask, Autoneg);
goto err_phy;
of_node_put(np); if (state->interface == PHY_INTERFACE_MODE_TRGMII) {
phylink_set(mask, 1000baseT_Full);
} else {
phylink_set(mask, 10baseT_Half);
phylink_set(mask, 10baseT_Full);
phylink_set(mask, 100baseT_Half);
phylink_set(mask, 100baseT_Full);
return 0; if (state->interface != PHY_INTERFACE_MODE_MII) {
phylink_set(mask, 1000baseT_Half);
phylink_set(mask, 1000baseT_Full);
phylink_set(mask, 1000baseX_Full);
}
}
err_phy: phylink_set(mask, Pause);
if (of_phy_is_fixed_link(mac->of_node)) phylink_set(mask, Asym_Pause);
of_phy_deregister_fixed_link(mac->of_node);
of_node_put(np); linkmode_and(supported, supported, mask);
dev_err(eth->dev, "%s: invalid phy\n", __func__); linkmode_and(state->advertising, state->advertising, mask);
return -EINVAL;
} }
static const struct phylink_mac_ops mtk_phylink_ops = {
.validate = mtk_validate,
.mac_link_state = mtk_mac_link_state,
.mac_an_restart = mtk_mac_an_restart,
.mac_config = mtk_mac_config,
.mac_link_down = mtk_mac_link_down,
.mac_link_up = mtk_mac_link_up,
};
static int mtk_mdio_init(struct mtk_eth *eth) static int mtk_mdio_init(struct mtk_eth *eth)
{ {
struct device_node *mii_np; struct device_node *mii_np;
...@@ -2013,6 +2070,14 @@ static int mtk_open(struct net_device *dev) ...@@ -2013,6 +2070,14 @@ static int mtk_open(struct net_device *dev)
{ {
struct mtk_mac *mac = netdev_priv(dev); struct mtk_mac *mac = netdev_priv(dev);
struct mtk_eth *eth = mac->hw; struct mtk_eth *eth = mac->hw;
int err;
err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0);
if (err) {
netdev_err(dev, "%s: could not attach PHY: %d\n", __func__,
err);
return err;
}
/* we run 2 netdevs on the same dma ring so we only bring it up once */ /* we run 2 netdevs on the same dma ring so we only bring it up once */
if (!refcount_read(&eth->dma_refcnt)) { if (!refcount_read(&eth->dma_refcnt)) {
...@@ -2030,7 +2095,7 @@ static int mtk_open(struct net_device *dev) ...@@ -2030,7 +2095,7 @@ static int mtk_open(struct net_device *dev)
else else
refcount_inc(&eth->dma_refcnt); refcount_inc(&eth->dma_refcnt);
phy_start(dev->phydev); phylink_start(mac->phylink);
netif_start_queue(dev); netif_start_queue(dev);
return 0; return 0;
} }
...@@ -2063,8 +2128,11 @@ static int mtk_stop(struct net_device *dev) ...@@ -2063,8 +2128,11 @@ static int mtk_stop(struct net_device *dev)
struct mtk_mac *mac = netdev_priv(dev); struct mtk_mac *mac = netdev_priv(dev);
struct mtk_eth *eth = mac->hw; struct mtk_eth *eth = mac->hw;
phylink_stop(mac->phylink);
netif_tx_disable(dev); netif_tx_disable(dev);
phy_stop(dev->phydev);
phylink_disconnect_phy(mac->phylink);
/* only shutdown DMA if this is the last user */ /* only shutdown DMA if this is the last user */
if (!refcount_dec_and_test(&eth->dma_refcnt)) if (!refcount_dec_and_test(&eth->dma_refcnt))
...@@ -2159,15 +2227,6 @@ static int mtk_hw_init(struct mtk_eth *eth) ...@@ -2159,15 +2227,6 @@ static int mtk_hw_init(struct mtk_eth *eth)
ethsys_reset(eth, RSTCTRL_FE); ethsys_reset(eth, RSTCTRL_FE);
ethsys_reset(eth, RSTCTRL_PPE); ethsys_reset(eth, RSTCTRL_PPE);
regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
for (i = 0; i < MTK_MAC_COUNT; i++) {
if (!eth->mac[i])
continue;
val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, eth->mac[i]->id);
val |= SYSCFG0_GE_MODE(eth->mac[i]->ge_mode, eth->mac[i]->id);
}
regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val);
if (eth->pctl) { if (eth->pctl) {
/* Set GE2 driving and slew rate */ /* Set GE2 driving and slew rate */
regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00); regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00);
...@@ -2180,11 +2239,11 @@ static int mtk_hw_init(struct mtk_eth *eth) ...@@ -2180,11 +2239,11 @@ static int mtk_hw_init(struct mtk_eth *eth)
} }
/* Set linkdown as the default for each GMAC. Its own MCR would be set /* Set linkdown as the default for each GMAC. Its own MCR would be set
* up with the more appropriate value when mtk_phy_link_adjust call is * up with the more appropriate value when mtk_mac_config call is being
* being invoked. * invoked.
*/ */
for (i = 0; i < MTK_MAC_COUNT; i++) for (i = 0; i < MTK_MAC_COUNT; i++)
mtk_w32(eth, 0, MTK_MAC_MCR(i)); mtk_w32(eth, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(i));
/* Indicates CDM to parse the MTK special tag from CPU /* Indicates CDM to parse the MTK special tag from CPU
* which also is working out for untag packets. * which also is working out for untag packets.
...@@ -2212,7 +2271,7 @@ static int mtk_hw_init(struct mtk_eth *eth) ...@@ -2212,7 +2271,7 @@ static int mtk_hw_init(struct mtk_eth *eth)
mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2); mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2);
mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
for (i = 0; i < 2; i++) { for (i = 0; i < MTK_MAC_COUNT; i++) {
u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i)); u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i));
/* setup the forward port to send frame to PDMA */ /* setup the forward port to send frame to PDMA */
...@@ -2264,7 +2323,7 @@ static int __init mtk_init(struct net_device *dev) ...@@ -2264,7 +2323,7 @@ static int __init mtk_init(struct net_device *dev)
dev->dev_addr); dev->dev_addr);
} }
return mtk_phy_connect(dev); return 0;
} }
static void mtk_uninit(struct net_device *dev) static void mtk_uninit(struct net_device *dev)
...@@ -2272,20 +2331,20 @@ static void mtk_uninit(struct net_device *dev) ...@@ -2272,20 +2331,20 @@ static void mtk_uninit(struct net_device *dev)
struct mtk_mac *mac = netdev_priv(dev); struct mtk_mac *mac = netdev_priv(dev);
struct mtk_eth *eth = mac->hw; struct mtk_eth *eth = mac->hw;
phy_disconnect(dev->phydev); phylink_disconnect_phy(mac->phylink);
if (of_phy_is_fixed_link(mac->of_node))
of_phy_deregister_fixed_link(mac->of_node);
mtk_tx_irq_disable(eth, ~0); mtk_tx_irq_disable(eth, ~0);
mtk_rx_irq_disable(eth, ~0); mtk_rx_irq_disable(eth, ~0);
} }
static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{ {
struct mtk_mac *mac = netdev_priv(dev);
switch (cmd) { switch (cmd) {
case SIOCGMIIPHY: case SIOCGMIIPHY:
case SIOCGMIIREG: case SIOCGMIIREG:
case SIOCSMIIREG: case SIOCSMIIREG:
return phy_mii_ioctl(dev->phydev, ifr, cmd); return phylink_mii_ioctl(mac->phylink, ifr, cmd);
default: default:
break; break;
} }
...@@ -2326,16 +2385,6 @@ static void mtk_pending_work(struct work_struct *work) ...@@ -2326,16 +2385,6 @@ static void mtk_pending_work(struct work_struct *work)
eth->dev->pins->default_state); eth->dev->pins->default_state);
mtk_hw_init(eth); mtk_hw_init(eth);
for (i = 0; i < MTK_MAC_COUNT; i++) {
if (!eth->mac[i] ||
of_phy_is_fixed_link(eth->mac[i]->of_node))
continue;
err = phy_init_hw(eth->netdev[i]->phydev);
if (err)
dev_err(eth->dev, "%s: PHY init failed.\n",
eth->netdev[i]->name);
}
/* restart DMA and enable IRQs */ /* restart DMA and enable IRQs */
for (i = 0; i < MTK_MAC_COUNT; i++) { for (i = 0; i < MTK_MAC_COUNT; i++) {
if (!test_bit(i, &restart)) if (!test_bit(i, &restart))
...@@ -2398,9 +2447,7 @@ static int mtk_get_link_ksettings(struct net_device *ndev, ...@@ -2398,9 +2447,7 @@ static int mtk_get_link_ksettings(struct net_device *ndev,
if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
return -EBUSY; return -EBUSY;
phy_ethtool_ksettings_get(ndev->phydev, cmd); return phylink_ethtool_ksettings_get(mac->phylink, cmd);
return 0;
} }
static int mtk_set_link_ksettings(struct net_device *ndev, static int mtk_set_link_ksettings(struct net_device *ndev,
...@@ -2411,7 +2458,7 @@ static int mtk_set_link_ksettings(struct net_device *ndev, ...@@ -2411,7 +2458,7 @@ static int mtk_set_link_ksettings(struct net_device *ndev,
if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
return -EBUSY; return -EBUSY;
return phy_ethtool_ksettings_set(ndev->phydev, cmd); return phylink_ethtool_ksettings_set(mac->phylink, cmd);
} }
static void mtk_get_drvinfo(struct net_device *dev, static void mtk_get_drvinfo(struct net_device *dev,
...@@ -2445,22 +2492,10 @@ static int mtk_nway_reset(struct net_device *dev) ...@@ -2445,22 +2492,10 @@ static int mtk_nway_reset(struct net_device *dev)
if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
return -EBUSY; return -EBUSY;
return genphy_restart_aneg(dev->phydev); if (!mac->phylink)
} return -ENOTSUPP;
static u32 mtk_get_link(struct net_device *dev)
{
struct mtk_mac *mac = netdev_priv(dev);
int err;
if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
return -EBUSY;
err = genphy_update_link(dev->phydev);
if (err)
return ethtool_op_get_link(dev);
return dev->phydev->link; return phylink_ethtool_nway_reset(mac->phylink);
} }
static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data) static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data)
...@@ -2580,7 +2615,7 @@ static const struct ethtool_ops mtk_ethtool_ops = { ...@@ -2580,7 +2615,7 @@ static const struct ethtool_ops mtk_ethtool_ops = {
.get_msglevel = mtk_get_msglevel, .get_msglevel = mtk_get_msglevel,
.set_msglevel = mtk_set_msglevel, .set_msglevel = mtk_set_msglevel,
.nway_reset = mtk_nway_reset, .nway_reset = mtk_nway_reset,
.get_link = mtk_get_link, .get_link = ethtool_op_get_link,
.get_strings = mtk_get_strings, .get_strings = mtk_get_strings,
.get_sset_count = mtk_get_sset_count, .get_sset_count = mtk_get_sset_count,
.get_ethtool_stats = mtk_get_ethtool_stats, .get_ethtool_stats = mtk_get_ethtool_stats,
...@@ -2608,9 +2643,10 @@ static const struct net_device_ops mtk_netdev_ops = { ...@@ -2608,9 +2643,10 @@ static const struct net_device_ops mtk_netdev_ops = {
static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
{ {
struct mtk_mac *mac;
const __be32 *_id = of_get_property(np, "reg", NULL); const __be32 *_id = of_get_property(np, "reg", NULL);
int id, err; struct phylink *phylink;
int phy_mode, id, err;
struct mtk_mac *mac;
if (!_id) { if (!_id) {
dev_err(eth->dev, "missing mac id\n"); dev_err(eth->dev, "missing mac id\n");
...@@ -2654,6 +2690,32 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) ...@@ -2654,6 +2690,32 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
u64_stats_init(&mac->hw_stats->syncp); u64_stats_init(&mac->hw_stats->syncp);
mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET; mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
/* phylink create */
phy_mode = of_get_phy_mode(np);
if (phy_mode < 0) {
dev_err(eth->dev, "incorrect phy-mode\n");
err = -EINVAL;
goto free_netdev;
}
/* mac config is not set */
mac->interface = PHY_INTERFACE_MODE_NA;
mac->mode = MLO_AN_PHY;
mac->speed = SPEED_UNKNOWN;
mac->phylink_config.dev = &eth->netdev[id]->dev;
mac->phylink_config.type = PHYLINK_NETDEV;
phylink = phylink_create(&mac->phylink_config,
of_fwnode_handle(mac->of_node),
phy_mode, &mtk_phylink_ops);
if (IS_ERR(phylink)) {
err = PTR_ERR(phylink);
goto free_netdev;
}
mac->phylink = phylink;
SET_NETDEV_DEV(eth->netdev[id], eth->dev); SET_NETDEV_DEV(eth->netdev[id], eth->dev);
eth->netdev[id]->watchdog_timeo = 5 * HZ; eth->netdev[id]->watchdog_timeo = 5 * HZ;
eth->netdev[id]->netdev_ops = &mtk_netdev_ops; eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
...@@ -2682,8 +2744,7 @@ static int mtk_probe(struct platform_device *pdev) ...@@ -2682,8 +2744,7 @@ static int mtk_probe(struct platform_device *pdev)
{ {
struct device_node *mac_np; struct device_node *mac_np;
struct mtk_eth *eth; struct mtk_eth *eth;
int err; int err, i;
int i;
eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL); eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL);
if (!eth) if (!eth)
...@@ -2869,6 +2930,7 @@ static int mtk_probe(struct platform_device *pdev) ...@@ -2869,6 +2930,7 @@ static int mtk_probe(struct platform_device *pdev)
static int mtk_remove(struct platform_device *pdev) static int mtk_remove(struct platform_device *pdev)
{ {
struct mtk_eth *eth = platform_get_drvdata(pdev); struct mtk_eth *eth = platform_get_drvdata(pdev);
struct mtk_mac *mac;
int i; int i;
/* stop all devices to make sure that dma is properly shut down */ /* stop all devices to make sure that dma is properly shut down */
...@@ -2876,6 +2938,8 @@ static int mtk_remove(struct platform_device *pdev) ...@@ -2876,6 +2938,8 @@ static int mtk_remove(struct platform_device *pdev)
if (!eth->netdev[i]) if (!eth->netdev[i])
continue; continue;
mtk_stop(eth->netdev[i]); mtk_stop(eth->netdev[i]);
mac = netdev_priv(eth->netdev[i]);
phylink_disconnect_phy(mac->phylink);
} }
mtk_hw_deinit(eth); mtk_hw_deinit(eth);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/of_net.h> #include <linux/of_net.h>
#include <linux/u64_stats_sync.h> #include <linux/u64_stats_sync.h>
#include <linux/refcount.h> #include <linux/refcount.h>
#include <linux/phylink.h>
#define MTK_QDMA_PAGE_SIZE 2048 #define MTK_QDMA_PAGE_SIZE 2048
#define MTK_MAX_RX_LENGTH 1536 #define MTK_MAX_RX_LENGTH 1536
...@@ -330,12 +331,19 @@ ...@@ -330,12 +331,19 @@
#define MAC_MCR_SPEED_100 BIT(2) #define MAC_MCR_SPEED_100 BIT(2)
#define MAC_MCR_FORCE_DPX BIT(1) #define MAC_MCR_FORCE_DPX BIT(1)
#define MAC_MCR_FORCE_LINK BIT(0) #define MAC_MCR_FORCE_LINK BIT(0)
#define MAC_MCR_FIXED_LINK (MAC_MCR_MAX_RX_1536 | MAC_MCR_IPG_CFG | \ #define MAC_MCR_FORCE_LINK_DOWN (MAC_MCR_FORCE_MODE)
MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN | \
MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN | \ /* Mac status registers */
MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_RX_FC | \ #define MTK_MAC_MSR(x) (0x10108 + (x * 0x100))
MAC_MCR_FORCE_TX_FC | MAC_MCR_SPEED_1000 | \ #define MAC_MSR_EEE1G BIT(7)
MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_LINK) #define MAC_MSR_EEE100M BIT(6)
#define MAC_MSR_RX_FC BIT(5)
#define MAC_MSR_TX_FC BIT(4)
#define MAC_MSR_SPEED_1000 BIT(3)
#define MAC_MSR_SPEED_100 BIT(2)
#define MAC_MSR_SPEED_MASK (MAC_MSR_SPEED_1000 | MAC_MSR_SPEED_100)
#define MAC_MSR_DPX BIT(1)
#define MAC_MSR_LINK BIT(0)
/* TRGMII RXC control register */ /* TRGMII RXC control register */
#define TRGMII_RCK_CTRL 0x10300 #define TRGMII_RCK_CTRL 0x10300
...@@ -858,22 +866,23 @@ struct mtk_eth { ...@@ -858,22 +866,23 @@ struct mtk_eth {
/* struct mtk_mac - the structure that holds the info about the MACs of the /* struct mtk_mac - the structure that holds the info about the MACs of the
* SoC * SoC
* @id: The number of the MAC * @id: The number of the MAC
* @ge_mode: Interface mode kept for setup restoring * @interface: Interface mode kept for detecting change in hw settings
* @of_node: Our devicetree node * @of_node: Our devicetree node
* @hw: Backpointer to our main datastruture * @hw: Backpointer to our main datastruture
* @hw_stats: Packet statistics counter * @hw_stats: Packet statistics counter
* @trgmii Indicate if the MAC uses TRGMII connected to internal
switch
*/ */
struct mtk_mac { struct mtk_mac {
int id; int id;
int ge_mode; phy_interface_t interface;
unsigned int mode;
int speed;
struct device_node *of_node; struct device_node *of_node;
struct phylink *phylink;
struct phylink_config phylink_config;
struct mtk_eth *hw; struct mtk_eth *hw;
struct mtk_hw_stats *hw_stats; struct mtk_hw_stats *hw_stats;
__be32 hwlro_ip[MTK_MAX_LRO_IP_CNT]; __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT];
int hwlro_ip_cnt; int hwlro_ip_cnt;
bool trgmii;
}; };
/* the struct describing the SoC. these are declared in the soc_xyz.c files */ /* the struct describing the SoC. these are declared in the soc_xyz.c files */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment