Commit 51cf06dd authored by Daniel Golle's avatar Daniel Golle Committed by Jakub Kicinski
Browse files

net: ethernet: mtk_eth_soc: add support for MT7988 internal 2.5G PHY



The MediaTek MT7988 SoC comes with an single built-in Ethernet PHY for
2500Base-T/1000Base-T/100Base-TX/10Base-T link partners in addition to
the built-in 1GE switch. The built-in PHY only supports full duplex.

Add muxes allowing to select GMAC2->2.5G PHY path and add basic support
for XGMAC as the built-in 2.5G PHY is internally connected via XGMII.
The XGMAC features will also be used by 5GBase-R, 10GBase-R and USXGMII
SerDes modes which are going to be added once support for standalone PCS
drivers is in place.

In order to make use of the built-in 2.5G PHY the appropriate PHY driver
as well as (proprietary) PHY firmware has to be present as well.

Signed-off-by: default avatarDaniel Golle <daniel@makrotopia.org>
Link: https://patch.msgid.link/9072cefbff6db969720672ec98ed5cef65e8218c.1745715380.git.daniel@makrotopia.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 7a4f15ca
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ static const char *mtk_eth_path_name(u64 path)
		return "gmac2_rgmii";
	case MTK_ETH_PATH_GMAC2_SGMII:
		return "gmac2_sgmii";
	case MTK_ETH_PATH_GMAC2_2P5GPHY:
		return "gmac2_2p5gphy";
	case MTK_ETH_PATH_GMAC2_GEPHY:
		return "gmac2_gephy";
	case MTK_ETH_PATH_GDM1_ESW:
@@ -127,6 +129,29 @@ static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path)
	return 0;
}

static int set_mux_gmac2_to_2p5gphy(struct mtk_eth *eth, u64 path)
{
	int ret;

	if (path == MTK_ETH_PATH_GMAC2_2P5GPHY) {
		ret = regmap_clear_bits(eth->ethsys, ETHSYS_SYSCFG0,
					SYSCFG0_SGMII_GMAC2_V2);
		if (ret)
			return ret;

		/* Setup mux to 2p5g PHY */
		ret = regmap_clear_bits(eth->infra, TOP_MISC_NETSYS_PCS_MUX,
					MUX_G2_USXGMII_SEL);
		if (ret)
			return ret;

		dev_dbg(eth->dev, "path %s in %s updated\n",
			mtk_eth_path_name(path), __func__);
	}

	return 0;
}

static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path)
{
	unsigned int val = 0;
@@ -209,6 +234,10 @@ static const struct mtk_eth_muxc mtk_eth_muxc[] = {
		.name = "mux_u3_gmac2_to_qphy",
		.cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY,
		.set_path = set_mux_u3_gmac2_to_qphy,
	}, {
		.name = "mux_gmac2_to_2p5gphy",
		.cap_bit = MTK_ETH_MUX_GMAC2_TO_2P5GPHY,
		.set_path = set_mux_gmac2_to_2p5gphy,
	}, {
		.name = "mux_gmac1_gmac2_to_sgmii_rgmii",
		.cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII,
@@ -260,6 +289,20 @@ int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
	return mtk_eth_mux_setup(eth, path);
}

int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id)
{
	u64 path = 0;

	if (mac_id == MTK_GMAC2_ID)
		path = MTK_ETH_PATH_GMAC2_2P5GPHY;

	if (!path)
		return -EINVAL;

	/* Setup proper MUXes along the path */
	return mtk_eth_mux_setup(eth, path);
}

