[][kernel][common][eth][Add phylink_pcs support for the SGMII/USXGMII]

[Description]
Add phylink_pcs support for the SGMII/USXGMII.

If without this patch, phylink framework cannot configure MAC and PCS
properly for the inband mode.

[Release-log]
N/A


Change-Id: I6cda355eeb2abb3c90a9120f3b77b3721200dc81
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7353960
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 134e579..1368a7b 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -500,6 +500,34 @@
 		mtk_w32(eth, mcr, MTK_MAC_MCR(mac->id));
 }
 
+static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config,
+					      phy_interface_t interface)
+{
+	struct mtk_mac *mac = container_of(config, struct mtk_mac,
+					   phylink_config);
+	struct mtk_eth *eth = mac->hw;
+	unsigned int sid;
+
+	if (interface == PHY_INTERFACE_MODE_SGMII ||
+	    phy_interface_mode_is_8023z(interface)) {
+		sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ?
+		       0 : mtk_mac2xgmii_id(eth, mac->id);
+
+		return mtk_sgmii_select_pcs(eth->sgmii, sid);
+	} else if (interface == PHY_INTERFACE_MODE_USXGMII ||
+		   interface == PHY_INTERFACE_MODE_10GKR ||
+		   interface == PHY_INTERFACE_MODE_5GBASER) {
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3) &&
+		    mac->id != MTK_GMAC1_ID) {
+			sid = mtk_mac2xgmii_id(eth, mac->id);
+
+			return mtk_usxgmii_select_pcs(eth->usxgmii, sid);
+		}
+	}
+
+	return NULL;
+}
+
 static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
 			   const struct phylink_link_state *state)
 {
@@ -649,38 +677,13 @@
 		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->xgmii, sid,
-							 state);
-		else
-			err = mtk_sgmii_setup_mode_an(eth->xgmii, sid);
-
-		if (err) {
-			spin_unlock(&eth->syscfg0_lock);
-			goto init_err;
-		}
-
-		regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
-				   SYSCFG0_SGMII_MASK, val);
+		/* Save the syscfg0 value for mac_finish */
+		mac->syscfg0 = val;
 		spin_unlock(&eth->syscfg0_lock);
 	} else if (state->interface == PHY_INTERFACE_MODE_USXGMII ||
 		   state->interface == PHY_INTERFACE_MODE_10GKR ||
 		   state->interface == PHY_INTERFACE_MODE_5GBASER) {
-		sid = mac->id;
-
-		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3) &&
-		    sid != MTK_GMAC1_ID) {
-			if (phylink_autoneg_inband(mode))
-				err = mtk_usxgmii_setup_mode_force(eth->xgmii, sid,
-								   state);
-			else
-				err = mtk_usxgmii_setup_mode_an(eth->xgmii, sid,
-								SPEED_10000);
-
-			if (err)
-				goto init_err;
-		}
+		/* Nothing to do */
 	} else if (phylink_autoneg_inband(mode)) {
 		dev_err(eth->dev,
 			"In-band mode not supported in non SGMII mode!\n");
@@ -730,6 +733,10 @@
 			}
 		}
 
+		/* FIXME: In current hardware design, we have to reset FE
+		 * when swtiching XGDM to GDM. Therefore, here trigger an SER
+		 * to let GDM go back to the initial state.
+		 */
 		if (mac->type != mac_type) {
 			if (atomic_read(&reset_pending) == 0) {
 				atomic_inc(&force);
@@ -752,6 +759,22 @@
 		mac->id, phy_modes(state->interface), err);
 }
 
