Commit 4ebcfd9a authored by David S. Miller's avatar David S. Miller

Merge branch 'Add-MT7629-ethernet-support'

Sean Wang says:

====================
Add MT7629 ethernet support

MT7629 inlcudes two sets of SGMIIs used for external switch or PHY, and embedded
switch (ESW) via GDM1, GePHY via GMAC2, so add several patches in the series to
make the code base common with the old SoCs.

The patch 1, 3 and 6, adds extension for SGMII to have the hardware configured
for 1G, 2.5G and AN to fit the capability of the target PHY. In patch 6 could be
an example showing how to use these configurations for underlying PHY speed to
match up the link speed of the target PHY.

The patch 4 is used for automatically configured the hardware path from GMACx to
the target PHY by the description in deviceetree topology to determine the
proper value for the corresponding MUX.

The patch 2 and 5 is for the update for MT7629 including dt-binding document and
its driver.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2789c14d afdede61
...@@ -9,6 +9,8 @@ Required Properties: ...@@ -9,6 +9,8 @@ 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
......
...@@ -11,6 +11,7 @@ Required properties: ...@@ -11,6 +11,7 @@ Required properties:
"mediatek,mt2701-eth": for MT2701 SoC "mediatek,mt2701-eth": for MT2701 SoC
"mediatek,mt7623-eth", "mediatek,mt2701-eth": for MT7623 SoC "mediatek,mt7623-eth", "mediatek,mt2701-eth": for MT7623 SoC
"mediatek,mt7622-eth": for MT7622 SoC "mediatek,mt7622-eth": for MT7622 SoC
"mediatek,mt7629-eth": for MT7629 SoC
- reg: Address and length of the register set for the device - reg: Address and length of the register set for the device
- interrupts: Should contain the three frame engines interrupts in numeric - interrupts: Should contain the three frame engines interrupts in numeric
order. These are fe_int0, fe_int1 and fe_int2. order. These are fe_int0, fe_int1 and fe_int2.
...@@ -19,14 +20,23 @@ Required properties: ...@@ -19,14 +20,23 @@ Required properties:
"ethif", "esw", "gp2", "gp1" : For MT2701 and MT7623 SoC "ethif", "esw", "gp2", "gp1" : For MT2701 and MT7623 SoC
"ethif", "esw", "gp0", "gp1", "gp2", "sgmii_tx250m", "sgmii_rx250m", "ethif", "esw", "gp0", "gp1", "gp2", "sgmii_tx250m", "sgmii_rx250m",
"sgmii_cdr_ref", "sgmii_cdr_fb", "sgmii_ck", "eth2pll" : For MT7622 SoC "sgmii_cdr_ref", "sgmii_cdr_fb", "sgmii_ck", "eth2pll" : For MT7622 SoC
"ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", "fe", "sgmii_tx250m",
"sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", "sgmii2_tx250m",
"sgmii2_rx250m", "sgmii2_cdr_ref", "sgmii2_cdr_fb", "sgmii_ck",
"eth2pll" : For MT7629 SoC.
- power-domains: phandle to the power domain that the ethernet is part of - power-domains: phandle to the power domain that the ethernet is part of
- resets: Should contain phandles to the ethsys reset signals - resets: Should contain phandles to the ethsys reset signals
- reset-names: Should contain the names of reset signal listed in the resets - reset-names: Should contain the names of reset signal listed in the resets
property property
These are "fe", "gmac" and "ppe" These are "fe", "gmac" and "ppe"
- mediatek,ethsys: phandle to the syscon node that handles the port setup - mediatek,ethsys: phandle to the syscon node that handles the port setup
- mediatek,sgmiisys: phandle to the syscon node that handles the SGMII setup - mediatek,infracfg: phandle to the syscon node that handles the path from
which is required for those SoCs equipped with SGMII such as MT7622 SoC. GMAC to PHY variants, which is required for MT7629 SoC.
- mediatek,sgmiisys: a list of phandles to the syscon node that handles the
SGMII setup which is required for those SoCs equipped with SGMII such
as MT7622 and MT7629 SoC. And MT7622 have only one set of SGMII shared
by GMAC1 and GMAC2; MT7629 have two independent sets of SGMII directed
to GMAC1 and GMAC2, respectively.
- mediatek,pctl: phandle to the syscon node that handles the ports slew rate - mediatek,pctl: phandle to the syscon node that handles the ports slew rate
and driver current: only for MT2701 and MT7623 SoC and driver current: only for MT2701 and MT7623 SoC
......
...@@ -929,7 +929,8 @@ eth: ethernet@1b100000 { ...@@ -929,7 +929,8 @@ eth: ethernet@1b100000 {
sgmiisys: sgmiisys@1b128000 { sgmiisys: sgmiisys@1b128000 {
compatible = "mediatek,mt7622-sgmiisys", compatible = "mediatek,mt7622-sgmiisys",
"syscon"; "syscon";
reg = <0 0x1b128000 0 0x1000>; reg = <0 0x1b128000 0 0x3000>;
#clock-cells = <1>; #clock-cells = <1>;
mediatek,physpeed = "2500";
}; };
}; };
...@@ -3,4 +3,5 @@ ...@@ -3,4 +3,5 @@
# Makefile for the Mediatek SoCs built-in ethernet macs # Makefile for the Mediatek SoCs built-in ethernet macs
# #
obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o mtk_sgmii.o \
mtk_eth_path.o
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018-2019 MediaTek Inc.
/* A library for configuring path from GMAC/GDM to target PHY
*
* Author: Sean Wang <sean.wang@mediatek.com>
*
*/
#include <linux/phy.h>
#include <linux/regmap.h>
#include "mtk_eth_soc.h"
struct mtk_eth_muxc {
int (*set_path)(struct mtk_eth *eth, int path);
};
static const char * const mtk_eth_mux_name[] = {
"mux_gdm1_to_gmac1_esw", "mux_gmac2_gmac0_to_gephy",
"mux_u3_gmac2_to_qphy", "mux_gmac1_gmac2_to_sgmii_rgmii",
"mux_gmac12_to_gephy_sgmii",
};
static const char * const mtk_eth_path_name[] = {
"gmac1_rgmii", "gmac1_trgmii", "gmac1_sgmii", "gmac2_rgmii",
"gmac2_sgmii", "gmac2_gephy", "gdm1_esw",
};
static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, int path)
{
bool updated = true;
u32 val, mask, set;
switch (path) {
case MTK_ETH_PATH_GMAC1_SGMII:
mask = ~(u32)MTK_MUX_TO_ESW;
set = 0;
break;
case MTK_ETH_PATH_GDM1_ESW:
mask = ~(u32)MTK_MUX_TO_ESW;
set = MTK_MUX_TO_ESW;
break;
default:
updated = false;
break;
};
if (updated) {
val = mtk_r32(eth, MTK_MAC_MISC);
val = (val & mask) | set;
mtk_w32(eth, val, MTK_MAC_MISC);
}
dev_dbg(eth->dev, "path %s in %s updated = %d\n",
mtk_eth_path_name[path], __func__, updated);
return 0;
}
static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path)
{
unsigned int val = 0;
bool updated = true;
switch (path) {
case MTK_ETH_PATH_GMAC2_GEPHY:
val = ~(u32)GEPHY_MAC_SEL;
break;
default:
updated = false;
break;
}
if (updated)
regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val);
dev_dbg(eth->dev, "path %s in %s updated = %d\n",
mtk_eth_path_name[path], __func__, updated);
return 0;
}
static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path)
{
unsigned int val = 0;
bool updated = true;
switch (path) {
case MTK_ETH_PATH_GMAC2_SGMII:
val = CO_QPHY_SEL;
break;
default:
updated = false;
break;
}
if (updated)
regmap_update_bits(eth->infra, INFRA_MISC2, CO_QPHY_SEL, val);
dev_dbg(eth->dev, "path %s in %s updated = %d\n",
mtk_eth_path_name[path], __func__, updated);
return 0;
}
static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, int path)
{
unsigned int val = 0;
bool updated = true;
switch (path) {
case MTK_ETH_PATH_GMAC1_SGMII:
val = SYSCFG0_SGMII_GMAC1;
break;
case MTK_ETH_PATH_GMAC2_SGMII:
val = SYSCFG0_SGMII_GMAC2;
break;
case MTK_ETH_PATH_GMAC1_RGMII:
case MTK_ETH_PATH_GMAC2_RGMII:
regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
val &= SYSCFG0_SGMII_MASK;
if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) ||
(path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2))
val = 0;
else
updated = false;
break;
default:
updated = false;
break;
};
if (updated)
regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
SYSCFG0_SGMII_MASK, val);
dev_dbg(eth->dev, "path %s in %s updated = %d\n",
mtk_eth_path_name[path], __func__, updated);
return 0;
}
static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, int path)
{
unsigned int val = 0;
bool updated = true;
regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
switch (path) {
case MTK_ETH_PATH_GMAC1_SGMII:
val |= SYSCFG0_SGMII_GMAC1_V2;
break;
case MTK_ETH_PATH_GMAC2_GEPHY:
val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2;
break;
case MTK_ETH_PATH_GMAC2_SGMII:
val |= SYSCFG0_SGMII_GMAC2_V2;
break;
default:
updated = false;
};
if (updated)
regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
SYSCFG0_SGMII_MASK, val);
dev_dbg(eth->dev, "path %s in %s updated = %d\n",
mtk_eth_path_name[path], __func__, updated);
return 0;
}
static const struct mtk_eth_muxc mtk_eth_muxc[] = {
{ .set_path = set_mux_gdm1_to_gmac1_esw, },
{ .set_path = set_mux_gmac2_gmac0_to_gephy, },
{ .set_path = set_mux_u3_gmac2_to_qphy, },
{ .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii, },
{ .set_path = set_mux_gmac12_to_gephy_sgmii, }
};
static int mtk_eth_mux_setup(struct mtk_eth *eth, int path)
{
int i, err = 0;
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_PATH_BIT(path))) {
dev_err(eth->dev, "path %s isn't support on the SoC\n",
mtk_eth_path_name[path]);
return -EINVAL;
}
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX))
return 0;
/* Setup MUX in path fabric */
for (i = 0; i < MTK_ETH_MUX_MAX; i++) {
if (MTK_HAS_CAPS(eth->soc->caps, MTK_MUX_BIT(i))) {
err = mtk_eth_muxc[i].set_path(eth, path);
if (err)
goto out;
} else {
dev_dbg(eth->dev, "mux %s isn't present on the SoC\n",
mtk_eth_mux_name[i]);
}
}
out:
return err;
}
static int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
{
unsigned int val = 0;
int sid, err, path;
path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII :
MTK_ETH_PATH_GMAC2_SGMII;
/* Setup proper MUXes along the path */
err = mtk_eth_mux_setup(eth, path);
if (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;
}
static int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
{
int err, path = 0;
if (mac_id == 1)
path = MTK_ETH_PATH_GMAC2_GEPHY;
if (!path)
return -EINVAL;
/* Setup proper MUXes along the path */
err = mtk_eth_mux_setup(eth, path);
if (err)
return err;
return 0;
}
static int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)
{
int err, path;
path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII :
MTK_ETH_PATH_GMAC2_RGMII;
/* Setup proper MUXes along the path */
err = mtk_eth_mux_setup(eth, path);
if (err)
return err;
return 0;
}
int mtk_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode)
{
int err;
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;
}
...@@ -54,8 +54,10 @@ static const struct mtk_ethtool_stats { ...@@ -54,8 +54,10 @@ static const struct mtk_ethtool_stats {
}; };
static const char * const mtk_clks_source_name[] = { static const char * const mtk_clks_source_name[] = {
"ethif", "esw", "gp0", "gp1", "gp2", "trgpll", "sgmii_tx250m", "ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", "fe", "trgpll",
"sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", "sgmii_ck", "eth2pll" "sgmii_tx250m", "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb",
"sgmii2_tx250m", "sgmii2_rx250m", "sgmii2_cdr_ref", "sgmii2_cdr_fb",
"sgmii_ck", "eth2pll",
}; };
void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg) void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
...@@ -165,47 +167,6 @@ static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth, int speed) ...@@ -165,47 +167,6 @@ 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_gmac_sgmii_hw_setup(struct mtk_eth *eth, int mac_id)
{
u32 val;
/* Setup the link timer and QPHY power up inside SGMIISYS */
regmap_write(eth->sgmiisys, SGMSYS_PCS_LINK_TIMER,
SGMII_LINK_TIMER_DEFAULT);
regmap_read(eth->sgmiisys, SGMSYS_SGMII_MODE, &val);
val |= SGMII_REMOTE_FAULT_DIS;
regmap_write(eth->sgmiisys, SGMSYS_SGMII_MODE, val);
regmap_read(eth->sgmiisys, SGMSYS_PCS_CONTROL_1, &val);
val |= SGMII_AN_RESTART;
regmap_write(eth->sgmiisys, SGMSYS_PCS_CONTROL_1, val);
regmap_read(eth->sgmiisys, SGMSYS_QPHY_PWR_STATE_CTRL, &val);
val &= ~SGMII_PHYA_PWD;
regmap_write(eth->sgmiisys, SGMSYS_QPHY_PWR_STATE_CTRL, val);
/* Determine MUX for which GMAC uses the SGMII interface */
if (MTK_HAS_CAPS(eth->soc->caps, MTK_DUAL_GMAC_SHARED_SGMII)) {
regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
val &= ~SYSCFG0_SGMII_MASK;
val |= !mac_id ? SYSCFG0_SGMII_GMAC1 : SYSCFG0_SGMII_GMAC2;
regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val);
dev_info(eth->dev, "setup shared sgmii for gmac=%d\n",
mac_id);
}
/* Setup the GMAC1 going through SGMII path when SoC also support
* ESW on GMAC1
*/
if (MTK_HAS_CAPS(eth->soc->caps, MTK_GMAC1_ESW | MTK_GMAC1_SGMII) &&
!mac_id) {
mtk_w32(eth, 0, MTK_MAC_MISC);
dev_info(eth->dev, "setup gmac1 going through sgmii");
}
}
static void mtk_phy_link_adjust(struct net_device *dev) static void mtk_phy_link_adjust(struct net_device *dev)
{ {
struct mtk_mac *mac = netdev_priv(dev); struct mtk_mac *mac = netdev_priv(dev);
...@@ -295,6 +256,7 @@ static int mtk_phy_connect(struct net_device *dev) ...@@ -295,6 +256,7 @@ static int mtk_phy_connect(struct net_device *dev)
struct mtk_eth *eth; struct mtk_eth *eth;
struct device_node *np; struct device_node *np;
u32 val; u32 val;
int err;
eth = mac->hw; eth = mac->hw;
np = of_parse_phandle(mac->of_node, "phy-handle", 0); np = of_parse_phandle(mac->of_node, "phy-handle", 0);
...@@ -304,6 +266,10 @@ static int mtk_phy_connect(struct net_device *dev) ...@@ -304,6 +266,10 @@ static int mtk_phy_connect(struct net_device *dev)
if (!np) if (!np)
return -ENODEV; return -ENODEV;
err = mtk_setup_hw_path(eth, mac->id, of_get_phy_mode(np));
if (err)
goto err_phy;
mac->ge_mode = 0; mac->ge_mode = 0;
switch (of_get_phy_mode(np)) { switch (of_get_phy_mode(np)) {
case PHY_INTERFACE_MODE_TRGMII: case PHY_INTERFACE_MODE_TRGMII:
...@@ -312,12 +278,10 @@ static int mtk_phy_connect(struct net_device *dev) ...@@ -312,12 +278,10 @@ static int mtk_phy_connect(struct net_device *dev)
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:
break;
case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_SGMII:
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII))
mtk_gmac_sgmii_hw_setup(eth, mac->id);
break; break;
case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_MII:
case PHY_INTERFACE_MODE_GMII:
mac->ge_mode = 1; mac->ge_mode = 1;
break; break;
case PHY_INTERFACE_MODE_REVMII: case PHY_INTERFACE_MODE_REVMII:
...@@ -2482,16 +2446,28 @@ static int mtk_probe(struct platform_device *pdev) ...@@ -2482,16 +2446,28 @@ static int mtk_probe(struct platform_device *pdev)
return PTR_ERR(eth->ethsys); return PTR_ERR(eth->ethsys);
} }
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { if (MTK_HAS_CAPS(eth->soc->caps, MTK_INFRA)) {
eth->sgmiisys = eth->infra = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "mediatek,infracfg");
"mediatek,sgmiisys"); if (IS_ERR(eth->infra)) {
if (IS_ERR(eth->sgmiisys)) { dev_err(&pdev->dev, "no infracfg regmap found\n");
dev_err(&pdev->dev, "no sgmiisys regmap found\n"); return PTR_ERR(eth->infra);
return PTR_ERR(eth->sgmiisys);
} }
} }
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii),
GFP_KERNEL);
if (!eth->sgmii)
return -ENOMEM;
err = mtk_sgmii_init(eth->sgmii, pdev->dev.of_node,
eth->soc->ana_rgc3);
if (err)
return err;
}
if (eth->soc->required_pctl) { if (eth->soc->required_pctl) {
eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"mediatek,pctl"); "mediatek,pctl");
...@@ -2630,7 +2606,7 @@ static int mtk_remove(struct platform_device *pdev) ...@@ -2630,7 +2606,7 @@ static int mtk_remove(struct platform_device *pdev)
} }
static const struct mtk_soc_data mt2701_data = { static const struct mtk_soc_data mt2701_data = {
.caps = MTK_GMAC1_TRGMII | MTK_HWLRO, .caps = MT7623_CAPS | MTK_HWLRO,
.required_clks = MT7623_CLKS_BITMAP, .required_clks = MT7623_CLKS_BITMAP,
.required_pctl = true, .required_pctl = true,
}; };
...@@ -2642,22 +2618,31 @@ static const struct mtk_soc_data mt7621_data = { ...@@ -2642,22 +2618,31 @@ static const struct mtk_soc_data mt7621_data = {
}; };
static const struct mtk_soc_data mt7622_data = { static const struct mtk_soc_data mt7622_data = {
.caps = MTK_DUAL_GMAC_SHARED_SGMII | MTK_GMAC1_ESW | MTK_HWLRO, .ana_rgc3 = 0x2028,
.caps = MT7622_CAPS | MTK_HWLRO,
.required_clks = MT7622_CLKS_BITMAP, .required_clks = MT7622_CLKS_BITMAP,
.required_pctl = false, .required_pctl = false,
}; };
static const struct mtk_soc_data mt7623_data = { static const struct mtk_soc_data mt7623_data = {
.caps = MTK_GMAC1_TRGMII | MTK_HWLRO, .caps = MT7623_CAPS | MTK_HWLRO,
.required_clks = MT7623_CLKS_BITMAP, .required_clks = MT7623_CLKS_BITMAP,
.required_pctl = true, .required_pctl = true,
}; };
static const struct mtk_soc_data mt7629_data = {
.ana_rgc3 = 0x128,
.caps = MT7629_CAPS | MTK_HWLRO,
.required_clks = MT7629_CLKS_BITMAP,
.required_pctl = false,
};
const struct of_device_id of_mtk_match[] = { const struct of_device_id of_mtk_match[] = {
{ .compatible = "mediatek,mt2701-eth", .data = &mt2701_data}, { .compatible = "mediatek,mt2701-eth", .data = &mt2701_data},
{ .compatible = "mediatek,mt7621-eth", .data = &mt7621_data}, { .compatible = "mediatek,mt7621-eth", .data = &mt7621_data},
{ .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data},
{ .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data},
{ .compatible = "mediatek,mt7629-eth", .data = &mt7629_data},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, of_mtk_match); MODULE_DEVICE_TABLE(of, of_mtk_match);
......
...@@ -15,6 +15,10 @@ ...@@ -15,6 +15,10 @@
#ifndef MTK_ETH_H #ifndef MTK_ETH_H
#define MTK_ETH_H #define MTK_ETH_H
#include <linux/dma-mapping.h>
#include <linux/netdevice.h>
#include <linux/of_net.h>
#include <linux/u64_stats_sync.h>
#include <linux/refcount.h> #include <linux/refcount.h>
#define MTK_QDMA_PAGE_SIZE 2048 #define MTK_QDMA_PAGE_SIZE 2048
...@@ -369,9 +373,12 @@ ...@@ -369,9 +373,12 @@
#define ETHSYS_SYSCFG0 0x14 #define ETHSYS_SYSCFG0 0x14
#define SYSCFG0_GE_MASK 0x3 #define SYSCFG0_GE_MASK 0x3
#define SYSCFG0_GE_MODE(x, y) (x << (12 + (y * 2))) #define SYSCFG0_GE_MODE(x, y) (x << (12 + (y * 2)))
#define SYSCFG0_SGMII_MASK (3 << 8) #define SYSCFG0_SGMII_MASK GENMASK(9, 8)
#define SYSCFG0_SGMII_GMAC1 ((2 << 8) & GENMASK(9, 8)) #define SYSCFG0_SGMII_GMAC1 ((2 << 8) & SYSCFG0_SGMII_MASK)
#define SYSCFG0_SGMII_GMAC2 ((3 << 8) & GENMASK(9, 8)) #define SYSCFG0_SGMII_GMAC2 ((3 << 8) & SYSCFG0_SGMII_MASK)
#define SYSCFG0_SGMII_GMAC1_V2 BIT(9)
#define SYSCFG0_SGMII_GMAC2_V2 BIT(8)
/* ethernet subsystem clock register */ /* ethernet subsystem clock register */
#define ETHSYS_CLKCFG0 0x2c #define ETHSYS_CLKCFG0 0x2c
...@@ -399,6 +406,11 @@ ...@@ -399,6 +406,11 @@
#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 #define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8
#define SGMII_PHYA_PWD BIT(4) #define SGMII_PHYA_PWD BIT(4)
/* Infrasys subsystem config registers */
#define INFRA_MISC2 0x70c
#define CO_QPHY_SEL BIT(0)
#define GEPHY_MAC_SEL BIT(1)
struct mtk_rx_dma { struct mtk_rx_dma {
unsigned int rxd1; unsigned int rxd1;
unsigned int rxd2; unsigned int rxd2;
...@@ -463,15 +475,21 @@ enum mtk_tx_flags { ...@@ -463,15 +475,21 @@ enum mtk_tx_flags {
*/ */
enum mtk_clks_map { enum mtk_clks_map {
MTK_CLK_ETHIF, MTK_CLK_ETHIF,
MTK_CLK_SGMIITOP,
MTK_CLK_ESW, MTK_CLK_ESW,
MTK_CLK_GP0, MTK_CLK_GP0,
MTK_CLK_GP1, MTK_CLK_GP1,
MTK_CLK_GP2, MTK_CLK_GP2,
MTK_CLK_FE,
MTK_CLK_TRGPLL, MTK_CLK_TRGPLL,
MTK_CLK_SGMII_TX_250M, MTK_CLK_SGMII_TX_250M,
MTK_CLK_SGMII_RX_250M, MTK_CLK_SGMII_RX_250M,
MTK_CLK_SGMII_CDR_REF, MTK_CLK_SGMII_CDR_REF,
MTK_CLK_SGMII_CDR_FB, MTK_CLK_SGMII_CDR_FB,
MTK_CLK_SGMII2_TX_250M,
MTK_CLK_SGMII2_RX_250M,
MTK_CLK_SGMII2_CDR_REF,
MTK_CLK_SGMII2_CDR_FB,
MTK_CLK_SGMII_CK, MTK_CLK_SGMII_CK,
MTK_CLK_ETH2PLL, MTK_CLK_ETH2PLL,
MTK_CLK_MAX MTK_CLK_MAX
...@@ -490,6 +508,19 @@ enum mtk_clks_map { ...@@ -490,6 +508,19 @@ enum mtk_clks_map {
BIT(MTK_CLK_SGMII_CK) | \ BIT(MTK_CLK_SGMII_CK) | \
BIT(MTK_CLK_ETH2PLL)) BIT(MTK_CLK_ETH2PLL))
#define MT7621_CLKS_BITMAP (0) #define MT7621_CLKS_BITMAP (0)
#define MT7629_CLKS_BITMAP (BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) | \
BIT(MTK_CLK_GP0) | BIT(MTK_CLK_GP1) | \
BIT(MTK_CLK_GP2) | BIT(MTK_CLK_FE) | \
BIT(MTK_CLK_SGMII_TX_250M) | \
BIT(MTK_CLK_SGMII_RX_250M) | \
BIT(MTK_CLK_SGMII_CDR_REF) | \
BIT(MTK_CLK_SGMII_CDR_FB) | \
BIT(MTK_CLK_SGMII2_TX_250M) | \
BIT(MTK_CLK_SGMII2_RX_250M) | \
BIT(MTK_CLK_SGMII2_CDR_REF) | \
BIT(MTK_CLK_SGMII2_CDR_FB) | \
BIT(MTK_CLK_SGMII_CK) | \
BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP))
enum mtk_dev_state { enum mtk_dev_state {
MTK_HW_INIT, MTK_HW_INIT,
...@@ -560,21 +591,105 @@ struct mtk_rx_ring { ...@@ -560,21 +591,105 @@ struct mtk_rx_ring {
u32 crx_idx_reg; u32 crx_idx_reg;
}; };
#define MTK_TRGMII BIT(0) enum mtk_eth_mux {
#define MTK_GMAC1_TRGMII (BIT(1) | MTK_TRGMII) MTK_ETH_MUX_GDM1_TO_GMAC1_ESW,
#define MTK_ESW BIT(4) MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY,
#define MTK_GMAC1_ESW (BIT(5) | MTK_ESW) MTK_ETH_MUX_U3_GMAC2_TO_QPHY,
#define MTK_SGMII BIT(8) MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII,
#define MTK_GMAC1_SGMII (BIT(9) | MTK_SGMII) MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII,
#define MTK_GMAC2_SGMII (BIT(10) | MTK_SGMII) MTK_ETH_MUX_MAX,
#define MTK_DUAL_GMAC_SHARED_SGMII (BIT(11) | MTK_GMAC1_SGMII | \ };
MTK_GMAC2_SGMII)
#define MTK_HWLRO BIT(12) enum mtk_eth_path {
#define MTK_SHARED_INT BIT(13) MTK_ETH_PATH_GMAC1_RGMII,
MTK_ETH_PATH_GMAC1_TRGMII,
MTK_ETH_PATH_GMAC1_SGMII,
MTK_ETH_PATH_GMAC2_RGMII,
MTK_ETH_PATH_GMAC2_SGMII,
MTK_ETH_PATH_GMAC2_GEPHY,
MTK_ETH_PATH_GDM1_ESW,
MTK_ETH_PATH_MAX,
};
/* Supported hardware group on SoCs */
#define MTK_RGMII BIT(0)
#define MTK_TRGMII BIT(1)
#define MTK_SGMII BIT(2)
#define MTK_ESW BIT(3)
#define MTK_GEPHY BIT(4)
#define MTK_MUX BIT(5)
#define MTK_INFRA BIT(6)
#define MTK_SHARED_SGMII BIT(7)
#define MTK_HWLRO BIT(8)
#define MTK_SHARED_INT BIT(9)
/* Supported path present on SoCs */
#define MTK_PATH_BIT(x) BIT((x) + 10)
#define MTK_GMAC1_RGMII \
(MTK_PATH_BIT(MTK_ETH_PATH_GMAC1_RGMII) | MTK_RGMII)
#define MTK_GMAC1_TRGMII \
(MTK_PATH_BIT(MTK_ETH_PATH_GMAC1_TRGMII) | MTK_TRGMII)
#define MTK_GMAC1_SGMII \
(MTK_PATH_BIT(MTK_ETH_PATH_GMAC1_SGMII) | MTK_SGMII)
#define MTK_GMAC2_RGMII \
(MTK_PATH_BIT(MTK_ETH_PATH_GMAC2_RGMII) | MTK_RGMII)
#define MTK_GMAC2_SGMII \
(MTK_PATH_BIT(MTK_ETH_PATH_GMAC2_SGMII) | MTK_SGMII)
#define MTK_GMAC2_GEPHY \
(MTK_PATH_BIT(MTK_ETH_PATH_GMAC2_GEPHY) | MTK_GEPHY)
#define MTK_GDM1_ESW \
(MTK_PATH_BIT(MTK_ETH_PATH_GDM1_ESW) | MTK_ESW)
#define MTK_MUX_BIT(x) BIT((x) + 20)
/* MUXes present on SoCs */
/* 0: GDM1 -> GMAC1, 1: GDM1 -> ESW */
#define MTK_MUX_GDM1_TO_GMAC1_ESW \
(MTK_MUX_BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW) | MTK_MUX)
/* 0: GMAC2 -> GEPHY, 1: GMAC0 -> GePHY */
#define MTK_MUX_GMAC2_GMAC0_TO_GEPHY \
(MTK_MUX_BIT(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY) | MTK_MUX | MTK_INFRA)
/* 0: U3 -> QPHY, 1: GMAC2 -> QPHY */
#define MTK_MUX_U3_GMAC2_TO_QPHY \
(MTK_MUX_BIT(MTK_ETH_MUX_U3_GMAC2_TO_QPHY) | MTK_MUX | MTK_INFRA)
/* 2: GMAC1 -> SGMII, 3: GMAC2 -> SGMII */
#define MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \
(MTK_MUX_BIT(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII) | MTK_MUX | \
MTK_SHARED_SGMII)
/* 0: GMACx -> GEPHY, 1: GMACx -> SGMII where x is 1 or 2 */
#define MTK_MUX_GMAC12_TO_GEPHY_SGMII \
(MTK_MUX_BIT(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII) | MTK_MUX)
#define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x)) #define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x))
#define MT7622_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_SGMII | MTK_GMAC2_RGMII | \
MTK_GMAC2_SGMII | MTK_GDM1_ESW | \
MTK_MUX_GDM1_TO_GMAC1_ESW | \
MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII)
#define MT7623_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | MTK_GMAC2_RGMII)
#define MT7629_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
MTK_GDM1_ESW | MTK_MUX_GDM1_TO_GMAC1_ESW | \
MTK_MUX_GMAC2_GMAC0_TO_GEPHY | \
MTK_MUX_U3_GMAC2_TO_QPHY | \
MTK_MUX_GMAC12_TO_GEPHY_SGMII)
/* struct mtk_eth_data - This is the structure holding all differences /* struct mtk_eth_data - This is the structure holding all differences
* among various plaforms * among various plaforms
* @ana_rgc3: The offset for register ANA_RGC3 related to
* sgmiisys syscon
* @caps Flags shown the extra capability for the SoC * @caps Flags shown the extra capability for the SoC
* @required_clks Flags shown the bitmap for required clocks on * @required_clks Flags shown the bitmap for required clocks on
* the target SoC * the target SoC
...@@ -582,6 +697,7 @@ struct mtk_rx_ring { ...@@ -582,6 +697,7 @@ struct mtk_rx_ring {
* the extra setup for those pins used by GMAC. * the extra setup for those pins used by GMAC.
*/ */
struct mtk_soc_data { struct mtk_soc_data {
u32 ana_rgc3;
u32 caps; u32 caps;
u32 required_clks; u32 required_clks;
bool required_pctl; bool required_pctl;
...@@ -590,6 +706,26 @@ struct mtk_soc_data { ...@@ -590,6 +706,26 @@ struct mtk_soc_data {
/* currently no SoC has more than 2 macs */ /* currently no SoC has more than 2 macs */
#define MTK_MAX_DEVS 2 #define MTK_MAX_DEVS 2
#define MTK_SGMII_PHYSPEED_AN BIT(31)
#define MTK_SGMII_PHYSPEED_MASK GENMASK(0, 2)
#define MTK_SGMII_PHYSPEED_1000 BIT(0)
#define MTK_SGMII_PHYSPEED_2500 BIT(1)
#define MTK_HAS_FLAGS(flags, _x) (((flags) & (_x)) == (_x))
/* struct mtk_sgmii - This is the structure holding sgmii regmap and its
* characteristics
* @regmap: The register map pointing at the range used to setup
* SGMII modes
* @flags: The enum refers to which mode the sgmii wants to run on
* @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap
*/
struct mtk_sgmii {
struct regmap *regmap[MTK_MAX_DEVS];
u32 flags[MTK_MAX_DEVS];
u32 ana_rgc3;
};
/* struct mtk_eth - This is the main datasructure for holding the state /* struct mtk_eth - This is the main datasructure for holding the state
* of the driver * of the driver
* @dev: The device pointer * @dev: The device pointer
...@@ -605,8 +741,8 @@ struct mtk_soc_data { ...@@ -605,8 +741,8 @@ struct mtk_soc_data {
* @msg_enable: Ethtool msg level * @msg_enable: Ethtool msg level
* @ethsys: The register map pointing at the range used to setup * @ethsys: The register map pointing at the range used to setup
* MII modes * MII modes
* @sgmiisys: The register map pointing at the range used to setup * @infra: The register map pointing at the range used to setup
* SGMII modes * SGMII and GePHY path
* @pctl: The register map pointing at the range used to setup * @pctl: The register map pointing at the range used to setup
* GMAC port drive/slew values * GMAC port drive/slew values
* @dma_refcnt: track how many netdevs are using the DMA engine * @dma_refcnt: track how many netdevs are using the DMA engine
...@@ -638,7 +774,8 @@ struct mtk_eth { ...@@ -638,7 +774,8 @@ struct mtk_eth {
u32 msg_enable; u32 msg_enable;
unsigned long sysclk; unsigned long sysclk;
struct regmap *ethsys; struct regmap *ethsys;
struct regmap *sgmiisys; struct regmap *infra;
struct mtk_sgmii *sgmii;
struct regmap *pctl; struct regmap *pctl;
bool hwlro; bool hwlro;
refcount_t dma_refcnt; refcount_t dma_refcnt;
...@@ -689,4 +826,10 @@ void mtk_stats_update_mac(struct mtk_mac *mac); ...@@ -689,4 +826,10 @@ void mtk_stats_update_mac(struct mtk_mac *mac);
void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg);
u32 mtk_r32(struct mtk_eth *eth, unsigned reg); u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np,
u32 ana_rgc3);
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_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode);
#endif /* MTK_ETH_H */ #endif /* MTK_ETH_H */
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018-2019 MediaTek Inc.
/* A library for MediaTek SGMII circuit
*
* Author: Sean Wang <sean.wang@mediatek.com>
*
*/
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include "mtk_eth_soc.h"
int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3)
{
struct device_node *np;
const char *str;
int i, err;
ss->ana_rgc3 = ana_rgc3;
for (i = 0; i < MTK_MAX_DEVS; i++) {
np = of_parse_phandle(r, "mediatek,sgmiisys", i);
if (!np)
break;
ss->regmap[i] = syscon_node_to_regmap(np);
if (IS_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;
}
int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id)
{
unsigned int val;
if (!ss->regmap[id])
return -EINVAL;
/* Setup the link timer and QPHY power up inside SGMIISYS */
regmap_write(ss->regmap[id], SGMSYS_PCS_LINK_TIMER,
SGMII_LINK_TIMER_DEFAULT);
regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val);
val |= SGMII_REMOTE_FAULT_DIS;
regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val);
regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val);
val |= SGMII_AN_RESTART;
regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val);
regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val);
val &= ~SGMII_PHYA_PWD;
regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val);
return 0;
}
int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id)
{
unsigned int val;
int mode;
if (!ss->regmap[id])
return -EINVAL;
regmap_read(ss->regmap[id], ss->ana_rgc3, &val);
val &= ~GENMASK(2, 3);
mode = ss->flags[id] & MTK_SGMII_PHYSPEED_MASK;
val |= (mode == MTK_SGMII_PHYSPEED_1000) ? 0 : BIT(2);
regmap_write(ss->regmap[id], ss->ana_rgc3, val);
/* Disable SGMII AN */
regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val);
val &= ~BIT(12);
regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val);
/* SGMII force mode setting */
val = 0x31120019;
regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val);
/* Release PHYA power down state */
regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val);
val &= ~SGMII_PHYA_PWD;
regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val);
return 0;
}
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