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@google.com>,
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>,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-mediatek@lists.infradead.org
Subject: [PATCH net-next 5/5] net: phy: mediatek: add calibration logic for AN7583
Date: Wed, 8 Jul 2026 12:23:31 +0200 [thread overview]
Message-ID: <20260708102341.53919-6-ansuelsmth@gmail.com> (raw)
In-Reply-To: <20260708102341.53919-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 | 227 ++++++++++++++++++++++-
drivers/net/phy/mediatek/mtk.h | 1 +
2 files changed, 225 insertions(+), 3 deletions(-)
diff --git a/drivers/net/phy/mediatek/airoha-ge-soc.c b/drivers/net/phy/mediatek/airoha-ge-soc.c
index bc487b093cfa..601a64d83365 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] = {
+ [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 },
+ },
+ },
+ [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 },
+ },
+ },
+};
+
+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,
+};
+
static int airoha_cal_cycle(struct phy_device *phydev, int devad,
u32 regnum, u16 mask, u16 cal_val)
{
@@ -766,8 +866,9 @@ static int airoha_rx_offset_cal_sw(struct phy_device *phydev)
phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0x171,
BIT(8) | BIT(7));
- 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;
}
@@ -1540,8 +1641,126 @@ static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index,
static int an7583_phy_config_init(struct phy_device *phydev)
{
+ struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
+ struct phy_device *phydev_p0;
+ 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);
+
+ phydev_p0 = shared->phydev_p0;
+ phy_offset = phydev->mdio.addr - phydev_p0->mdio.addr;
+
+ /* FIXME: Read SoC MDI Resister Type if available or default to 5R */
+ shared->mdi_resister_type = MDI_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;
+
+ 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_0R)
+ 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_0R) {
+ /* 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_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
+ __phy_write(phydev, 0x14, 0x190);
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_1);
+ __phy_write(phydev, 0x14, 0x3a18);
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+ 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[] = {
@@ -1572,6 +1791,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 c690aaf38124..cd9d4c5550c3 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.53.0
next prev parent reply other threads:[~2026-07-08 10:24 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-08 10:23 [PATCH net-next 0/5] net: phy: mediatek: calibration for AN7581/3 Christian Marangi
2026-07-08 10:23 ` [PATCH net-next 1/5] net: phy: mediatek: export __mtk_tr_write Christian Marangi
2026-07-08 10:23 ` [PATCH net-next 2/5] net: phy: mediatek: move MTK GE SoC registers define to dedicated header Christian Marangi
2026-07-08 23:44 ` Andrew Lunn
2026-07-09 13:46 ` Christian Marangi
2026-07-08 10:23 ` [PATCH net-next 3/5] net: phy: mediatek: split Airoha code to dedicated source Christian Marangi
2026-07-08 16:32 ` Wayen Yan
2026-07-08 10:23 ` [PATCH net-next 4/5] net: phy: mediatek: add calibration logic for AN7581 Christian Marangi
2026-07-08 16:30 ` Wayen Yan
2026-07-08 10:23 ` Christian Marangi [this message]
2026-07-08 16:31 ` [PATCH net-next 5/5] net: phy: mediatek: add calibration logic for AN7583 Wayen Yan
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=20260708102341.53919-6-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@google.com \
--cc=hkallweit1@gmail.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=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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox