Merge branch 'net-ethernet-mediatek-convert-to-PHYLINK'

René van Dorst says:

====================
net: ethernet: mediatek: convert to PHYLINK

These patches converts mediatek driver to PHYLINK API.

v3->v4:
* Phylink improvements and clean-ups after review
v2->v3:
* Phylink improvements and clean-ups after review
v1->v2:
* Rebase for mt76x8 changes
* Phylink improvements and clean-ups after review
* SGMII port doesn't support 2.5Gbit in SGMII mode only in BASE-X mode.
  Refactor the code.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2019-08-27 20:19:28 -07:00
commit 1ddc5d9484
8 changed files with 499 additions and 321 deletions

View File

@ -9,8 +9,6 @@ Required Properties:
- "mediatek,mt7622-sgmiisys", "syscon" - "mediatek,mt7622-sgmiisys", "syscon"
- "mediatek,mt7629-sgmiisys", "syscon" - "mediatek,mt7629-sgmiisys", "syscon"
- #clock-cells: Must be 1 - #clock-cells: Must be 1
- mediatek,physpeed: Should be one of "auto", "1000" or "2500" to match up
the capability of the target PHY.
The SGMIISYS controller uses the common clk binding from The SGMIISYS controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt Documentation/devicetree/bindings/clock/clock-bindings.txt

View File

@ -115,24 +115,34 @@ &cir {
}; };
&eth { &eth {
pinctrl-names = "default";
pinctrl-0 = <&eth_pins>;
status = "okay"; status = "okay";
gmac0: mac@0 {
compatible = "mediatek,eth-mac";
reg = <0>;
phy-mode = "2500base-x";
fixed-link {
speed = <2500>;
full-duplex;
pause;
};
};
gmac1: mac@1 { gmac1: mac@1 {
compatible = "mediatek,eth-mac"; compatible = "mediatek,eth-mac";
reg = <1>; reg = <1>;
phy-handle = <&phy5>; phy-mode = "rgmii";
fixed-link {
speed = <1000>;
full-duplex;
pause;
};
}; };
mdio-bus { mdio: mdio-bus {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
phy5: ethernet-phy@5 {
reg = <5>;
phy-mode = "sgmii";
};
}; };
}; };

View File

@ -931,6 +931,5 @@ sgmiisys: sgmiisys@1b128000 {
"syscon"; "syscon";
reg = <0 0x1b128000 0 0x3000>; reg = <0 0x1b128000 0 0x3000>;
#clock-cells = <1>; #clock-cells = <1>;
mediatek,physpeed = "2500";
}; };
}; };

View File

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

View File

@ -239,10 +239,9 @@ static int mtk_eth_mux_setup(struct mtk_eth *eth, int path)
return err; return err;
} }
static int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id) int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
{ {
unsigned int val = 0; int err, path;
int sid, err, path;
path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII : path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII :
MTK_ETH_PATH_GMAC2_SGMII; MTK_ETH_PATH_GMAC2_SGMII;
@ -252,33 +251,10 @@ static int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
if (err) if (err)
return err; return err;
/* The path GMAC to SGMII will be enabled once the SGMIISYS is being
* setup done.
*/
regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
SYSCFG0_SGMII_MASK, ~(u32)SYSCFG0_SGMII_MASK);
/* Decide how GMAC and SGMIISYS be mapped */
sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? 0 : mac_id;
/* Setup SGMIISYS with the determined property */
if (MTK_HAS_FLAGS(eth->sgmii->flags[sid], MTK_SGMII_PHYSPEED_AN))
err = mtk_sgmii_setup_mode_an(eth->sgmii, sid);
else
err = mtk_sgmii_setup_mode_force(eth->sgmii, sid);
if (err)
return err;
regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
SYSCFG0_SGMII_MASK, val);
return 0; return 0;
} }
static int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id) int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
{ {
int err, path = 0; int err, path = 0;
@ -296,7 +272,7 @@ static int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
return 0; return 0;
} }
static int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id) int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)
{ {
int err, path; int err, path;
@ -311,46 +287,3 @@ static int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)
return 0; return 0;
} }
int mtk_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode)
{
int err;
/* No mux'ing for MT7628/88 */
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
return 0;
switch (phymode) {
case PHY_INTERFACE_MODE_TRGMII:
case PHY_INTERFACE_MODE_RGMII_TXID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_MII:
case PHY_INTERFACE_MODE_REVMII:
case PHY_INTERFACE_MODE_RMII:
if (MTK_HAS_CAPS(eth->soc->caps, MTK_RGMII)) {
err = mtk_gmac_rgmii_path_setup(eth, mac_id);
if (err)
return err;
}
break;
case PHY_INTERFACE_MODE_SGMII:
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
err = mtk_gmac_sgmii_path_setup(eth, mac_id);
if (err)
return err;
}
break;
case PHY_INTERFACE_MODE_GMII:
if (MTK_HAS_CAPS(eth->soc->caps, MTK_GEPHY)) {
err = mtk_gmac_gephy_path_setup(eth, mac_id);
if (err)
return err;
}
break;
default:
break;
}
return 0;
}

