Re: [PATCH v2 net-next 2/2] net: phy: air_en8811h: Add the Airoha EN8811H PHY driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> +static int en8811h_config_init(struct phy_device *phydev)
> +{
> +	struct en8811h_priv *priv = phydev->priv;
> +	struct device *dev = &phydev->mdio.dev;
> +	int ret, pollret, reg_value;
> +	u32 pbus_value;
> +
> +	if (!priv->firmware_version)
> +		ret = en8811h_load_firmware(phydev);

How long does this take for your hardware?

We have a phylib design issue with loading firmware. It would be
better if it happened during probe, but it might not be finished by
the time the MAC driver tries to attach to the PHY and so that fails.
This is the second PHY needing this, so maybe we need to think about
adding a thread kicked off in probe to download the firmware? But
probably later, not part of this patchset.

> +	else
> +		ret = en8811h_restart_host(phydev);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Because of mdio-lock, may have to wait for multiple loads */
> +	pollret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
> +					    EN8811H_PHY_FW_STATUS, reg_value,
> +					    reg_value == EN8811H_PHY_READY,
> +					    20000, 7500000, true);
> +
> +	ret = air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, &pbus_value);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (pollret || !pbus_value) {
> +		phydev_err(phydev, "Firmware not ready: 0x%x\n", reg_value);
> +		return -ENODEV;
> +	}
> +
> +	if (!priv->firmware_version) {
> +		phydev_info(phydev, "MD32 firmware version: %08x\n", pbus_value);
> +		priv->firmware_version = pbus_value;
> +	}
> +
> +	/* Select mode 1, the only mode supported */

Maybe a comment about what mode 1 actually is?

> +	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_1,
> +			    AIR_PHY_HOST_CMD_1_MODE1);
> +	if (ret < 0)
> +		return ret;
> +	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_2,
> +			    AIR_PHY_HOST_CMD_2_MODE1);
> +	if (ret < 0)
> +		return ret;
> +	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_3,
> +			    AIR_PHY_HOST_CMD_3_MODE1);
> +	if (ret < 0)
> +		return ret;
> +	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_HOST_CMD_4,
> +			    AIR_PHY_HOST_CMD_4_MODE1);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Serdes polarity */
> +	pbus_value = 0;
> +	if (device_property_read_bool(dev, "airoha,pnswap-rx"))
> +		pbus_value |=  EN8811H_POLARITY_RX_REVERSE;
> +	else
> +		pbus_value &= ~EN8811H_POLARITY_RX_REVERSE;
> +	if (device_property_read_bool(dev, "airoha,pnswap-tx"))
> +		pbus_value &= ~EN8811H_POLARITY_TX_NORMAL;
> +	else
> +		pbus_value |=  EN8811H_POLARITY_TX_NORMAL;
> +	ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
> +				      EN8811H_POLARITY_RX_REVERSE |
> +				      EN8811H_POLARITY_TX_NORMAL, pbus_value);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR,
> +			    AIR_LED_MODE_USER_DEFINE);
> +	if (ret < 0) {
> +		phydev_err(phydev, "Failed to initialize leds: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = air_buckpbus_reg_modify(phydev, EN8811H_GPIO_OUTPUT,
> +				      EN8811H_GPIO_OUTPUT_345,
> +				      EN8811H_GPIO_OUTPUT_345);

What does this do? Configure them as inputs? Hopefully they are inputs
by default, or at least Hi-Z.

> +static int en8811h_get_features(struct phy_device *phydev)
> +{
> +	linkmode_set_bit_array(phy_basic_ports_array,
> +			       ARRAY_SIZE(phy_basic_ports_array),
> +			       phydev->supported);
> +
> +	return genphy_c45_pma_read_abilities(phydev);
> +}
> +

> +static int en8811h_config_aneg(struct phy_device *phydev)
> +{
> +	bool changed = false;
> +	int ret;
> +	u32 adv;
> +
> +	adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);
> +
> +	ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
> +				     MDIO_AN_10GBT_CTRL_ADV2_5G, adv);
> +	if (ret < 0)
> +		return ret;
> +	if (ret > 0)
> +		changed = true;
> +
> +	return __genphy_config_aneg(phydev, changed);

There was a comment that it does not support forced link mode, only
auto-neg? It would be good to test the configuration here and return
EOPNOTSUPP, or EINVAL if auto-neg is turned off.

> +}
> +
> +static int en8811h_read_status(struct phy_device *phydev)
> +{
> +	struct en8811h_priv *priv = phydev->priv;
> +	u32 pbus_value;
> +	int ret, val;
> +
> +	ret = genphy_update_link(phydev);
> +	if (ret)
> +		return ret;
> +
> +	phydev->master_slave_get = MASTER_SLAVE_CFG_UNSUPPORTED;
> +	phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED;
> +	phydev->speed = SPEED_UNKNOWN;
> +	phydev->duplex = DUPLEX_UNKNOWN;
> +	phydev->pause = 0;
> +	phydev->asym_pause = 0;
> +
> +	ret = genphy_read_master_slave(phydev);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = genphy_read_lpa(phydev);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Get link partner 2.5GBASE-T ability from vendor register */
> +	ret = air_buckpbus_reg_read(phydev, EN8811H_2P5G_LPA, &pbus_value);
> +	if (ret < 0)
> +		return ret;
> +	linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
> +			 phydev->lp_advertising,
> +			 pbus_value & EN8811H_2P5G_LPA_2P5G);
> +
> +	if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)

Is the first part of that expression needed? I thought you could not
turn auto-neg off?

> +
> +	/* Only supports full duplex */
> +	phydev->duplex = DUPLEX_FULL;

What does en8811h_get_features() indicate the PHY can do? Are any 1/2
duplex modes listed?

       Andrew




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux