@@ -633,6 +729,1048 @@ static int ytphy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
return phy_restore_page(phydev, old_page, ret);
}
+/**
+ * yt8824_read_page() - read PHY8824 reg page
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * Returns: current reg space of yt8824 (YT8824_RSSR_USXGMII_SPACE/
+ * YT8824_RSSR_UTP_SPACE) or negative errno code
+ */
+static int yt8824_read_page(struct phy_device *phydev)
+{
+ int old_page;
+
+ old_page = ytphy_read_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG);
+ if (old_page < 0)
+ return old_page;
+
+ return old_page & YT8824_RSSR_SPACE_MASK;
+};
+
+/**
+ * yt8824_write_page() - write reg page
+ * @phydev: a pointer to a &struct phy_device
+ * @page: Reg page(YT8824_RSSR_USXGMII_SPACE/YT8824_RSSR_UTP_SPACE) to write.
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_write_page(struct phy_device *phydev, int page)
+{
+ int old_page;
+ u16 data;
+
+ old_page = ytphy_read_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG);
+ if (old_page < 0)
+ return old_page;
+ data = old_page & (~YT8824_RSSR_SPACE_MASK);
+ data |= page;
+
+ return ytphy_write_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG, data);
+};
+
+/**
+ * yt8824_utp_invalid_test_mode_paged() - config YT8824 to invalid test mode.
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_utp_invalid_test_mode_paged(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ return genphy_c45_template_testmode
+ (phydev, MDIO_PMA_10GBT_TESTMODE_1);
+}
+
+/**
+ * yt8824_sds_isolate_paged() - enable YT8824 serdes isolate.
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_sds_isolate_paged(struct phy_device *phydev)
+{
+ int old_page = YT8824_RSSR_UTP_SPACE;
+ int ret = 0;
+
+ old_page = phy_select_page(phydev, YT8824_RSSR_USXGMII_SPACE);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ /* enable sds isolate */
+ ret = __phy_modify(phydev, MII_BMCR, BMCR_ISOLATE, BMCR_ISOLATE);
+
+err_restore_page:
+ /* restore page, release the lock */
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * yt8824_utp_softreset_paged() - config YT8824 UTP softreset.
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_utp_softreset_paged(struct phy_device *phydev)
+{
+ int ret = 0;
+ int val;
+
+ ret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ ret = phy_modify(phydev, MII_BMCR, BMCR_RESET, BMCR_RESET);
+ if (ret < 0)
+ return ret;
+ /* wait until softreset done. */
+ return phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
+ 50000, 600000, true);
+}
+
+/**
+ * yt8824_utp_normal_test_mode_paged() - config YT8824 to normal test mode.
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_utp_normal_test_mode_paged(struct phy_device *phydev)
+{
+ int ret = 0;
+
+ ret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ return genphy_c45_template_testmode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+}
+
+/**
+ * yt8824_sds_isolate_and_softreset_paged() - disable YT8824 serdes isolate
+ * and sds softreset.
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_sds_isolate_and_softreset_paged(struct phy_device *phydev)
+{
+ int old_page = YT8824_RSSR_UTP_SPACE;
+ int val = 0;
+ int ret = -1;
+
+ old_page = phy_select_page(phydev, YT8824_RSSR_USXGMII_SPACE);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ /* sds softreset and disable isolate */
+ ret = __phy_modify(phydev, MII_BMCR, BMCR_RESET | BMCR_ISOLATE,
+ BMCR_RESET & ~BMCR_ISOLATE);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* poll while still holding the lock */
+ ret = read_poll_timeout(__phy_read, val,
+ (val < 0) || !(val & BMCR_RESET), 50000, 600000,
+ true, phydev, MII_BMCR);
+ if (val < 0)
+ ret = val;
+
+err_restore_page:
+ /* restore page, release the lock */
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * yt8824_restore_working_status() - called to do store working status
+ * @phydev: a pointer to a &struct phy_device
+ * @ret: operation's return code
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_restore_working_status(struct phy_device *phydev, int ret)
+{
+ struct yt8824_shared_priv *priv = phy_package_get_priv(phydev);
+ int r;
+
+ /* configure normal test mode */
+ r = yt8824_utp_normal_test_mode_paged(phydev);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ if (priv->interface_mode != PHY_INTERFACE_MODE_INTERNAL) {
+ /* sds soft reset and disable isolation */
+ r = yt8824_sds_isolate_and_softreset_paged(phydev);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ }
+
+ return ret;
+}
+
+/**
+ * yt8824_soft_reset() - called to do PHY software reset
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_soft_reset(struct phy_device *phydev)
+{
+ struct yt8824_shared_priv *priv = phy_package_get_priv(phydev);
+ int ret;
+
+ mutex_lock(&priv->shared_lock);
+ if (priv->interface_mode == PHY_INTERFACE_MODE_INTERNAL) {
+ /* invalid test mode */
+ ret = yt8824_utp_invalid_test_mode_paged(phydev);
+ if (ret < 0)
+ goto retry;
+ ret = yt8824_utp_softreset_paged(phydev);
+ if (ret < 0)
+ goto retry;
+ /* normal mode */
+ ret = yt8824_utp_normal_test_mode_paged(phydev);
+ if (ret < 0)
+ goto retry;
+ } else {
+ /* invalid test mode */
+ ret = yt8824_utp_invalid_test_mode_paged(phydev);
+ if (ret < 0)
+ goto retry;
+
+ /* sds isolation */
+ ret = yt8824_sds_isolate_paged(phydev);
+ if (ret < 0)
+ goto retry;
+
+ /* utp soft reset */
+ ret = yt8824_utp_softreset_paged(phydev);
+ if (ret < 0)
+ goto retry;
+
+ /* normal mode */
+ ret = yt8824_utp_normal_test_mode_paged(phydev);
+ if (ret < 0)
+ goto retry;
+
+ /* sds soft reset and disable isolation */
+ ret = yt8824_sds_isolate_and_softreset_paged(phydev);
+ if (ret < 0)
+ goto retry;
+ }
+ mutex_unlock(&priv->shared_lock);
+ return ret;
+retry:
+ ret = yt8824_restore_working_status(phydev, ret);
+ mutex_unlock(&priv->shared_lock);
+
+ return ret;
+}
+
+/**
+ * yt8824_extern_config_utp_init_paged() - config external phy8824 utp init
+ * @phydev: target phy_device struct
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_extern_config_utp_init_paged(struct phy_device *phydev)
+{
+ int ret = 0;
+ int val = 0;
+ int r;
+
+ ret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ /* power down */
+ ret = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN);
+ if (ret < 0)
+ goto err_restore;
+
+ /* pll calibration */
+ ret = ytphy_write_ext_with_lock(phydev, 0x0001, 0x0003);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa20e, 0x0cba);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa20a, 0xc3f1);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa20c, 0x1620);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2b6, 0x0a00);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2b6, 0x0e00);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimization utp */
+ ret = ytphy_write_ext_with_lock(phydev, 0x0001, 0x0003);
+ if (ret < 0)
+ goto err_restore;
+
+ /* enable nibble */
+ ret = ytphy_write_ext_with_lock(phydev, 0xa003, 0x0003);
+ if (ret < 0)
+ goto err_restore;
+
+ /* idle err detect enable */
+ ret = ytphy_write_ext_with_lock(phydev, 0x03d0, 0x5210);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized 2.5G long cable performance */
+ ret = ytphy_write_ext_with_lock(phydev, 0x0372, 0x5038);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x037c, 0x6068);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x0388, 0x00a0);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized fast retrain */
+ ret = ytphy_write_ext_with_lock(phydev, 0x0359, 0x2140);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x000c, 0xc1a0);
+ if (ret < 0)
+ goto err_restore;
+
+ /* 2.5G template tone */
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2fa, 0x0083);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x04e2, 0x0149);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized 2.5G template */
+ ret = ytphy_write_ext_with_lock(phydev, 0x047e, 0x3939);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x047f, 0x3939);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x0480, 0x3939);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x0481, 0x3939);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized 1000M cable length threshold */
+ ret = ytphy_write_ext_with_lock(phydev, 0x0336, 0xab0a);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x0340, 0x301d);
+ if (ret < 0)
+ goto err_restore;
+
+ /* 100M template amplitude */
+ ret = ytphy_write_ext_with_lock(phydev, 0x046e, 0x4545);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x046f, 0x4545);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x0470, 0x4545);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x0471, 0x4545);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized 100M cable length threshold */
+ ret = ytphy_write_ext_with_lock(phydev, 0x030b, 0xaa1d);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x071f, 0x0036);
+ if (ret < 0)
+ goto err_restore;
+
+ /* 10M template amplitude */
+ ret = ytphy_write_ext_with_lock(phydev, 0x046b, 0x1818);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x046c, 0x1818);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized 10M cable length threshold */
+ ret = ytphy_write_ext_with_lock(phydev, 0x0466, 0x6c6c);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x0467, 0x6c6c);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x0468, 0x6c6c);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x0469, 0x6c6c);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimize utp 1000M performance */
+ ret = ytphy_write_ext_with_lock(phydev, 0x034a, 0xff03);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x00f8, 0xb3ff);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x0059, 0x4040);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x032c, 0x5094);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x032d, 0xd094);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x032e, 0x5308);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x0322, 0x6440);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x04d3, 0x5220);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x04d2, 0x5220);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized EMC CS */
+ ret = ytphy_write_ext_with_lock(phydev, 0x00c8, 0xffff);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x00be, 0x6406);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x037a, 0x40ff);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized EMC RE */
+ ret = ytphy_write_ext_with_lock(phydev, 0x0482, 0xffff);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2d5, 0x1f1f);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2d6, 0x1f1f);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2d7, 0x1f1f);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2d8, 0x1f1f);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa218, 0x006e);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa01d, 0xfff0);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa01e, 0xfff0);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa01d, 0xffff);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0xa01e, 0xffff);
+ if (ret < 0)
+ goto err_restore;
+
+ ret = genphy_c45_template_testmode(phydev, MDIO_PMA_10GBT_TESTMODE_1);
+ if (ret < 0)
+ goto err_restore_normal;
+ /* reset */
+ ret = phy_modify(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE,
+ BMCR_RESET | BMCR_ANENABLE);
+ if (ret < 0)
+ goto err_restore_normal;
+ ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
+ 50000, 600000, true);
+ if (ret < 0)
+ goto err_restore_normal;
+
+ ret = genphy_c45_template_testmode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+ if (ret < 0)
+ goto err_restore_normal;
+ return 0;
+
+err_restore:
+ r = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ return ret;
+
+err_restore_normal:
+ r = genphy_c45_template_testmode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ r = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ return ret;
+}
+
+/**
+ * yt8824_extern_config_sds_init_paged() - config external phy8824 sds init
+ * @phydev: target phy_device struct
+ *
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_extern_config_sds_init_paged(struct phy_device *phydev)
+{
+ int old_page = YT8824_RSSR_UTP_SPACE;
+ int val_1, val_2, val_3, tmp;
+ int ret = -1;
+ int val;
+
+ old_page = phy_select_page(phydev, YT8824_RSSR_USXGMII_SPACE);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ /* read efuse */
+ ret = ytphy_read_top_ext(phydev, 0xa13e);
+ if (ret < 0)
+ goto err_restore_page;
+ else
+ val_1 = ret;
+
+ ret = ytphy_read_top_ext(phydev, 0xa13f);
+ if (ret < 0)
+ goto err_restore_page;
+ else
+ val_2 = ret;
+
+ ret = ytphy_read_top_ext(phydev, 0xa140);
+ if (ret < 0)
+ goto err_restore_page;
+ else
+ val_3 = ret;
+
+ /* Serdes optimization */
+ ret = ytphy_write_ext(phydev, 0x04be, 0x000d);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x049f, 0x7ded);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x04a9, 0x009f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* analog CDR */
+ ret = ytphy_write_ext(phydev, 0x0406, 0x0800);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized VCO */
+ ret = ytphy_write_ext(phydev, 0x0438, 0x9024);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0439, 0x00c0);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized PLL lock */
+ ret = ytphy_read_ext(phydev, 0x0429);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(13) | BIT(12));
+ tmp = (val_1 & (BIT(7) | BIT(6))) >> 6;
+ ret |= (tmp << 12);
+ ret = ytphy_write_ext(phydev, 0x0429, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_read_ext(phydev, 0x0441);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(1) | BIT(0));
+ tmp = (val_1 & (BIT(5) | BIT(4))) >> 4;
+ ret |= tmp;
+ ret = ytphy_write_ext(phydev, 0x0441, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_read_ext(phydev, 0x042b);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(13) | BIT(12));
+ tmp = (val_3 & (BIT(1) | BIT(0)));
+ ret |= (tmp << 12);
+ ret = ytphy_write_ext(phydev, 0x042b, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x043a, 0x1006);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x042a, 0xf070);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* cable length threshold */
+ ret = ytphy_write_ext(phydev, 0x0491, 0x007f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0492, 0x7f7f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* Serdes training threshold */
+ ret = ytphy_write_ext(phydev, 0x0454, 0x0f14);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0497, 0x0a44);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* digital eye diagram of SerDes */
+ ret = ytphy_write_ext(phydev, 0x04cd, 0x0000);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* Serdes LDO */
+ ret = ytphy_read_ext(phydev, 0x04b5);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(6) | BIT(5) | BIT(4));
+ tmp = (val_2 & (BIT(4) | BIT(3) | BIT(2))) >> 2;
+ ret |= (tmp << 4);
+ ret = ytphy_write_ext(phydev, 0x04b5, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_read_ext(phydev, 0x04b4);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(10) | BIT(9) | BIT(8));
+ tmp = (val_2 & (BIT(7) | BIT(6) | BIT(5))) >> 5;
+ ret |= (tmp << 8);
+ ret = ytphy_write_ext(phydev, 0x04b4, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized Serdes RX */
+ ret = ytphy_write_ext(phydev, 0x04af, 0x45e3);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x048a, 0x0fff);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0408, 0x7c00);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x04d6, 0x007f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x044f, 0xff08);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized Serdes TX */
+ ret = ytphy_write_ext(phydev, 0x048e, 0x7d00);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x000d, 0x0606);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* Serdes manual config */
+ ret = ytphy_write_ext(phydev, 0x04b0, 0x0804);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x04b1, 0x7074);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x04af, 0x45e7);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* restart calibration */
+ ret = ytphy_write_ext(phydev, 0x0003, 0x5603);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0492, 0x7fff);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0492, 0x7f7f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x2000, 0x0040);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x2000, 0x0000);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* TX preamble padded to 8; RX IPG always > 8 */
+ ret = __phy_read(phydev, MII_RESV1);
+ if (ret < 0)
+ goto err_restore_page;
+ ret &= ~YT8824_SDS_CFG_MIN_PRE_MASK;
+ ret |= YT8824_SDS_TX_PRE_PADDING;
+ ret |= YT8824_SDS_EN_FILL_PRE;
+ ret = __phy_write(phydev, MII_RESV1, ret);
+ if (ret < 0)
+ goto err_restore_page;
+ /* reset serdes */
+ ret = __phy_modify(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE,
+ BMCR_RESET | BMCR_ANENABLE);
+ if (ret < 0)
+ goto err_restore_page;
+ /* poll while still holding the lock; __phy_read takes no lock */
+ ret = read_poll_timeout(__phy_read, val,
+ (val < 0) || !(val & BMCR_RESET), 50000, 600000,
+ true, phydev, MII_BMCR);
+ if (val < 0)
+ ret = val;
+err_restore_page:
+ /* restore page, release the lock */
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * yt8824_internal_config_init_paged() - config internal phy8824 init
+ * @phydev: target phy_device struct
+ *
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_internal_config_init_paged(struct phy_device *phydev)
+{
+ int ret = 0;
+ int val = 0;
+ int r = 0;
+
+ ret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ ret = ytphy_write_ext_with_lock(phydev, 0x1, 0x3);
+ if (ret < 0)
+ return ret;
+ /* power down */
+ ret = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa20e, 0xcba);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa20a, 0xc3f1);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa20c, 0x1620);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2b6, 0xa00);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2b6, 0xe00);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa003, 0x3);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x3d0, 0x5210);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x372, 0x5038);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x37c, 0x6068);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x388, 0xa0);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x359, 0x2140);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2fa, 0x83);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x4e2, 0x149);
+ if (ret < 0)
+ goto err_restore;
+ /* 2.5G tempate */
+ ret = ytphy_write_ext_with_lock(phydev, 0x47e, 0x3939);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x47f, 0x3939);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x480, 0x3939);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x481, 0x3939);
+ if (ret < 0)
+ goto err_restore;
+ /* 1000 cable length threshold */
+ ret = ytphy_write_ext_with_lock(phydev, 0x336, 0xab0a);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x340, 0x301d);
+ if (ret < 0)
+ goto err_restore;
+ /* 1000 performance */
+ ret = ytphy_write_ext_with_lock(phydev, 0x34a, 0xff03);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xf8, 0xb3ff);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x32c, 0x5094);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x32d, 0xd094);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x32e, 0x5308);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x322, 0x6440);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x4d3, 0x5220);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x4d2, 0x5220);
+ if (ret < 0)
+ goto err_restore;
+ /* 100 tempate */
+ ret = ytphy_write_ext_with_lock(phydev, 0x46e, 0x4545);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x46f, 0x4545);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x470, 0x4545);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x471, 0x4545);
+ if (ret < 0)
+ goto err_restore;
+ /* 100 cable length threshold */
+ ret = ytphy_write_ext_with_lock(phydev, 0x30b, 0xaa1d);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x71f, 0x36);
+ if (ret < 0)
+ goto err_restore;
+ /* 10 tempate */
+ ret = ytphy_write_ext_with_lock(phydev, 0x46b, 0x1818);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x46c, 0x1818);
+ if (ret < 0)
+ goto err_restore;
+ /* 10 tempate MAU*/
+ ret = ytphy_write_ext_with_lock(phydev, 0x466, 0x6c6c);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x467, 0x6c6c);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x468, 0x6c6c);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x469, 0x6c6c);
+ if (ret < 0)
+ goto err_restore;
+ /* EMC CS, Inconsistent with external phy */
+ ret = ytphy_write_ext_with_lock(phydev, 0xc8, 0xfff);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xbe, 0x6406);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0x37a, 0x40ff);
+ if (ret < 0)
+ goto err_restore;
+ /* EMC RE*/
+ ret = ytphy_write_ext_with_lock(phydev, 0x482, 0xffff);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2d5, 0x1f1f);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2d6, 0x1f1f);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2d7, 0x1f1f);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa2d8, 0x1f1f);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa218, 0x6e);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa01d, 0xfff0);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa01e, 0xfff0);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa01d, 0xffff);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xa01e, 0xffff);
+ if (ret < 0)
+ goto err_restore;
+ ret = ytphy_write_ext_with_lock(phydev, 0xc, 0x41a1);
+ if (ret < 0)
+ goto err_restore;
+ ret = genphy_c45_template_testmode(phydev, MDIO_PMA_10GBT_TESTMODE_1);
+ if (ret)
+ goto err_restore_normal;
+ /* reset */
+ ret = phy_modify(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE,
+ BMCR_RESET | BMCR_ANENABLE);
+ if (ret < 0)
+ goto err_restore_normal;
+ ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
+ 50000, 600000, true);
+ if (ret < 0)
+ goto err_restore_normal;
+
+ ret = genphy_c45_template_testmode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+ if (ret < 0)
+ goto err_restore_normal;
+
+ return 0;
+
+err_restore:
+ r = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ return ret;
+
+err_restore_normal:
+ r = genphy_c45_template_testmode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ r = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ return ret;
+}
+
+/**
+ * yt8824_config_init() - phy initializatioin
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_config_init(struct phy_device *phydev)
+{
+ struct yt8824_shared_priv *priv = phy_package_get_priv(phydev);
+ int ret;
+
+ mutex_lock(&priv->shared_lock);
+ if (priv->interface_mode == PHY_INTERFACE_MODE_INTERNAL) {
+ ret = yt8824_internal_config_init_paged(phydev);
+ if (ret < 0)
+ goto err;
+ } else {
+ ret = yt8824_extern_config_sds_init_paged(phydev);
+ if (ret < 0)
+ goto err;
+ ret = yt8824_extern_config_utp_init_paged(phydev);
+ if (ret < 0)
+ goto err;
+ }
+ mutex_unlock(&priv->shared_lock);
+ ret = yt8824_soft_reset(phydev);
+
+ phydev_dbg(phydev, "%s done, phy addr: %d\n", __func__,
+ phydev->mdio.addr);
+ return ret;
+err:
+ mutex_unlock(&priv->shared_lock);
+ return ret;
+}
+
static int yt8531_set_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol)
{