Re: [PATCH 1/4] net: phy: adin1100: Add initial support for ADIN1100 industrial PHY
From: Andrew Lunn <andrew@lunn.ch>
Date: 2021-06-24 17:15:50
Also in:
lkml
+static const int phy_10_features_array[] = {
+ ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+};Since this is a T1 PHY, please add a ETHTOOL_LINK_MODE_10baseT1_Full_BIT definition, and use that. It looks like the device also supports half duplex? So add ETHTOOL_LINK_MODE_10baseT1_Half_BIT as well. What does genphy_read_abilities() determine for this device? Is there a standardized way to detect 10BaseT1?
+
+#define ADIN_B10L_PCS_CNTRL 0x08e6
+#define ADIN_PCS_CNTRL_B10L_LB_PCS_EN BIT(14)
+
+#define ADIN_B10L_PMA_CNTRL 0x08f6
+#define ADIN_PMA_CNTRL_B10L_LB_PMA_LOC_EN BIT(0)
+
+#define ADIN_B10L_PMA_STAT 0x08f7
+#define ADIN_PMA_STAT_B10L_LB_PMA_LOC_ABLE BIT(13)
+#define ADIN_PMA_STAT_B10L_TX_LVL_HI_ABLE BIT(12)
+
+#define ADIN_AN_CONTROL 0x0200
+#define ADIN_AN_RESTART BIT(9)
+#define ADIN_AN_EN BIT(12)
+
+#define ADIN_AN_STATUS 0x0201
+#define ADIN_AN_ADV_ABILITY_L 0x0202
+#define ADIN_AN_ADV_ABILITY_M 0x0203
+#define ADIN_AN_ADV_ABILITY_H 0x0204U
+#define ADIN_AN_ADV_B10L_TX_LVL_HI_ABL BIT(13)
+#define ADIN_AN_ADV_B10L_TX_LVL_HI_REQ BIT(12)
+
+#define ADIN_AN_LP_ADV_ABILITY_L 0x0205
+
+#define ADIN_AN_LP_ADV_ABILITY_M 0x0206
+#define ADIN_AN_LP_ADV_B10L BIT(14)
+#define ADIN_AN_LP_ADV_B1000 BIT(7)
+#define ADIN_AN_LP_ADV_B10S_FD BIT(6)
+#define ADIN_AN_LP_ADV_B100 BIT(5)
+#define ADIN_AN_LP_ADV_MST BIT(4)
+
+#define ADIN_AN_LP_ADV_ABILITY_H 0x0207
+#define ADIN_AN_LP_ADV_B10L_EEE BIT(14)
+#define ADIN_AN_LP_ADV_B10L_TX_LVL_HI_ABL BIT(13)
+#define ADIN_AN_LP_ADV_B10L_TX_LVL_HI_REQ BIT(12)
+#define ADIN_AN_LP_ADV_B10S_HD BIT(11)
+
+#define ADIN_CRSM_SFT_RST 0x8810
+#define ADIN_CRSM_SFT_RST_EN BIT(0)
+
+#define ADIN_CRSM_SFT_PD_CNTRL 0x8812
+#define ADIN_CRSM_SFT_PD_CNTRL_EN BIT(0)
+
+#define ADIN_CRSM_STAT 0x8818
+#define ADIN_CRSM_SFT_PD_RDY BIT(1)
+#define ADIN_CRSM_SYS_RDY BIT(0)
+
+#define ADIN_MAC_IF_LOOPBACK 0x803d
+#define ADIN_MAC_IF_LOOPBACK_EN BIT(0)
+#define ADIN_MAC_IF_REMOTE_LOOPBACK_EN BIT(2)
+
+/**
+ * struct adin_priv - ADIN PHY driver private data
+ * tx_level_24v set if the PHY supports 2.4V TX levels (10BASE-T1L)
+ */
+struct adin_priv {
+ unsigned int tx_level_24v:1;
+};
++static int adin_match_phy_device(struct phy_device *phydev)
+{
+ struct mii_bus *bus = phydev->mdio.bus;
+ int phy_addr = phydev->mdio.addr;
+ u32 id;
+ int rc;
+
+ mutex_lock(&bus->mdio_lock);
+
+ /* Need to call __mdiobus_read() directly here, because at this point
+ * in time, the driver isn't attached to the PHY device.
+ */
+ rc = __mdiobus_read(bus, phy_addr, MDIO_DEVID1);
+ if (rc < 0) {
+ mutex_unlock(&bus->mdio_lock);
+ return rc;
+ }
+
+ id = rc << 16;
+
+ rc = __mdiobus_read(bus, phy_addr, MDIO_DEVID2);
+ mutex_unlock(&bus->mdio_lock);
+
+ if (rc < 0)
+ return rc;
+
+ id |= rc;
+
+ switch (id) {
+ case PHY_ID_ADIN1100:
+ return 1;
+ default:
+ return 0;
+ }
+}I must be missing something here. Why do you need this?
+static void adin_mii_adv_m_to_ethtool_adv_t(unsigned long *advertising, u32 adv)
+{
+ if (adv & ADIN_AN_LP_ADV_B10L)
+ linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, advertising);
+ if (adv & ADIN_AN_LP_ADV_B1000) {
+ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertising);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertising);
+ }
+ if (adv & ADIN_AN_LP_ADV_B10S_FD)
+ linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, advertising);
+ if (adv & ADIN_AN_LP_ADV_B100)
+ linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, advertising);Since this is a T1 PHY, i assume these are all T1 link modes? Please use ETHTOOL_LINK_MODE_1000baseT1_Half_BIT, ETHTOOL_LINK_MODE_100baseT1_Full_BIT, etc.
+static void adin_link_change_notify(struct phy_device *phydev)
+{
+ bool tx_level_24v;
+ bool lp_tx_level_24v;
+ int val, mask;
+
+ if (phydev->state != PHY_RUNNING || phydev->autoneg == AUTONEG_DISABLE)
+ return;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, ADIN_AN_LP_ADV_ABILITY_H);
+ if (val < 0)
+ return;
+
+ mask = ADIN_AN_LP_ADV_B10L_TX_LVL_HI_ABL | ADIN_AN_LP_ADV_B10L_TX_LVL_HI_REQ;
+ lp_tx_level_24v = (val & mask) == mask;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, ADIN_AN_ADV_ABILITY_H);
+ if (val < 0)
+ return;
+
+ mask = ADIN_AN_ADV_B10L_TX_LVL_HI_ABL | ADIN_AN_ADV_B10L_TX_LVL_HI_REQ;
+ tx_level_24v = (val & mask) == mask;
+
+ if (tx_level_24v && lp_tx_level_24v)
+ phydev_info(phydev, "Negotiated 2.4V TX level\n");
+ else
+ phydev_info(phydev, "Negotiated 1.0V TX level\n");>We have ETHTOOL_LINK_MODE_Autoneg_BIT to indicate autoneg is supported. Maybe we should add ETHTOOL_LINK_MODE_2400mv_BIT? Are there other voltages defined in the standards?
+static int adin_set_powerdown_mode(struct phy_device *phydev, bool en)
+{
+ int ret, timeout;
+ u16 val;
+
+ if (en)
+ val = ADIN_CRSM_SFT_PD_CNTRL_EN;
+ else
+ val = 0;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ ADIN_CRSM_SFT_PD_CNTRL, val);
+ if (ret < 0)
+ return ret;
+
+ timeout = 30;
+ while (timeout-- > 0) {
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+ ADIN_CRSM_STAT);
+ if (ret < 0)
+ return ret;
+
+ if ((ret & ADIN_CRSM_SFT_PD_RDY) == val)
+ return 0;
+
+ mdelay(1);
+ }
+
+ return -ETIMEDOUT;We already have phy_read_poll_timeout(). Please add a phy_read_mmd_poll_timeout() function.
+static int adin_set_loopback(struct phy_device *phydev, bool enable)
+{
+ int ret;
+
+ if (enable)
+ return phy_set_bits_mmd(phydev, MDIO_MMD_PCS,
+ ADIN_B10L_PCS_CNTRL,
+ ADIN_PCS_CNTRL_B10L_LB_PCS_EN);
+
+ /* MAC interface block loopback */
+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, ADIN_MAC_IF_LOOPBACK,
+ ADIN_MAC_IF_LOOPBACK_EN |
+ ADIN_MAC_IF_REMOTE_LOOPBACK_EN);
+ if (ret < 0)
+ return ret;
+
+ /* PCS loopback (according to 10BASE-T1L spec) */
+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, ADIN_B10L_PCS_CNTRL,
+ ADIN_PCS_CNTRL_B10L_LB_PCS_EN);
+ if (ret < 0)
+ return ret;
+
+ /* PMA loopback (according to 10BASE-T1L spec) */
+ return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, ADIN_B10L_PMA_CNTRL,
+ ADIN_PMA_CNTRL_B10L_LB_PMA_LOC_EN);
Why three loopbacks at the same time. The outgoing frame it going to
hit the first loopback, and never reach the other two.
Andrew