int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
{
	u64 path = 0;
+106 −13
Original line number Diff line number Diff line
@@ -503,7 +503,7 @@ static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth,
static void mtk_setup_bridge_switch(struct mtk_eth *eth)
{
	/* Force Port1 XGMAC Link Up */
	mtk_m32(eth, 0, MTK_XGMAC_FORCE_LINK(MTK_GMAC1_ID),
	mtk_m32(eth, 0, MTK_XGMAC_FORCE_MODE(MTK_GMAC1_ID),
		MTK_XGMAC_STS(MTK_GMAC1_ID));

	/* Adjust GSW bridge IPG to 11 */
@@ -532,6 +532,26 @@ static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config,
	return NULL;
}

static int mtk_mac_prepare(struct phylink_config *config, unsigned int mode,
			   phy_interface_t iface)
{
	struct mtk_mac *mac = container_of(config, struct mtk_mac,
					   phylink_config);
	struct mtk_eth *eth = mac->hw;

	if (mtk_interface_mode_is_xgmii(eth, iface) &&
	    mac->id != MTK_GMAC1_ID) {
		mtk_m32(mac->hw, XMAC_MCR_TRX_DISABLE,
			XMAC_MCR_TRX_DISABLE, MTK_XMAC_MCR(mac->id));

		mtk_m32(mac->hw, MTK_XGMAC_FORCE_MODE(mac->id) |
				 MTK_XGMAC_FORCE_LINK(mac->id),
			MTK_XGMAC_FORCE_MODE(mac->id), MTK_XGMAC_STS(mac->id));
	}

	return 0;
}

static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
			   const struct phylink_link_state *state)
{
@@ -573,6 +593,12 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
			}
			break;
		case PHY_INTERFACE_MODE_INTERNAL:
			if (mac->id == MTK_GMAC2_ID &&
			    MTK_HAS_CAPS(eth->soc->caps, MTK_2P5GPHY)) {
				err = mtk_gmac_2p5gphy_path_setup(eth, mac->id);
				if (err)
					goto init_err;
			}
			break;
		default:
			goto err_phy;
@@ -644,11 +670,11 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
	}

	/* Setup gmac */
	if (mtk_is_netsys_v3_or_greater(eth) &&
	    mac->interface == PHY_INTERFACE_MODE_INTERNAL) {
	if (mtk_interface_mode_is_xgmii(eth, state->interface)) {
		mtk_w32(mac->hw, MTK_GDMA_XGDM_SEL, MTK_GDMA_EG_CTRL(mac->id));
		mtk_w32(mac->hw, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(mac->id));

		if (mac->id == MTK_GMAC1_ID)
			mtk_setup_bridge_switch(eth);
	}

@@ -696,10 +722,19 @@ static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode,
{
	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 | MAC_MCR_FORCE_LINK);
	mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
	if (!mtk_interface_mode_is_xgmii(mac->hw, interface)) {
		/* GMAC modes */
		mtk_m32(mac->hw,
			MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK, 0,
			MTK_MAC_MCR(mac->id));
	} else if (mac->id != MTK_GMAC1_ID) {
		/* XGMAC except for built-in switch */
		mtk_m32(mac->hw, XMAC_MCR_TRX_DISABLE, XMAC_MCR_TRX_DISABLE,
			MTK_XMAC_MCR(mac->id));
		mtk_m32(mac->hw, MTK_XGMAC_FORCE_LINK(mac->id), 0,
			MTK_XGMAC_STS(mac->id));
	}
}

static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx,
@@ -771,13 +806,12 @@ static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx,
	mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs);
}