View File

@ -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,339 @@ 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, sid;
MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN | int val, ge_mode, err;
MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN |
MAC_MCR_BACKPR_EN;
if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) /* MT76x8 has no hardware settings between for the MAC */
return; if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) &&
mac->interface != state->interface) {
switch (dev->phydev->speed) { /* Setup soc pin functions */
case SPEED_1000: switch (state->interface) {
mcr |= MAC_MCR_SPEED_1000;
break;
case SPEED_100:
mcr |= MAC_MCR_SPEED_100;
break;
}
if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII) && !mac->id) {
if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII_MT7621_CLK)) {
if (mt7621_gmac0_rgmii_adjust(mac->hw,
dev->phydev->interface))
return;
} else {
if (!mac->trgmii)
mtk_gmac0_rgmii_adjust(mac->hw,
dev->phydev->speed);
}
}
if (dev->phydev->link)
mcr |= MAC_MCR_FORCE_LINK;
if (dev->phydev->duplex) {
mcr |= MAC_MCR_FORCE_DPX;
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);
flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
if (flowctrl & FLOW_CTRL_TX)
mcr |= MAC_MCR_FORCE_TX_FC;
if (flowctrl & FLOW_CTRL_RX)
mcr |= MAC_MCR_FORCE_RX_FC;
netif_dbg(mac->hw, link, dev, "rx pause %s, tx pause %s\n",
flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
}
mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
if (!of_phy_is_fixed_link(mac->of_node))
phy_print_status(dev->phydev);
}
static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac,
struct device_node *phy_node)
{
struct phy_device *phydev;
int phy_mode;
phy_mode = of_get_phy_mode(phy_node);
if (phy_mode < 0) {
dev_err(eth->dev, "incorrect phy-mode %d\n", phy_mode);
return -EINVAL;
}
phydev = of_phy_connect(eth->netdev[mac->id], phy_node,
mtk_phy_link_adjust, 0, phy_mode);
if (!phydev) {
dev_err(eth->dev, "could not connect to PHY\n");
return -ENODEV;
}
dev_info(eth->dev,
"connected mac %d to PHY at %s [uid=%08x, driver=%s]\n",
mac->id, phydev_name(phydev), phydev->phy_id,
phydev->drv->name);
return 0;
}
static int mtk_phy_connect(struct net_device *dev)
{
struct mtk_mac *mac = netdev_priv(dev);
struct mtk_eth *eth;
struct device_node *np;
u32 val;
int err;
eth = mac->hw;
np = of_parse_phandle(mac->of_node, "phy-handle", 0);
if (!np && of_phy_is_fixed_link(mac->of_node))
if (!of_phy_register_fixed_link(mac->of_node))
np = of_node_get(mac->of_node);
if (!np)
return -ENODEV;
err = mtk_setup_hw_path(eth, mac->id, of_get_phy_mode(np));
if (err)
goto err_phy;
mac->ge_mode = 0;
switch (of_get_phy_mode(np)) {
case PHY_INTERFACE_MODE_TRGMII: case PHY_INTERFACE_MODE_TRGMII:
mac->trgmii = true; if (mac->id)
goto err_phy;
if (!MTK_HAS_CAPS(mac->hw->soc->caps,
MTK_GMAC1_TRGMII))
goto err_phy;
/* fall through */
case PHY_INTERFACE_MODE_RGMII_TXID: case PHY_INTERFACE_MODE_RGMII_TXID:
case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_SGMII:
break;
case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_MII:
case PHY_INTERFACE_MODE_GMII:
mac->ge_mode = 1;
break;
case PHY_INTERFACE_MODE_REVMII: case PHY_INTERFACE_MODE_REVMII:
mac->ge_mode = 2;
break;
case PHY_INTERFACE_MODE_RMII: case PHY_INTERFACE_MODE_RMII:
if (!mac->id) if (MTK_HAS_CAPS(eth->soc->caps, MTK_RGMII)) {
goto err_phy; err = mtk_gmac_rgmii_path_setup(eth, mac->id);
mac->ge_mode = 3; if (err)
goto init_err;
}
break;
case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_2500BASEX:
case PHY_INTERFACE_MODE_SGMII:
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
err = mtk_gmac_sgmii_path_setup(eth, mac->id);
if (err)
goto init_err;
}
break;
case PHY_INTERFACE_MODE_GMII:
if (MTK_HAS_CAPS(eth->soc->caps, MTK_GEPHY)) {
err = mtk_gmac_gephy_path_setup(eth, mac->id);
if (err)
goto init_err;
}
break; break;
default: default:
goto err_phy; goto err_phy;
} }
/* No MT7628/88 support for now */ /* Setup clock for 1st gmac */
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { if (!mac->id && state->interface != PHY_INTERFACE_MODE_SGMII &&
!phy_interface_mode_is_8023z(state->interface) &&
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,
state->interface))
goto err_phy;
} else {
if (state->interface !=
PHY_INTERFACE_MODE_TRGMII)
mtk_gmac0_rgmii_adjust(mac->hw,
state->speed);
}
}
ge_mode = 0;
switch (state->interface) {
case PHY_INTERFACE_MODE_MII:
ge_mode = 1;
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:
break;
}
/* put the gmac into the right mode */ /* put the gmac into the right mode */
regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, mac->id); val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, mac->id);
val |= SYSCFG0_GE_MODE(mac->ge_mode, mac->id); val |= SYSCFG0_GE_MODE(ge_mode, mac->id);
regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val); regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val);
mac->interface = state->interface;
} }
/* couple phydev to net_device */ /* SGMII */
if (mtk_phy_connect_node(eth, mac, np)) if (state->interface == PHY_INTERFACE_MODE_SGMII ||
goto err_phy; phy_interface_mode_is_8023z(state->interface)) {
/* The path GMAC to SGMII will be enabled once the SGMIISYS is
* being setup done.
*/
regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
of_node_put(np); regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
SYSCFG0_SGMII_MASK,
~(u32)SYSCFG0_SGMII_MASK);
return 0; /* Decide how GMAC and SGMIISYS be mapped */
sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ?
0 : mac->id;
/* Setup SGMIISYS with the determined property */
if (state->interface != PHY_INTERFACE_MODE_SGMII)
err = mtk_sgmii_setup_mode_force(eth->sgmii, sid,
state);
else if (phylink_autoneg_inband(mode))
err = mtk_sgmii_setup_mode_an(eth->sgmii, sid);
if (err)
goto init_err;
regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
SYSCFG0_SGMII_MASK, val);
} else if (phylink_autoneg_inband(mode)) {
dev_err(eth->dev,
"In-band mode not supported in non SGMII mode!\n");
return;
}
/* Setup gmac */
mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
mcr_new = mcr_cur;
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;
switch (state->speed) {
case SPEED_2500:
case SPEED_1000:
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;
}
/* Only update control register when needed! */
if (mcr_new != mcr_cur)
mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id));
return;
err_phy: err_phy:
if (of_phy_is_fixed_link(mac->of_node)) dev_err(eth->dev, "%s: GMAC%d mode %s not supported!\n", __func__,
of_phy_deregister_fixed_link(mac->of_node); mac->id, phy_modes(state->interface));
of_node_put(np); return;
dev_err(eth->dev, "%s: invalid phy\n", __func__);
return -EINVAL; init_err:
dev_err(eth->dev, "%s: GMAC%d mode %s err: %d!\n", __func__,
mac->id, phy_modes(state->interface), err);
} }
static int mtk_mac_link_state(struct phylink_config *config,
struct phylink_link_state *state)
{
struct mtk_mac *mac = container_of(config, struct mtk_mac,
phylink_config);
u32 pmsr = mtk_r32(mac->hw, MTK_MAC_MSR(mac->id));
state->link = (pmsr & MAC_MSR_LINK);
state->duplex = (pmsr & MAC_MSR_DPX) >> 1;
switch (pmsr & (MAC_MSR_SPEED_1000 | MAC_MSR_SPEED_100)) {
case 0:
state->speed = SPEED_10;
break;
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;
}
state->pause &= (MLO_PAUSE_RX | MLO_PAUSE_TX);
if (pmsr & MAC_MSR_RX_FC)
state->pause |= MLO_PAUSE_RX;
if (pmsr & MAC_MSR_TX_FC)
state->pause |= MLO_PAUSE_TX;
return 1;
}
static void mtk_mac_an_restart(struct phylink_config *config)
{
struct mtk_mac *mac = container_of(config, struct mtk_mac,
phylink_config);
mtk_sgmii_restart_an(mac->hw, mac->id);
}
static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode,
phy_interface_t interface)
{
struct mtk_mac *mac = container_of(config, struct mtk_mac,
phylink_config);
u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN);
mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
}
static void mtk_mac_link_up(struct phylink_config *config, unsigned int mode,
phy_interface_t interface,
struct phy_device *phy)
{
struct mtk_mac *mac = container_of(config, struct mtk_mac,
phylink_config);
u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
mcr |= MAC_MCR_TX_EN | MAC_MCR_RX_EN;
mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
}
static void mtk_validate(struct phylink_config *config,
unsigned long *supported,
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) &&
!(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII) &&
(state->interface == PHY_INTERFACE_MODE_SGMII ||
phy_interface_mode_is_8023z(state->interface)))) {
linkmode_zero(supported);
return;
}
phylink_set_port_modes(mask);
phylink_set(mask, Autoneg);
switch (state->interface) {
case PHY_INTERFACE_MODE_TRGMII:
phylink_set(mask, 1000baseT_Full);
break;
case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_2500BASEX:
phylink_set(mask, 1000baseX_Full);
phylink_set(mask, 2500baseX_Full);
break;
case PHY_INTERFACE_MODE_GMII:
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
phylink_set(mask, 1000baseT_Half);
/* fall through */
case PHY_INTERFACE_MODE_SGMII:
phylink_set(mask, 1000baseT_Full);
phylink_set(mask, 1000baseX_Full);
/* fall through */
case PHY_INTERFACE_MODE_MII:
case PHY_INTERFACE_MODE_RMII:
case PHY_INTERFACE_MODE_REVMII:
case PHY_INTERFACE_MODE_NA:
default:
phylink_set(mask, 10baseT_Half);
phylink_set(mask, 10baseT_Full);
phylink_set(mask, 100baseT_Half);
phylink_set(mask, 100baseT_Full);
break;
}
if (state->interface == PHY_INTERFACE_MODE_NA) {
if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII)) {
phylink_set(mask, 1000baseT_Full);
phylink_set(mask, 1000baseX_Full);
phylink_set(mask, 2500baseX_Full);
}
if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII)) {
phylink_set(mask, 1000baseT_Full);
phylink_set(mask, 1000baseT_Half);
phylink_set(mask, 1000baseX_Full);
}
if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GEPHY)) {
phylink_set(mask, 1000baseT_Full);
phylink_set(mask, 1000baseT_Half);
}
}
phylink_set(mask, Pause);
phylink_set(mask, Asym_Pause);
linkmode_and(supported, supported, mask);
linkmode_and(state->advertising, state->advertising, mask);
/* We can only operate at 2500BaseX or 1000BaseX. If requested
* to advertise both, only report advertising at 2500BaseX.
*/
phylink_helper_basex_speed(state);
}
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 +2185,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 +2210,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 +2243,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 +2342,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 +2354,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 +2386,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 +2438,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 +2446,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 +2500,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 +2562,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 +2573,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 +2607,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) return phylink_ethtool_nway_reset(mac->phylink);
{
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;
} }
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 +2730,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 +2758,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 +2805,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 +2859,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 +3045,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 +3053,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);

