[PATCH net-next v4 5/6] net: phy: mediatek: add calibration logic for AN7581

Andrew Lunn andrew at lunn.ch
Thu Nov 5 14:47:26 PST 2026


> +static int airoha_cal_cycle(struct phy_device *phydev, int devad,
> +			    u32 regnum, u16 mask, u16 cal_val)
> +{
> +	struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
> +	struct phy_device *phydev_p0;
> +	int ret;
> +
> +	phydev_p0 = shared->phydev_p0;
> +
> +	phy_modify_mmd(phydev, devad, regnum, mask, cal_val);
> +
> +	ret = mtk_cal_cycle_wait(phydev_p0);


> +static int airoha_rext_cal_sw(struct phy_device *phydev)
> +{

...

> +	phydev_dbg(phydev, "Start REXT SW cal.\n");
> +	first_calib = airoha_cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
> +				       MTK_PHY_RG_REXT_ZCAL_CTRL_MASK, zcal_ctrl);
> +

> +static int airoha_cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
> +			 u8 start_pair, u8 end_pair)
> +{
> +	u8 pair_n;
> +	int ret;
> +
> +	for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
> +		switch (cal_item) {
> +		case REXT:
> +			ret = airoha_rext_cal_sw(phydev);
> +			break;

> +static int airoha_start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
> +			    enum CAL_MODE cal_mode, u8 start_pair,
> +			    u8 end_pair, u32 *buf)
> +{
> +	int ret;
> +
> +	switch (cal_mode) {
> +	case SW_M:
> +		ret = airoha_cal_sw(phydev, cal_item, start_pair, end_pair);


> +static int airoha_phy_calib(struct phy_device *phydev)
> +{
> +	phy_package_lock(phydev);
> +	if (!shared->rext_sw_calib_done) {
> +		ret = airoha_start_cal(phydev, REXT, SW_M, NO_PAIR, NO_PAIR, NULL);
> +		if (ret) {
> +			phy_package_unlock(phydev);
> +			return ret;
> +		}
> +
> +		shared->rext_sw_calib_done = true;
> +	}
> +	phy_package_unlock(phydev);
> +
> +	ret = airoha_start_cal(phydev, TX_R50, SW_M, PAIR_A, PAIR_D, NULL);


> +static int an7581_phy_config_init(struct phy_device *phydev)
> +{
> +	struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
> +	struct phy_device *phydev_p0;
> +	u8 phy_offset;
> +	int oldpage;
> +	int ret;
> +
> +	phydev_p0 = shared->phydev_p0;
> +	phy_offset = phydev->mdio.addr - phydev_p0->mdio.addr;
> +
> +	if (phy_package_init_once(phydev)) {
> +		ret = an7581_phy_package_config_init_once(phydev);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = airoha_phy_calib(phydev);

> @@ -88,6 +1610,7 @@ static struct phy_driver mtk_socphy_driver[] = {
>  	{
>  		PHY_ID_MATCH_EXACT(AIROHA_GPHY_ID_AN7581),
>  		.name		= "Airoha AN7581 PHY",
> +		.config_init	= an7581_phy_config_init,

> > There are 4 phys in total, only the phy with mdio address 9 has the
> > calibration capability. Thus only one phy at the time can perform
> > the calibration sequence.

config_init -> airoha_phy_calib -> airoha_start_cal -> airoha_cal_sw
-> airoha_cal_cycle

I cannot say i looked at all the details closely, maybe i missed an ==
9 somewhere, but to me, it looks like two config_init can run in
parallel.

	Andrew



More information about the linux-arm-kernel mailing list