Commit 9983a2c9 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'fixes-for-mtk_eth_soc'

Bjørn Mork says:

====================
Fix mtk_eth_soc sgmii configuration.

This has been tested on a MT7986 with a Maxlinear GPY211C phy
permanently attached to the second SoC mac.
====================

Link: https://lore.kernel.org/r/20230201182331.943411-1-bjorn@mork.no


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents b0de13d3 3337a6e0
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -519,7 +519,7 @@
#define SGMII_SPEED_10			FIELD_PREP(SGMII_SPEED_MASK, 0)
#define SGMII_SPEED_100			FIELD_PREP(SGMII_SPEED_MASK, 1)
#define SGMII_SPEED_1000		FIELD_PREP(SGMII_SPEED_MASK, 2)
#define SGMII_DUPLEX_FULL		BIT(4)
#define SGMII_DUPLEX_HALF		BIT(4)
#define SGMII_IF_MODE_BIT5		BIT(5)
#define SGMII_REMOTE_FAULT_DIS		BIT(8)
#define SGMII_CODE_SYNC_SET_VAL		BIT(9)
@@ -1036,11 +1036,13 @@ struct mtk_soc_data {
 * @regmap:            The register map pointing at the range used to setup
 *                     SGMII modes
 * @ana_rgc3:          The offset refers to register ANA_RGC3 related to regmap
 * @interface:         Currently configured interface mode
 * @pcs:               Phylink PCS structure
 */
struct mtk_pcs {
	struct regmap	*regmap;
	u32             ana_rgc3;
	phy_interface_t	interface;
	struct phylink_pcs pcs;
};

+32 −14
Original line number Diff line number Diff line
@@ -43,11 +43,6 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
	int advertise, link_timer;
	bool changed, use_an;

	if (interface == PHY_INTERFACE_MODE_2500BASEX)
		rgc3 = RG_PHY_SPEED_3_125G;
	else
		rgc3 = 0;

	advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
							     advertising);
	if (advertise < 0)
@@ -88,10 +83,23 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
		bmcr = 0;
	}

	if (mpcs->interface != interface) {
		/* PHYA power down */
		regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
				   SGMII_PHYA_PWD, SGMII_PHYA_PWD);

		if (interface == PHY_INTERFACE_MODE_2500BASEX)
			rgc3 = RG_PHY_SPEED_3_125G;
		else
			rgc3 = 0;

		/* Configure the underlying interface speed */
		regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
				   RG_PHY_SPEED_3_125G, rgc3);

		mpcs->interface = interface;
	}

	/* Update the advertisement, noting whether it has changed */
	regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE,
				 SGMII_ADVERTISE, advertise, &changed);
@@ -108,9 +116,17 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
	regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1,
			   SGMII_AN_RESTART | SGMII_AN_ENABLE, bmcr);

	/* Release PHYA power down state */
	regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
			   SGMII_PHYA_PWD, 0);
	/* Release PHYA power down state
	 * Only removing bit SGMII_PHYA_PWD isn't enough.
	 * There are cases when the SGMII_PHYA_PWD register contains 0x9 which
	 * prevents SGMII from working. The SGMII still shows link but no traffic
	 * can flow. Writing 0x0 to the PHYA_PWD register fix the issue. 0x0 was
	 * taken from a good working state of the SGMII interface.
	 * Unknown how much the QPHY needs but it is racy without a sleep.
	 * Tested on mt7622 & mt7986.
	 */
	usleep_range(50, 100);
	regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);

	return changed;
}
@@ -138,11 +154,11 @@ static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
		else
			sgm_mode = SGMII_SPEED_1000;

		if (duplex == DUPLEX_FULL)
			sgm_mode |= SGMII_DUPLEX_FULL;
		if (duplex != DUPLEX_FULL)
			sgm_mode |= SGMII_DUPLEX_HALF;

		regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
				   SGMII_DUPLEX_FULL | SGMII_SPEED_MASK,
				   SGMII_DUPLEX_HALF | SGMII_SPEED_MASK,
				   sgm_mode);
	}
}
@@ -171,6 +187,8 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3)
			return PTR_ERR(ss->pcs[i].regmap);

		ss->pcs[i].pcs.ops = &mtk_pcs_ops;
		ss->pcs[i].pcs.poll = true;
		ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
	}

	return 0;