View File

@ -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 @@
#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
@ -404,6 +412,13 @@
/* Register to auto-negotiation restart */ /* Register to auto-negotiation restart */
#define SGMSYS_PCS_CONTROL_1 0x0 #define SGMSYS_PCS_CONTROL_1 0x0
#define SGMII_AN_RESTART BIT(9) #define SGMII_AN_RESTART BIT(9)
#define SGMII_ISOLATE BIT(10)
#define SGMII_AN_ENABLE BIT(12)
#define SGMII_LINK_STATYS BIT(18)
#define SGMII_AN_ABILITY BIT(19)
#define SGMII_AN_COMPLETE BIT(21)
#define SGMII_PCS_FAULT BIT(23)
#define SGMII_AN_EXPANSION_CLR BIT(30)
/* Register to programmable link timer, the unit in 2 * 8ns */ /* Register to programmable link timer, the unit in 2 * 8ns */
#define SGMSYS_PCS_LINK_TIMER 0x18 #define SGMSYS_PCS_LINK_TIMER 0x18
@ -411,7 +426,24 @@
/* Register to control remote fault */ /* Register to control remote fault */
#define SGMSYS_SGMII_MODE 0x20 #define SGMSYS_SGMII_MODE 0x20
#define SGMII_IF_MODE_BIT0 BIT(0)
#define SGMII_SPEED_DUPLEX_AN BIT(1)
#define SGMII_SPEED_10 0x0
#define SGMII_SPEED_100 BIT(2)
#define SGMII_SPEED_1000 BIT(3)
#define SGMII_DUPLEX_FULL BIT(4)
#define SGMII_IF_MODE_BIT5 BIT(5)
#define SGMII_REMOTE_FAULT_DIS BIT(8) #define SGMII_REMOTE_FAULT_DIS BIT(8)
#define SGMII_CODE_SYNC_SET_VAL BIT(9)
#define SGMII_CODE_SYNC_SET_EN BIT(10)
#define SGMII_SEND_AN_ERROR_EN BIT(11)
#define SGMII_IF_MODE_MASK GENMASK(5, 1)
/* Register to set SGMII speed, ANA RG_ Control Signals III*/
#define SGMSYS_ANA_RG_CS3 0x2028
#define RG_PHY_SPEED_MASK (BIT(2) | BIT(3))
#define RG_PHY_SPEED_1_25G 0x0
#define RG_PHY_SPEED_3_125G BIT(2)
/* Register to power up QPHY */ /* Register to power up QPHY */
#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 #define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8
@ -858,22 +890,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 */
@ -888,7 +921,12 @@ u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np, int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np,
u32 ana_rgc3); u32 ana_rgc3);
int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id); int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id);
int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id); int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id,
int mtk_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode); const struct phylink_link_state *state);
void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id);
int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id);
int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id);
int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id);
#endif /* MTK_ETH_H */ #endif /* MTK_ETH_H */

