diff --git a/drivers/net/phy/aquantia/aquantia.h b/drivers/net/phy/aquantia/aquantia.h index 3fc7044bcdc7..2911965f0868 100644 --- a/drivers/net/phy/aquantia/aquantia.h +++ b/drivers/net/phy/aquantia/aquantia.h @@ -153,6 +153,24 @@ #define AQR_MAX_LEDS 3 +/* Custom driver definitions for constructing a single variable out of + * aggregate firmware build information. These do not represent hardware + * fields. + */ +#define AQR_FW_FINGERPRINT_MAJOR GENMASK_ULL(63, 56) +#define AQR_FW_FINGERPRINT_MINOR GENMASK_ULL(55, 48) +#define AQR_FW_FINGERPRINT_BUILD_ID GENMASK_ULL(47, 40) +#define AQR_FW_FINGERPRINT_PROV_ID GENMASK_ULL(39, 32) +#define AQR_FW_FINGERPRINT_MISC_ID GENMASK_ULL(31, 16) +#define AQR_FW_FINGERPRINT_MISC_VER GENMASK_ULL(15, 0) +#define AQR_FW_FINGERPRINT(major, minor, build_id, prov_id, misc_id, misc_ver) \ + (FIELD_PREP(AQR_FW_FINGERPRINT_MAJOR, major) | \ + FIELD_PREP(AQR_FW_FINGERPRINT_MINOR, minor) | \ + FIELD_PREP(AQR_FW_FINGERPRINT_BUILD_ID, build_id) | \ + FIELD_PREP(AQR_FW_FINGERPRINT_PROV_ID, prov_id) | \ + FIELD_PREP(AQR_FW_FINGERPRINT_MISC_ID, misc_id) | \ + FIELD_PREP(AQR_FW_FINGERPRINT_MISC_VER, misc_ver)) + struct aqr107_hw_stat { const char *name; int reg; @@ -203,6 +221,7 @@ struct aqr_global_syscfg { struct aqr107_priv { u64 sgmii_stats[AQR107_SGMII_STAT_SZ]; + u64 fingerprint; unsigned long leds_active_low; unsigned long leds_active_high; bool wait_on_global_cfg; @@ -216,6 +235,7 @@ static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; } #endif int aqr_firmware_load(struct phy_device *phydev); +int aqr_firmware_read_fingerprint(struct phy_device *phydev); int aqr_phy_led_blink_set(struct phy_device *phydev, u8 index, unsigned long *delay_on, diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index a9bd35b3be4b..5fbf392a84b2 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -88,6 +88,9 @@ #define MDIO_AN_TX_VEND_INT_MASK2 0xd401 #define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0) +#define PMAPMD_FW_MISC_ID 0xc41d +#define PMAPMD_FW_MISC_VER 0xc41e + #define PMAPMD_RSVD_VEND_PROV 0xe400 #define PMAPMD_RSVD_VEND_PROV_MDI_CONF GENMASK(1, 0) #define PMAPMD_RSVD_VEND_PROV_MDI_REVERSE BIT(0) @@ -677,27 +680,46 @@ int aqr_wait_reset_complete(struct phy_device *phydev) return ret; } -static void aqr107_chip_info(struct phy_device *phydev) +static int aqr_build_fingerprint(struct phy_device *phydev) { u8 fw_major, fw_minor, build_id, prov_id; + struct aqr107_priv *priv = phydev->priv; + u16 misc_id, misc_ver; int val; val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID); if (val < 0) - return; + return val; fw_major = FIELD_GET(VEND1_GLOBAL_FW_ID_MAJOR, val); fw_minor = FIELD_GET(VEND1_GLOBAL_FW_ID_MINOR, val); val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT1); if (val < 0) - return; + return val; build_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID, val); prov_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_PROV_ID, val); - phydev_dbg(phydev, "FW %u.%u, Build %u, Provisioning %u\n", - fw_major, fw_minor, build_id, prov_id); + val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_FW_MISC_ID); + if (val < 0) + return val; + + misc_id = val; + + val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_FW_MISC_VER); + if (val < 0) + return val; + + misc_ver = val; + + priv->fingerprint = AQR_FW_FINGERPRINT(fw_major, fw_minor, build_id, + prov_id, misc_id, misc_ver); + + phydev_dbg(phydev, "FW %u.%u, Build %u, Provisioning %u, Misc ID %u, Version %u\n", + fw_major, fw_minor, build_id, prov_id, misc_id, misc_ver); + + return 0; } static int aqr107_config_mdi(struct phy_device *phydev) @@ -745,8 +767,14 @@ static int aqr_gen1_config_init(struct phy_device *phydev) "Your devicetree is out of date, please update it. The AQR107 family doesn't support XGMII, maybe you mean USXGMII.\n"); ret = aqr_wait_reset_complete(phydev); - if (!ret) - aqr107_chip_info(phydev); + if (!ret) { + /* The PHY might work without a firmware image, so only build a + * fingerprint if the firmware was initialized. + */ + ret = aqr_build_fingerprint(phydev); + if (ret) + return ret; + } ret = aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT); if (ret)