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:23 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 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.