View File

@ -16,8 +16,7 @@
int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3)
{ {
struct device_node *np; struct device_node *np;
const char *str; int i;
int i, err;
ss->ana_rgc3 = ana_rgc3; ss->ana_rgc3 = ana_rgc3;
@ -29,19 +28,6 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3)
ss->regmap[i] = syscon_node_to_regmap(np); ss->regmap[i] = syscon_node_to_regmap(np);
if (IS_ERR(ss->regmap[i])) if (IS_ERR(ss->regmap[i]))
return PTR_ERR(ss->regmap[i]); return PTR_ERR(ss->regmap[i]);
err = of_property_read_string(np, "mediatek,physpeed", &str);
if (err)
return err;
if (!strcmp(str, "2500"))
ss->flags[i] |= MTK_SGMII_PHYSPEED_2500;
else if (!strcmp(str, "1000"))
ss->flags[i] |= MTK_SGMII_PHYSPEED_1000;
else if (!strcmp(str, "auto"))
ss->flags[i] |= MTK_SGMII_PHYSPEED_AN;
else
return -EINVAL;
} }
return 0; return 0;
@ -73,27 +59,45 @@ int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id)
return 0; return 0;
} }
int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id) int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id,
const struct phylink_link_state *state)
{ {
unsigned int val; unsigned int val;
int mode;
if (!ss->regmap[id]) if (!ss->regmap[id])
return -EINVAL; return -EINVAL;
regmap_read(ss->regmap[id], ss->ana_rgc3, &val); regmap_read(ss->regmap[id], ss->ana_rgc3, &val);
val &= ~GENMASK(3, 2); val &= ~RG_PHY_SPEED_MASK;
mode = ss->flags[id] & MTK_SGMII_PHYSPEED_MASK; if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
val |= (mode == MTK_SGMII_PHYSPEED_1000) ? 0 : BIT(2); val |= RG_PHY_SPEED_3_125G;
regmap_write(ss->regmap[id], ss->ana_rgc3, val); regmap_write(ss->regmap[id], ss->ana_rgc3, val);
/* Disable SGMII AN */ /* Disable SGMII AN */
regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val); regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val);
val &= ~BIT(12); val &= ~SGMII_AN_ENABLE;
regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val);
/* SGMII force mode setting */ /* SGMII force mode setting */
val = 0x31120019; regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val);
val &= ~SGMII_IF_MODE_MASK;
switch (state->speed) {
case SPEED_10:
val |= SGMII_SPEED_10;
break;
case SPEED_100:
val |= SGMII_SPEED_100;
break;
case SPEED_2500:
case SPEED_1000:
val |= SGMII_SPEED_1000;
break;
};
if (state->duplex == DUPLEX_FULL)
val |= SGMII_DUPLEX_FULL;
regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val);
/* Release PHYA power down state */ /* Release PHYA power down state */
@ -103,3 +107,20 @@ int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id)
return 0; return 0;
} }
void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id)
{
struct mtk_sgmii *ss = eth->sgmii;
unsigned int val, sid;
/* Decide how GMAC and SGMIISYS be mapped */
sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ?
0 : mac_id;
if (!ss->regmap[sid])
return;
regmap_read(ss->regmap[sid], SGMSYS_PCS_CONTROL_1, &val);
val |= SGMII_AN_RESTART;
regmap_write(ss->regmap[sid], SGMSYS_PCS_CONTROL_1, val);
}