static void mtk_mac_link_up(struct phylink_config *config,
static void mtk_gdm_mac_link_up(struct mtk_mac *mac,
				struct phy_device *phy,
				unsigned int mode, phy_interface_t interface,
			    int speed, int duplex, bool tx_pause, bool rx_pause)
				int speed, int duplex, bool tx_pause,
				bool rx_pause)
{
	struct mtk_mac *mac = container_of(config, struct mtk_mac,
					   phylink_config);
	u32 mcr;

	mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
@@ -811,6 +845,56 @@ static void mtk_mac_link_up(struct phylink_config *config,
	mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
}

static void mtk_xgdm_mac_link_up(struct mtk_mac *mac,
				 struct phy_device *phy,
				 unsigned int mode, phy_interface_t interface,
				 int speed, int duplex, bool tx_pause,
				 bool rx_pause)
{
	u32 mcr;

	if (mac->id == MTK_GMAC1_ID)
		return;

	/* Eliminate the interference(before link-up) caused by PHY noise */
	mtk_m32(mac->hw, XMAC_LOGIC_RST, 0, MTK_XMAC_LOGIC_RST(mac->id));
	mdelay(20);
	mtk_m32(mac->hw, XMAC_GLB_CNTCLR, XMAC_GLB_CNTCLR,
		MTK_XMAC_CNT_CTRL(mac->id));

	mtk_m32(mac->hw, MTK_XGMAC_FORCE_LINK(mac->id),
		MTK_XGMAC_FORCE_LINK(mac->id), MTK_XGMAC_STS(mac->id));

	mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id));
	mcr &= ~(XMAC_MCR_FORCE_TX_FC | XMAC_MCR_FORCE_RX_FC |
		 XMAC_MCR_TRX_DISABLE);
	/* Configure pause modes -
	 * phylink will avoid these for half duplex
	 */
	if (tx_pause)
		mcr |= XMAC_MCR_FORCE_TX_FC;
	if (rx_pause)
		mcr |= XMAC_MCR_FORCE_RX_FC;

	mtk_w32(mac->hw, mcr, MTK_XMAC_MCR(mac->id));
}

static void mtk_mac_link_up(struct phylink_config *config,
			    struct phy_device *phy,
			    unsigned int mode, phy_interface_t interface,
			    int speed, int duplex, bool tx_pause, bool rx_pause)
{
	struct mtk_mac *mac = container_of(config, struct mtk_mac,
					   phylink_config);

	if (mtk_interface_mode_is_xgmii(mac->hw, interface))
		mtk_xgdm_mac_link_up(mac, phy, mode, interface, speed, duplex,
				     tx_pause, rx_pause);
	else
		mtk_gdm_mac_link_up(mac, phy, mode, interface, speed, duplex,
				    tx_pause, rx_pause);
}