+static int mtk_mac_finish(struct phylink_config *config, unsigned int mode,
+			  phy_interface_t interface)
+{
+	struct mtk_mac *mac = container_of(config, struct mtk_mac,
+					   phylink_config);
+	struct mtk_eth *eth = mac->hw;
+
+	/* Enable SGMII */
+	if (interface == PHY_INTERFACE_MODE_SGMII ||
+	    phy_interface_mode_is_8023z(interface))
+		regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
+				   SYSCFG0_SGMII_MASK, mac->syscfg0);
+
+	return 0;
+}
+
 static int mtk_mac_pcs_get_state(struct phylink_config *config,
 				 struct phylink_link_state *state)
 {
@@ -764,7 +787,7 @@
 		if (mac->id == MTK_GMAC2_ID)
 			sts = sts >> 16;
 
-		state->duplex = 1;
+		state->duplex = DUPLEX_FULL;
 
 		switch (FIELD_GET(MTK_USXGMII_PCS_MODE, sts)) {
 		case 0:
@@ -785,18 +808,19 @@
 		state->link = FIELD_GET(MTK_USXGMII_PCS_LINK, sts);
 	} else if (mac->type == MTK_GDM_TYPE) {
 		struct mtk_eth *eth = mac->hw;
-		struct mtk_xgmii *ss = eth->xgmii;
+		struct mtk_sgmii *ss = eth->sgmii;
 		u32 id = mtk_mac2xgmii_id(eth, mac->id);
 		u32 pmsr = mtk_r32(mac->hw, MTK_MAC_MSR(mac->id));
-		u32 val = 0;
+		u32 rgc3, val = 0;
 
-		regmap_read(ss->regmap_sgmii[id], SGMSYS_PCS_CONTROL_1, &val);
+		regmap_read(ss->pcs[id].regmap, SGMSYS_PCS_CONTROL_1, &val);
 
 		state->interface = mac->interface;
 		state->link = FIELD_GET(SGMII_LINK_STATYS, val);
 
 		if (FIELD_GET(SGMII_AN_ENABLE, val)) {
-			regmap_read(ss->regmap_sgmii[id], SGMII_PCS_SPEED_ABILITY, &val);
+			regmap_read(ss->pcs[id].regmap,
+				    SGMII_PCS_SPEED_ABILITY, &val);
 
 			val = val >> 16;
 
@@ -814,9 +838,10 @@
 				break;
 			}
 		} else {
-			regmap_read(ss->regmap_sgmii[id], SGMSYS_SGMII_MODE, &val);
+			regmap_read(ss->pcs[id].regmap,
+				    SGMSYS_SGMII_MODE, &val);
 
-			state->duplex = !FIELD_GET(SGMII_DUPLEX_FULL, val);
+			state->duplex = !FIELD_GET(SGMII_DUPLEX_HALF, val);
 
 			switch (FIELD_GET(SGMII_SPEED_MASK, val)) {
 			case 0:
@@ -826,8 +851,10 @@
 				state->speed = SPEED_100;
 				break;
 			case 2:
-				regmap_read(ss->regmap_sgmii[id], ss->ana_rgc3, &val);
-				state->speed = (FIELD_GET(RG_PHY_SPEED_3_125G, val)) ? SPEED_2500 : SPEED_1000;
+				regmap_read(ss->pcs[id].regmap,
+					    ss->pcs[id].ana_rgc3, &val);
+				rgc3 = FIELD_GET(RG_PHY_SPEED_3_125G, val);
+				state->speed = rgc3 ? SPEED_2500 : SPEED_1000;
 				break;
 			}
 		}
@@ -842,15 +869,6 @@
 	return 1;
 }
 
