From: Christian Marangi <ansuelsmth@gmail.com>
To: Andrew Lunn <andrew@lunn.ch>,
Heiner Kallweit <hkallweit1@gmail.com>,
Russell King <linux@armlinux.org.uk>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Christian Marangi <ansuelsmth@gmail.com>,
Daniel Golle <daniel@makrotopia.org>,
Qingfang Deng <dqfext@gmail.com>,
SkyLake Huang <SkyLake.Huang@mediatek.com>,
Matthias Brugger <matthias.bgg@gmail.com>,
AngeloGioacchino Del Regno
<angelogioacchino.delregno@collabora.com>,
Joris Vaisvila <joey@tinyisr.com>,
Ahmed Naseef <naseefkm@gmail.com>,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-mediatek@lists.infradead.org
Subject: [PATCH net-next v5 6/6] net: phy: mediatek: add calibration logic for AN7583
Date: Thu, 5 Nov 2026 11:55:02 +0100 [thread overview]
Message-ID: <20261105105504.1024-7-ansuelsmth@gmail.com> (raw)
In-Reply-To: <20261105105504.1024-1-ansuelsmth@gmail.com>
Similar to Airoha AN7581 Switch PHY also the Airoha AN7583 SoC
requires dedicated calibration and tuneup to make EEE correctly work.
Airoha AN7583 differ from AN7581 by having a dedicated table for
calibration and additional EEE logic tuneup.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/net/phy/mediatek/airoha-ge-soc.c | 232 ++++++++++++++++++++++-
drivers/net/phy/mediatek/mtk.h | 1 +
2 files changed, 230 insertions(+), 3 deletions(-)
diff --git a/drivers/net/phy/mediatek/airoha-ge-soc.c b/drivers/net/phy/mediatek/airoha-ge-soc.c
index 18b9b6562f6d..089035bb3e9b 100644
--- a/drivers/net/phy/mediatek/airoha-ge-soc.c
+++ b/drivers/net/phy/mediatek/airoha-ge-soc.c
@@ -159,6 +159,106 @@ static u8 an7581_zcal_to_r45ohm[64] = {
52, 50, 48, 46, 44, 42, 40, 39, 36, 35, 32, 32, 30, 28, 27, 25
};
+/*
+ * 2 chip revision
+ * TXMR or discrete
+ * 2 MDI type
+ * TX AMP test/TX AMP 1G/TX AMP 100M/TX AMP 10M/R50
+ * 4 PHY
+ */
+static int an7583_tx_amp_compensation_tbl[TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX][CALIB_CONST_TYPE_MAX][4] = {
+ [DISCRETE] = {
+ [MDI_0R] = {
+ [TX_AMP_TEST_A] = { -3, -3, -3, -3 },
+ [TX_AMP_TEST_B] = { -3, -3, -3, -3 },
+ [TX_AMP_TEST_C] = { -3, -3, -3, -3 },
+ [TX_AMP_TEST_D] = { -3, -3, -3, -3 },
+ [TX_AMP_1G_A] = { 0, 0, 0, 0 },
+ [TX_AMP_1G_B] = { 0, 0, 0, 0 },
+ [TX_AMP_1G_C] = { 0, 0, 0, 0 },
+ [TX_AMP_1G_D] = { 0, 0, 0, 0 },
+ [TX_AMP_100M_A] = { 4, 4, 4, 4 },
+ [TX_AMP_100M_B] = { 4, 4, 4, 4 },
+ [TX_AMP_10M_A] = { 0, 0, 0, 0 },
+ [TX_AMP_10M_B] = { 0, 0, 0, 0 },
+ [R50_A] = { 4, 4, 4, 4 },
+ [R50_B] = { 4, 4, 4, 4 },
+ [R50_C] = { 6, 6, 6, 6 },
+ [R50_D] = { 4, 4, 4, 4 },
+ },
+ [MDI_5R] = {
+ [TX_AMP_TEST_A] = { -3, -3, -3, -3 },
+ [TX_AMP_TEST_B] = { -3, -3, -3, -3 },
+ [TX_AMP_TEST_C] = { -3, -3, -3, -3 },
+ [TX_AMP_TEST_D] = { -3, -3, -3, -3 },
+ [TX_AMP_1G_A] = { 0, 0, 0, 0 },
+ [TX_AMP_1G_B] = { 0, 0, 0, 0 },
+ [TX_AMP_1G_C] = { 0, 0, 0, 0 },
+ [TX_AMP_1G_D] = { 0, 0, 0, 0 },
+ [TX_AMP_100M_A] = { 4, 4, 4, 4 },
+ [TX_AMP_100M_B] = { 4, 4, 4, 4 },
+ [TX_AMP_10M_A] = { 0, 0, 0, 0 },
+ [TX_AMP_10M_B] = { 0, 0, 0, 0 },
+ [R50_A] = { 0, 0, 0, 0 },
+ [R50_B] = { 0, 0, 0, 0 },
+ [R50_C] = { 0, 0, 0, 0 },
+ [R50_D] = { 0, 0, 0, 0 },
+ },
+ },
+ [TXMR] = {
+ [MDI_0R] = {
+ [TX_AMP_TEST_A] = { -3, -3, -3, -3 },
+ [TX_AMP_TEST_B] = { -3, -3, -3, -3 },
+ [TX_AMP_TEST_C] = { -3, -3, -3, -3 },
+ [TX_AMP_TEST_D] = { -3, -3, -3, -3 },
+ [TX_AMP_1G_A] = { 0, 0, 0, 0 },
+ [TX_AMP_1G_B] = { 0, 0, 0, 0 },
+ [TX_AMP_1G_C] = { 0, 0, 0, 0 },
+ [TX_AMP_1G_D] = { 0, 0, 0, 0 },
+ [TX_AMP_100M_A] = { 4, 4, 4, 4 },
+ [TX_AMP_100M_B] = { 4, 4, 4, 4 },
+ [TX_AMP_10M_A] = { 0, 0, 0, 0 },
+ [TX_AMP_10M_B] = { 0, 0, 0, 0 },
+ [R50_A] = { 4, 4, 0, 0 },
+ [R50_B] = { 4, 4, 0, 0 },
+ [R50_C] = { 5, 5, 3, 4 },
+ [R50_D] = { 4, 4, 4, 0 },
+ },
+ [MDI_5R] = {
+ [TX_AMP_TEST_A] = { -3, -3, -3, -3 },
+ [TX_AMP_TEST_B] = { -3, -3, -3, -3 },
+ [TX_AMP_TEST_C] = { -3, -3, -3, -3 },
+ [TX_AMP_TEST_D] = { -3, -3, -3, -3 },
+ [TX_AMP_1G_A] = { 0, 0, 0, 0 },
+ [TX_AMP_1G_B] = { 0, 0, 0, 0 },
+ [TX_AMP_1G_C] = { 0, 0, 0, 0 },
+ [TX_AMP_1G_D] = { 0, 0, 0, 0 },
+ [TX_AMP_100M_A] = { 4, 4, 4, 4 },
+ [TX_AMP_100M_B] = { 4, 4, 4, 4 },
+ [TX_AMP_10M_A] = { 0, 0, 0, 0 },
+ [TX_AMP_10M_B] = { 0, 0, 0, 0 },
+ [R50_A] = { -4, -4, -4, -4 },
+ [R50_B] = { -4, -4, -4, -4 },
+ [R50_C] = { -2, -2, -2, -2 },
+ [R50_D] = { -3, -3, -2, -2 },
+ },
+ },
+};
+
+static u8 an7583_zcal_to_r50ohm_0R[64] = {
+ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 122, 118, 114, 110, 106, 102, 98, 96, 92, 88, 85, 82, 80,
+ 76, 72, 70, 68, 64, 62, 60, 57, 55, 52, 50, 48, 46, 44, 41, 40,
+ 38, 36, 33, 32, 30, 28, 26, 24, 24, 22, 20, 18, 16, 16, 14, 12,
+};
+
+static u8 an7583_zcal_to_r50ohm_5R[64] = {
+ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127, 127, 124, 120, 116, 112, 110, 106, 102,
+ 99, 96, 93, 90, 88, 84, 81, 79, 76, 73, 71, 68, 66, 64, 61, 59,
+ 56, 54, 52, 50, 48, 46, 44, 42, 40, 39, 37, 36, 33, 32, 31, 29,
+};
+
/* One calibration cycle consists of:
* 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
* until AD_CAL_COMP is ready to output calibration result.
@@ -824,8 +924,9 @@ static int airoha_rx_offset_cal_sw(struct phy_device *phydev)
phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x100, 0x0);
phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x145, 0x1000);
- phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG6,
- 0x1);
+ if (phydev->drv->phy_id == AIROHA_GPHY_ID_AN7581)
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ MTK_PHY_RG_ANA_CAL_RG6, 0x1);
return 0;
}
@@ -1625,10 +1726,133 @@ static int en7528_phy_config_init(struct phy_device *phydev)
MTK_PHY_LED_BCR_EXT_CTRL);
}
+static int an7583_phy_package_config_init_once(struct phy_device *phydev)
+{
+ struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
+
+ /* FIXME: Read SoC MDI Resister Type if available or default to 5R */
+ shared->mdi_resister_type = MDI_5R;
+
+ if (shared->mdi_resister_type == MDI_0R)
+ shared->r50_cal_tbl = an7583_zcal_to_r50ohm_0R;
+ if (shared->mdi_resister_type == MDI_5R)
+ shared->r50_cal_tbl = an7583_zcal_to_r50ohm_5R;
+ shared->tx_amp_compensation_tbl = &an7583_tx_amp_compensation_tbl;
+
+ return 0;
+}
+
static int an7583_phy_config_init(struct phy_device *phydev)
{
+ struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
+ u8 phy_offset;
+ int ret;
+
/* BMCR_PDOWN is enabled by default */
- return phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
+ phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
+
+ phy_offset = phy_package_offset(phydev);
+
+ if (phy_package_init_once(phydev)) {
+ ret = an7583_phy_package_config_init_once(phydev);
+ if (ret)
+ return ret;
+ }
+
+ ret = airoha_phy_calib(phydev);
+ if (ret)
+ return ret;
+
+ ret = airoha_phy_auto_select_transformer(phydev);
+ if (ret)
+ return ret;
+
+ ret = airoha_phy_tx_amp_compensation(phydev);
+ if (ret)
+ return ret;
+
+ /* Enable Idle Mode Power Setting */
+ if (phy_offset == 0) {
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x268, 0x07F1);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x703, 0x3111);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x271, 0x3C24);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x701, 0x1023);
+ }
+
+ if (shared->transformer_type[phy_offset] == TXMR) {
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0881);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0881);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0881);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0881);
+
+ if (shared->mdi_resister_type == MDI_5R)
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0205);
+ else
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0200);
+ } else {
+ if (shared->mdi_resister_type == MDI_5R) {
+ /* RX setting for 5R_TXMR before AN setting */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe7, 0x6666);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe9, 0x0003);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xfe, 0x0006);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe6, 0x1111);
+ /* 100M sharp */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0c86);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0c86);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0c86);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0c86);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01, 0x01cb);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x02, 0x01c2);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x03, 0x0108);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x04, 0x0211);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0205);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x06, 0x0387);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x07, 0x03ce);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x08, 0x03c8);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0b, 0x0005);
+ } else {
+ /* 100M sharp */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0886);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0886);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0886);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0886);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00, 0x0195);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01, 0x01cb);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x02, 0x01c2);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x03, 0x0108);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x04, 0x0211);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0205);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x06, 0x0387);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x07, 0x03ce);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x08, 0x03c3);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0a, 0x0010);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0b, 0x0005);
+ }
+ }
+
+ /* RX Setting */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3c, 0xc000);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3d, 0x0000);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3e, 0xc000);
+
+ /* EEE setting */
+ phy_write_mmd(phydev, MDIO_MMD_AN, 0x3c, 0x0000);
+
+ /* 10M settings */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x1a3, 0x00d2);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x1a4, 0x010e);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x27b, 0x1177);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x27c, 0x0808);
+
+ phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x14, 0x190);
+ phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_1, 0x14, 0x3a18);
+
+ phy_write(phydev, 0x9, 0x0600);
+
+ /* EEE keep only Pair A ON */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x630, 0x006E);
+
+ return 0;
}
static struct phy_driver mtk_socphy_driver[] = {
@@ -1671,6 +1895,8 @@ static struct phy_driver mtk_socphy_driver[] = {
.led_hw_control_set = mt798x_phy_led_hw_control_set,
.led_hw_control_get = mt798x_phy_led_hw_control_get,
.led_polarity_set = an7581_phy_led_polarity_set,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
},
};
diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h
index bc46646a95fd..608e5e3d754f 100644
--- a/drivers/net/phy/mediatek/mtk.h
+++ b/drivers/net/phy/mediatek/mtk.h
@@ -13,6 +13,7 @@
#define MTK_EXT_PAGE_ACCESS 0x1f
#define MTK_PHY_PAGE_EXTENDED_1 0x0001
+#define MTK_PHY_PAGE_EXTENDED_3 0x0003
#define MTK_PHY_PAGE_STANDARD 0x0000
#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
--
2.55.0
prev parent reply other threads:[~2026-11-05 10:55 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 10:54 [PATCH net-next v5 0/6] net: phy: mediatek: calibration for AN7581/3 Christian Marangi
2026-11-05 10:54 ` [PATCH net-next v5 1/6] net: phy: mediatek: export __mtk_tr_write Christian Marangi
2026-11-05 10:54 ` [PATCH net-next v5 2/6] net: phy: mediatek: move MTK GE SoC registers define to dedicated header Christian Marangi
2026-11-05 10:54 ` [PATCH net-next v5 3/6] net: phy: add additional helper for PHY package Christian Marangi
2026-11-05 19:32 ` kernel test robot
2026-11-05 10:55 ` [PATCH net-next v5 4/6] net: phy: mediatek: split Airoha code to dedicated source Christian Marangi
2026-11-05 10:55 ` [PATCH net-next v5 5/6] net: phy: mediatek: add calibration logic for AN7581 Christian Marangi
2026-11-05 10:55 ` Christian Marangi [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261105105504.1024-7-ansuelsmth@gmail.com \
--to=ansuelsmth@gmail.com \
--cc=SkyLake.Huang@mediatek.com \
--cc=andrew@lunn.ch \
--cc=angelogioacchino.delregno@collabora.com \
--cc=daniel@makrotopia.org \
--cc=davem@davemloft.net \
--cc=dqfext@gmail.com \
--cc=edumazet@kernel.org \
--cc=hkallweit1@gmail.com \
--cc=joey@tinyisr.com \
--cc=kuba@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mediatek@lists.infradead.org \
--cc=linux@armlinux.org.uk \
--cc=matthias.bgg@gmail.com \
--cc=naseefkm@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.