static void mtk_mac_disable_tx_lpi(struct phylink_config *config)
{
	struct mtk_mac *mac = container_of(config, struct mtk_mac,
@@ -828,6 +912,9 @@ static int mtk_mac_enable_tx_lpi(struct phylink_config *config, u32 timer,
	struct mtk_eth *eth = mac->hw;
	u32 val;

	if (mtk_interface_mode_is_xgmii(eth, mac->interface))
		return -EOPNOTSUPP;

	/* Tx idle timer in ms */
	timer = DIV_ROUND_UP(timer, 1000);

@@ -858,6 +945,7 @@ static int mtk_mac_enable_tx_lpi(struct phylink_config *config, u32 timer,
}

static const struct phylink_mac_ops mtk_phylink_ops = {
	.mac_prepare = mtk_mac_prepare,
	.mac_select_pcs = mtk_mac_select_pcs,
	.mac_config = mtk_mac_config,
	.mac_finish = mtk_mac_finish,
@@ -4763,6 +4851,11 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)

	mac->phylink = phylink;

	if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_2P5GPHY) &&
	    id == MTK_GMAC2_ID)
		__set_bit(PHY_INTERFACE_MODE_INTERNAL,
			  mac->phylink_config.supported_interfaces);

	SET_NETDEV_DEV(eth->netdev[id], eth->dev);
	eth->netdev[id]->watchdog_timeo = 5 * HZ;
	eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
+54 −3
Original line number Diff line number Diff line
@@ -431,7 +431,8 @@

/* XMAC status registers */
#define MTK_XGMAC_STS(x)	(((x) == MTK_GMAC3_ID) ? 0x1001C : 0x1000C)
#define MTK_XGMAC_FORCE_LINK(x)	(((x) == MTK_GMAC2_ID) ? BIT(31) : BIT(15))
#define MTK_XGMAC_FORCE_MODE(x)	(((x) == MTK_GMAC2_ID) ? BIT(31) : BIT(15))
#define MTK_XGMAC_FORCE_LINK(x)	(((x) == MTK_GMAC2_ID) ? BIT(27) : BIT(11))
#define MTK_USXGMII_PCS_LINK	BIT(8)
#define MTK_XGMAC_RX_FC		BIT(5)
#define MTK_XGMAC_TX_FC		BIT(4)
@@ -524,6 +525,21 @@
#define INTF_MODE_RGMII_1000    (TRGMII_MODE | TRGMII_CENTRAL_ALIGNED)
#define INTF_MODE_RGMII_10_100  0

/* XFI Mac control registers */
#define MTK_XMAC_BASE(x)	(0x12000 + (((x) - 1) * 0x1000))
#define MTK_XMAC_MCR(x)		(MTK_XMAC_BASE(x))
#define XMAC_MCR_TRX_DISABLE	0xf
#define XMAC_MCR_FORCE_TX_FC	BIT(5)
#define XMAC_MCR_FORCE_RX_FC	BIT(4)

/* XFI Mac logic reset registers */
#define MTK_XMAC_LOGIC_RST(x)	(MTK_XMAC_BASE(x) + 0x10)
#define XMAC_LOGIC_RST		BIT(0)

/* XFI Mac count global control */
#define MTK_XMAC_CNT_CTRL(x)	(MTK_XMAC_BASE(x) + 0x100)
#define XMAC_GLB_CNTCLR		BIT(0)

/* GPIO port control registers for GMAC 2*/
#define GPIO_OD33_CTRL8		0x4c0
#define GPIO_BIAS_CTRL		0xed0
@@ -587,6 +603,10 @@
#define GEPHY_MAC_SEL          BIT(1)

/* Top misc registers */
#define TOP_MISC_NETSYS_PCS_MUX	0x0
#define NETSYS_PCS_MUX_MASK	GENMASK(1, 0)
#define MUX_G2_USXGMII_SEL	BIT(1)

#define USB_PHY_SWITCH_REG	0x218
#define QPHY_SEL_MASK		GENMASK(1, 0)
#define SGMII_QPHY_SEL		0x2
@@ -951,6 +971,7 @@ enum mkt_eth_capabilities {
	MTK_RGMII_BIT = 0,
	MTK_TRGMII_BIT,
	MTK_SGMII_BIT,
	MTK_2P5GPHY_BIT,
	MTK_ESW_BIT,
	MTK_GEPHY_BIT,
	MTK_MUX_BIT,
@@ -971,6 +992,7 @@ enum mkt_eth_capabilities {
	MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT,
	MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT,
	MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT,
	MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT,
	MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT,
	MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT,

@@ -980,6 +1002,7 @@ enum mkt_eth_capabilities {
	MTK_ETH_PATH_GMAC1_SGMII_BIT,
	MTK_ETH_PATH_GMAC2_RGMII_BIT,
	MTK_ETH_PATH_GMAC2_SGMII_BIT,
	MTK_ETH_PATH_GMAC2_2P5GPHY_BIT,
	MTK_ETH_PATH_GMAC2_GEPHY_BIT,
	MTK_ETH_PATH_GDM1_ESW_BIT,
};
@@ -988,6 +1011,7 @@ enum mkt_eth_capabilities {
#define MTK_RGMII		BIT_ULL(MTK_RGMII_BIT)
#define MTK_TRGMII		BIT_ULL(MTK_TRGMII_BIT)
#define MTK_SGMII		BIT_ULL(MTK_SGMII_BIT)
#define MTK_2P5GPHY		BIT_ULL(MTK_2P5GPHY_BIT)
#define MTK_ESW			BIT_ULL(MTK_ESW_BIT)
#define MTK_GEPHY		BIT_ULL(MTK_GEPHY_BIT)
#define MTK_MUX			BIT_ULL(MTK_MUX_BIT)
@@ -1010,6 +1034,8 @@ enum mkt_eth_capabilities {
	BIT_ULL(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT)
#define MTK_ETH_MUX_U3_GMAC2_TO_QPHY		\
	BIT_ULL(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT)
#define MTK_ETH_MUX_GMAC2_TO_2P5GPHY		\
	BIT_ULL(MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT)
#define MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII	\
	BIT_ULL(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT)
#define MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII	\
@@ -1021,6 +1047,7 @@ enum mkt_eth_capabilities {
#define MTK_ETH_PATH_GMAC1_SGMII	BIT_ULL(MTK_ETH_PATH_GMAC1_SGMII_BIT)
#define MTK_ETH_PATH_GMAC2_RGMII	BIT_ULL(MTK_ETH_PATH_GMAC2_RGMII_BIT)
#define MTK_ETH_PATH_GMAC2_SGMII	BIT_ULL(MTK_ETH_PATH_GMAC2_SGMII_BIT)
#define MTK_ETH_PATH_GMAC2_2P5GPHY	BIT_ULL(MTK_ETH_PATH_GMAC2_2P5GPHY_BIT)
#define MTK_ETH_PATH_GMAC2_GEPHY	BIT_ULL(MTK_ETH_PATH_GMAC2_GEPHY_BIT)
#define MTK_ETH_PATH_GDM1_ESW		BIT_ULL(MTK_ETH_PATH_GDM1_ESW_BIT)

@@ -1030,6 +1057,7 @@ enum mkt_eth_capabilities {
#define MTK_GMAC2_RGMII		(MTK_ETH_PATH_GMAC2_RGMII | MTK_RGMII)
#define MTK_GMAC2_SGMII		(MTK_ETH_PATH_GMAC2_SGMII | MTK_SGMII)
#define MTK_GMAC2_GEPHY		(MTK_ETH_PATH_GMAC2_GEPHY | MTK_GEPHY)
#define MTK_GMAC2_2P5GPHY	(MTK_ETH_PATH_GMAC2_2P5GPHY | MTK_2P5GPHY)
#define MTK_GDM1_ESW		(MTK_ETH_PATH_GDM1_ESW | MTK_ESW)

/* MUXes present on SoCs */
@@ -1049,6 +1077,10 @@ enum mkt_eth_capabilities {
	(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII | MTK_MUX | \
	MTK_SHARED_SGMII)

/* 2: GMAC2 -> 2P5GPHY */
#define MTK_MUX_GMAC2_TO_2P5GPHY      \
	(MTK_ETH_MUX_GMAC2_TO_2P5GPHY | MTK_MUX | MTK_INFRA)

/* 0: GMACx -> GEPHY, 1: GMACx -> SGMII where x is 1 or 2 */
#define MTK_MUX_GMAC12_TO_GEPHY_SGMII   \
	(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX)
@@ -1084,8 +1116,9 @@ enum mkt_eth_capabilities {
		      MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
		      MTK_RSTCTRL_PPE1 | MTK_SRAM)

#define MT7988_CAPS  (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_QDMA | \
		      MTK_RSTCTRL_PPE1 | MTK_RSTCTRL_PPE2 | MTK_SRAM)
#define MT7988_CAPS  (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC2_2P5GPHY | \
		      MTK_MUX_GMAC2_TO_2P5GPHY | MTK_QDMA | MTK_RSTCTRL_PPE1 | \
		      MTK_RSTCTRL_PPE2 | MTK_SRAM)

struct mtk_tx_dma_desc_info {
	dma_addr_t	addr;
@@ -1437,6 +1470,23 @@ static inline u32 mtk_get_ib2_multicast_mask(struct mtk_eth *eth)
	return MTK_FOE_IB2_MULTICAST;
}

static inline bool mtk_interface_mode_is_xgmii(struct mtk_eth *eth,
					       phy_interface_t interface)
{
	if (!mtk_is_netsys_v3_or_greater(eth))
		return false;

	switch (interface) {
	case PHY_INTERFACE_MODE_INTERNAL:
	case PHY_INTERFACE_MODE_USXGMII:
	case PHY_INTERFACE_MODE_10GBASER:
	case PHY_INTERFACE_MODE_5GBASER:
		return true;
	default:
		return false;
	}
}

/* read the hardware status register */
void mtk_stats_update_mac(struct mtk_mac *mac);

@@ -1445,6 +1495,7 @@ u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
u32 mtk_m32(struct mtk_eth *eth, u32 mask, u32 set, unsigned int reg);

int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id);
int mtk_gmac_2p5gphy_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);