-static void mtk_mac_an_restart(struct phylink_config *config)
-{
-	struct mtk_mac *mac = container_of(config, struct mtk_mac,
-					   phylink_config);
-
-	if (mac->type != MTK_XGDM_TYPE)
-		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)
 {
@@ -1074,9 +1092,10 @@
 
 static const struct phylink_mac_ops mtk_phylink_ops = {
 	.validate = mtk_validate,
+	.mac_select_pcs = mtk_mac_select_pcs,
 	.mac_link_state = mtk_mac_pcs_get_state,
-	.mac_an_restart = mtk_mac_an_restart,
 	.mac_config = mtk_mac_config,
+	.mac_finish = mtk_mac_finish,
 	.mac_link_down = mtk_mac_link_down,
 	.mac_link_up = mtk_mac_link_up,
 };
@@ -3397,6 +3416,7 @@
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	struct mtk_phylink_priv *phylink_priv = &mac->phylink_priv;
+	u32 id = mtk_mac2xgmii_id(eth, mac->id);
 	int err, i;
 	struct device_node *phy_node;
 
@@ -3472,8 +3492,9 @@
 	phylink_start(mac->phylink);
 	netif_start_queue(dev);
 	phy_node = of_parse_phandle(mac->of_node, "phy-handle", 0);
-	if (!phy_node && eth->xgmii->regmap_sgmii[mac->id])
-		regmap_write(eth->xgmii->regmap_sgmii[mac->id], SGMSYS_QPHY_PWR_STATE_CTRL, 0);
+	if (!phy_node && eth->sgmii->pcs[id].regmap)
+		regmap_write(eth->sgmii->pcs[id].regmap,
+			     SGMSYS_QPHY_PWR_STATE_CTRL, 0);
 
 	mtk_gdm_config(eth, mac->id, MTK_GDMA_TO_PDMA);
 
@@ -3508,6 +3529,7 @@
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	int i;
+	u32 id = mtk_mac2xgmii_id(eth, mac->id);
 	u32 val = 0;
 	struct device_node *phy_node;
 
@@ -3515,10 +3537,12 @@
 	netif_tx_disable(dev);
 
 	phy_node = of_parse_phandle(mac->of_node, "phy-handle", 0);
-	if (!phy_node && eth->xgmii->regmap_sgmii[mac->id]) {
-		regmap_read(eth->xgmii->regmap_sgmii[mac->id], SGMSYS_QPHY_PWR_STATE_CTRL, &val);
+	if (!phy_node && eth->sgmii->pcs[id].regmap) {
+		regmap_read(eth->sgmii->pcs[id].regmap,
+			    SGMSYS_QPHY_PWR_STATE_CTRL, &val);
 		val |= SGMII_PHYA_PWD;
-		regmap_write(eth->xgmii->regmap_sgmii[mac->id], SGMSYS_QPHY_PWR_STATE_CTRL, val);
+		regmap_write(eth->sgmii->pcs[id].regmap,
+			     SGMSYS_QPHY_PWR_STATE_CTRL, val);
 	}
 
 	//GMAC RX disable
@@ -4589,29 +4613,24 @@
 	}
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
-		eth->xgmii = devm_kzalloc(eth->dev, sizeof(*eth->xgmii),
+		eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii),
 					  GFP_KERNEL);
-		if (!eth->xgmii)
+		if (!eth->sgmii)
 			return -ENOMEM;
 
-		eth->xgmii->eth = eth;
-		err = mtk_sgmii_init(eth->xgmii, pdev->dev.of_node,
+		err = mtk_sgmii_init(eth, pdev->dev.of_node,
 				     eth->soc->ana_rgc3);
-
 		if (err)
 			return err;
 	}
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_USXGMII)) {
-		err = mtk_usxgmii_init(eth->xgmii, pdev->dev.of_node);
-		if (err)
-			return err;
-
-		err = mtk_xfi_pextp_init(eth->xgmii, pdev->dev.of_node);
-		if (err)
-			return err;
+		eth->usxgmii = devm_kzalloc(eth->dev, sizeof(*eth->usxgmii),
+					    GFP_KERNEL);
+		if (!eth->usxgmii)
+			return -ENOMEM;
 
-		err = mtk_xfi_pll_init(eth->xgmii, pdev->dev.of_node);
+		err = mtk_usxgmii_init(eth, pdev->dev.of_node);
 		if (err)
 			return err;