* [PATCH v2 net-next 0/3] net: phy: mediatek: support EcoNet EN751221 gbit SoC PHY
@ 2026-08-26 20:21 Caleb James DeLisle
2026-08-26 20:21 ` [PATCH v2 net-next 1/3] net: phy: mediatek: move mtk_cal_cycle_wait to mtk-phy-lib Caleb James DeLisle
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Caleb James DeLisle @ 2026-08-26 20:21 UTC (permalink / raw)
To: netdev, ansuelsmth
Cc: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni, daniel,
dqfext, SkyLake.Huang, matthias.bgg, angelogioacchino.delregno,
cjd, linux-kernel, linux-arm-kernel, linux-mediatek
NOTE: This patchset bases on https://lore.kernel.org/netdev/20260708102341.53919-1-ansuelsmth@gmail.com/
Add support for the EcoNet EN751221 SoC gigabit PHY, as identified by
product IDs 9451, and 9471.
Changes since v1:
* Make calibration tables const
* Stop disabling EEE as it does not show problems in testing
* Stop setting MII_BMCR before calibration as testing shows it unnecessary
* Add comment: master/slave resolution is unreliable and is therefore disabled.
* Fix typo in phy_restore_page()
* v1: https://lore.kernel.org/netdev/20260825193456.1823985-1-cjd@cjdns.fr/
Caleb James DeLisle (3):
net: phy: mediatek: move mtk_cal_cycle_wait to mtk-phy-lib
net: phy: mediatek: bug fixes to airoha-ge-soc.c
net: phy: mediatek: support EcoNet EN751221 gbit SoC PHY
drivers/net/phy/mediatek/Kconfig | 9 +-
drivers/net/phy/mediatek/airoha-ge-soc.c | 231 ++++++++++++++++++++++-
drivers/net/phy/mediatek/mtk-ge-soc.c | 27 ---
drivers/net/phy/mediatek/mtk-ge-soc.h | 5 +-
drivers/net/phy/mediatek/mtk-phy-lib.c | 29 +++
drivers/net/phy/mediatek/mtk.h | 2 +
6 files changed, 258 insertions(+), 45 deletions(-)
--
2.39.5
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 net-next 1/3] net: phy: mediatek: move mtk_cal_cycle_wait to mtk-phy-lib
2026-08-26 20:21 [PATCH v2 net-next 0/3] net: phy: mediatek: support EcoNet EN751221 gbit SoC PHY Caleb James DeLisle
@ 2026-08-26 20:21 ` Caleb James DeLisle
2026-08-26 20:21 ` [PATCH v2 net-next 2/3] net: phy: mediatek: bug fixes to airoha-ge-soc.c Caleb James DeLisle
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Caleb James DeLisle @ 2026-08-26 20:21 UTC (permalink / raw)
To: netdev, ansuelsmth
Cc: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni, daniel,
dqfext, SkyLake.Huang, matthias.bgg, angelogioacchino.delregno,
cjd, linux-kernel, linux-arm-kernel, linux-mediatek
mtk_cal_cycle_wait() is shared between mtk-ge-soc.c and airoha-ge-soc.c
making airoha-ge-soc fail to build unless mtk-ge-soc is built too.
Move it to mtk-phy-lib.c which is for this purpose.
Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
---
drivers/net/phy/mediatek/mtk-ge-soc.c | 27 ------------------------
drivers/net/phy/mediatek/mtk-ge-soc.h | 3 ---
drivers/net/phy/mediatek/mtk-phy-lib.c | 29 ++++++++++++++++++++++++++
drivers/net/phy/mediatek/mtk.h | 2 ++
4 files changed, 31 insertions(+), 30 deletions(-)
diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c
index 868ae089013d..614901a8b7f7 100644
--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
@@ -39,33 +39,6 @@ struct mtk_socphy_shared {
struct mtk_socphy_priv priv[4];
};
-int mtk_cal_cycle_wait(struct phy_device *phydev)
-{
- int reg_val;
- int ret;
-
- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
- MTK_PHY_DA_CALIN_FLAG);
-
- ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
- MTK_PHY_RG_AD_CAL_CLK, reg_val,
- reg_val & MTK_PHY_DA_CAL_CLK, 500,
- ANALOG_INTERNAL_OPERATION_MAX_US,
- false);
- if (ret) {
- phydev_err(phydev, "Calibration cycle timeout\n");
- return ret;
- }
-
- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
- MTK_PHY_DA_CALIN_FLAG);
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
- if (ret < 0)
- return ret;
-
- return FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
-}
-
/* 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.
diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.h b/drivers/net/phy/mediatek/mtk-ge-soc.h
index 5e9d24a9833c..834b61dbc690 100644
--- a/drivers/net/phy/mediatek/mtk-ge-soc.h
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.h
@@ -358,7 +358,4 @@ enum CAL_MODE {
SW_M
};
-/* MTK GE SoC common functions */
-int mtk_cal_cycle_wait(struct phy_device *phydev);
-
#endif /* _MTK_GE_SOC_H_ */
diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c
index 8c2b26f9b840..e78dcc15f4e8 100644
--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
@@ -5,6 +5,7 @@
#include <linux/netdevice.h>
#include "mtk.h"
+#include "mtk-ge-soc.h"
/* Difference between functions with mtk_tr* and __mtk_tr* prefixes is
* mtk_tr* functions: wrapped by page switching operations
@@ -414,6 +415,34 @@ int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
};
EXPORT_SYMBOL_GPL(mt798x_phy_led_hw_control_set);
+int mtk_cal_cycle_wait(struct phy_device *phydev)
+{
+ int reg_val;
+ int ret;
+
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
+ MTK_PHY_DA_CALIN_FLAG);
+
+ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
+ MTK_PHY_RG_AD_CAL_CLK, reg_val,
+ reg_val & MTK_PHY_DA_CAL_CLK, 500,
+ ANALOG_INTERNAL_OPERATION_MAX_US,
+ false);
+ if (ret) {
+ phydev_err(phydev, "Calibration cycle timeout\n");
+ return ret;
+ }
+
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
+ MTK_PHY_DA_CALIN_FLAG);
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
+ if (ret < 0)
+ return ret;
+
+ return FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
+}
+EXPORT_SYMBOL_GPL(mtk_cal_cycle_wait);
+
MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common");
MODULE_AUTHOR("Sky Huang <SkyLake.Huang@mediatek.com>");
MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h
index cd9d4c5550c3..950bc89d3c74 100644
--- a/drivers/net/phy/mediatek/mtk.h
+++ b/drivers/net/phy/mediatek/mtk.h
@@ -87,6 +87,8 @@ void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
int mtk_phy_read_page(struct phy_device *phydev);
int mtk_phy_write_page(struct phy_device *phydev, int page);
+int mtk_cal_cycle_wait(struct phy_device *phydev);
+
int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules,
unsigned long supported_triggers);
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 net-next 2/3] net: phy: mediatek: bug fixes to airoha-ge-soc.c
2026-08-26 20:21 [PATCH v2 net-next 0/3] net: phy: mediatek: support EcoNet EN751221 gbit SoC PHY Caleb James DeLisle
2026-08-26 20:21 ` [PATCH v2 net-next 1/3] net: phy: mediatek: move mtk_cal_cycle_wait to mtk-phy-lib Caleb James DeLisle
@ 2026-08-26 20:21 ` Caleb James DeLisle
2026-08-26 20:21 ` [PATCH v2 net-next 3/3] net: phy: mediatek: support EcoNet EN751221 gbit SoC PHY Caleb James DeLisle
2026-08-27 8:19 ` [PATCH v2 net-next 0/3] " Paolo Abeni
3 siblings, 0 replies; 5+ messages in thread
From: Caleb James DeLisle @ 2026-08-26 20:21 UTC (permalink / raw)
To: netdev, ansuelsmth
Cc: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni, daniel,
dqfext, SkyLake.Huang, matthias.bgg, angelogioacchino.delregno,
cjd, linux-kernel, linux-arm-kernel, linux-mediatek
Fix crash bug from unconfigured shared, potential namespace collision
in devm_phy_package_join() and typo in Kconfig.
Also make calibration tables const.
Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
---
drivers/net/phy/mediatek/Kconfig | 2 +-
drivers/net/phy/mediatek/airoha-ge-soc.c | 21 ++++++++++++---------
2 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig
index fe51f4616c54..b8df1a8016c6 100644
--- a/drivers/net/phy/mediatek/Kconfig
+++ b/drivers/net/phy/mediatek/Kconfig
@@ -9,7 +9,7 @@ config AIROHA_GE_SOC_PHY
Supports Airoha SoC built-in Gigabit Ethernet PHYs.
Include support for built-in Ethernet PHYs which are present in
- the AN7581 and AN7583 SoCs. These PHYs d will dynamically
+ the AN7581 and AN7583 SoCs. These PHYs will dynamically
calibrate during startup.
config MEDIATEK_2P5GE_PHY
diff --git a/drivers/net/phy/mediatek/airoha-ge-soc.c b/drivers/net/phy/mediatek/airoha-ge-soc.c
index 601a64d83365..5a8838a47184 100644
--- a/drivers/net/phy/mediatek/airoha-ge-soc.c
+++ b/drivers/net/phy/mediatek/airoha-ge-soc.c
@@ -50,8 +50,8 @@ struct airoha_socphy_shared {
enum airoha_transformer_type transformer_type[4];
enum airoha_mdi_resister_type mdi_resister_type;
bool rext_sw_calib_done;
- int (*tx_amp_compensation_tbl)[TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX][CALIB_CONST_TYPE_MAX][4];
- u8 *r50_cal_tbl;
+ const int (*tx_amp_compensation_tbl)[TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX][CALIB_CONST_TYPE_MAX][4];
+ const u8 *r50_cal_tbl;
};
/*
@@ -61,7 +61,7 @@ struct airoha_socphy_shared {
* TX AMP test/TX AMP 1G/TX AMP 100M/TX AMP 10M/R50
* 4 PHY
*/
-static int an7581_tx_amp_compensation_tbl[2][TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX][CALIB_CONST_TYPE_MAX][4] = {
+static const int an7581_tx_amp_compensation_tbl[2][TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX][CALIB_CONST_TYPE_MAX][4] = {
{ /* IC version 1 */
[TXMR] = {
{ },
@@ -152,7 +152,7 @@ static int an7581_tx_amp_compensation_tbl[2][TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX]
},
};
-static u8 an7581_zcal_to_r45ohm[64] = {
+static const u8 an7581_zcal_to_r45ohm[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, 123, 119, 115, 112, 108, 104, 100, 96,
94, 92, 88, 85, 82, 80, 76, 74, 72, 68, 66, 64, 62, 60, 56, 55,
@@ -166,7 +166,7 @@ static u8 an7581_zcal_to_r45ohm[64] = {
* 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] = {
+static const 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 },
@@ -245,14 +245,14 @@ static int an7583_tx_amp_compensation_tbl[TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX][CA
},
};
-static u8 an7583_zcal_to_r50ohm_0R[64] = {
+static const 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] = {
+static const 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,
@@ -1142,7 +1142,7 @@ static int airoha_phy_tx_amp_compensation(struct phy_device *phydev)
int r50_high_limit = 0x88;
bool overflow;
- int (*tx_amp_table)[CALIB_CONST_TYPE_MAX][4];
+ const int (*tx_amp_table)[CALIB_CONST_TYPE_MAX][4];
int transformer_type, mdi_resister_type;
phydev_p0 = shared->phydev_p0;
@@ -1596,11 +1596,14 @@ static int an7581_phy_probe(struct phy_device *phydev)
dev_err(&phydev->mdio.bus->dev,
"Failed to setup PHY LED pinctrl\n");
- ret = devm_phy_package_join(&phydev->mdio.dev, phydev, 0,
+ ret = devm_phy_package_join(&phydev->mdio.dev, phydev,
+ AIROHA_DEFAULT_PORT0_ADDR,
sizeof(struct airoha_socphy_shared));
if (ret)
return ret;
+ shared = phy_package_get_priv(phydev);
+
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 net-next 3/3] net: phy: mediatek: support EcoNet EN751221 gbit SoC PHY
2026-08-26 20:21 [PATCH v2 net-next 0/3] net: phy: mediatek: support EcoNet EN751221 gbit SoC PHY Caleb James DeLisle
2026-08-26 20:21 ` [PATCH v2 net-next 1/3] net: phy: mediatek: move mtk_cal_cycle_wait to mtk-phy-lib Caleb James DeLisle
2026-08-26 20:21 ` [PATCH v2 net-next 2/3] net: phy: mediatek: bug fixes to airoha-ge-soc.c Caleb James DeLisle
@ 2026-08-26 20:21 ` Caleb James DeLisle
2026-08-27 8:19 ` [PATCH v2 net-next 0/3] " Paolo Abeni
3 siblings, 0 replies; 5+ messages in thread
From: Caleb James DeLisle @ 2026-08-26 20:21 UTC (permalink / raw)
To: netdev, ansuelsmth
Cc: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni, daniel,
dqfext, SkyLake.Huang, matthias.bgg, angelogioacchino.delregno,
cjd, linux-kernel, linux-arm-kernel, linux-mediatek
The EcoNet EN751221 gigabit SoC PHY is identified by product IDs 9451
and 9471. These devices have one such PHY which occupies MMIO index
12. This PHY is present in 3FE+1GE chips such as EN7526C, and also
the "G" chips which have an MCM gigabit switch. In the "G" chips,
this provides a 5th ethernet port.
Reference code disables EEE and sets MII_BMCR to BMCR_ANRESTART |
BMCR_ANENABLE prior to calibration. Testing has shown this seems
unnecessary and it has been omitted, but it is noted here in case
of future issues.
Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
---
drivers/net/phy/mediatek/Kconfig | 9 +-
drivers/net/phy/mediatek/airoha-ge-soc.c | 214 ++++++++++++++++++++++-
drivers/net/phy/mediatek/mtk-ge-soc.h | 2 +
3 files changed, 217 insertions(+), 8 deletions(-)
diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig
index b8df1a8016c6..2d73ea6d8398 100644
--- a/drivers/net/phy/mediatek/Kconfig
+++ b/drivers/net/phy/mediatek/Kconfig
@@ -1,15 +1,14 @@
# SPDX-License-Identifier: GPL-2.0-only
config AIROHA_GE_SOC_PHY
- tristate "Airoha SoC Ethernet PHYs"
- depends on ARM64 || COMPILE_TEST
- depends on ARCH_AIROHA || COMPILE_TEST
+ tristate "Airoha/EcoNet SoC Ethernet PHYs"
+ depends on ARCH_AIROHA || ECONET || COMPILE_TEST
select MTK_NET_PHYLIB
select PHY_PACKAGE
help
- Supports Airoha SoC built-in Gigabit Ethernet PHYs.
+ Supports Airoha and EcoNet SoC built-in Gigabit Ethernet PHYs.
Include support for built-in Ethernet PHYs which are present in
- the AN7581 and AN7583 SoCs. These PHYs will dynamically
+ the AN7581, AN7583, and EN751221 SoCs. These PHYs will dynamically
calibrate during startup.
config MEDIATEK_2P5GE_PHY
diff --git a/drivers/net/phy/mediatek/airoha-ge-soc.c b/drivers/net/phy/mediatek/airoha-ge-soc.c
index 5a8838a47184..1fa258dc22f4 100644
--- a/drivers/net/phy/mediatek/airoha-ge-soc.c
+++ b/drivers/net/phy/mediatek/airoha-ge-soc.c
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: GPL-2.0+
#include <linux/bitfield.h>
+#include <linux/mfd/syscon.h>
#include <linux/pinctrl/consumer.h>
#include <linux/phy.h>
+#include <linux/regmap.h>
#include "../phylib.h"
#include "mtk.h"
@@ -9,6 +11,8 @@
#define AIROHA_DEFAULT_PORT0_ADDR 0x9
#define AIROHA_PHY_MAX_LEDS 2
+#define ECONET_GPHY_CHIPSCU_RASEL_MASK GENMASK(15, 13)
+#define ECONET_GPHY_PORT0_ADDR 12
enum airoha_mdi_resister_type {
MDI_0R,
@@ -259,6 +263,69 @@ static const u8 an7583_zcal_to_r50ohm_5R[64] = {
56, 54, 52, 50, 48, 46, 44, 42, 40, 39, 37, 36, 33, 32, 31, 29,
};
+/*
+ * 2 chip revisions
+ * TXMR (no evidence that these chips were ever discrete)
+ * MDI 0R (5R not known to exist)
+ * TX AMP test/TX AMP 1G/TX AMP 100M/TX AMP 10M/R50
+ * 1 PHY
+ */
+static const int en751221_tx_amp_compensation_tbl[2][TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX][CALIB_CONST_TYPE_MAX][4] = {
+ {
+ /* EN751221 */
+ [TXMR] = {
+ [MDI_0R] = {
+ [TX_AMP_TEST_A] = { 14 },
+ [TX_AMP_TEST_B] = { 14 },
+ [TX_AMP_TEST_C] = { 14 },
+ [TX_AMP_TEST_D] = { 14 },
+ [TX_AMP_1G_A] = { 2 },
+ [TX_AMP_1G_B] = { 2 },
+ [TX_AMP_1G_C] = { 2 },
+ [TX_AMP_1G_D] = { 2 },
+ [TX_AMP_100M_A] = { 4 },
+ [TX_AMP_100M_B] = { 4 },
+ [TX_AMP_10M_A] = { 0 },
+ [TX_AMP_10M_B] = { 0 },
+ [R50_A] = { 0 },
+ [R50_B] = { 0 },
+ [R50_C] = { 0 },
+ [R50_D] = { 0 },
+ },
+ },
+ },
+ {
+ /* EN7526C */
+ [TXMR] = {
+ [MDI_0R] = {
+ [TX_AMP_TEST_A] = { 14 },
+ [TX_AMP_TEST_B] = { 14 },
+ [TX_AMP_TEST_C] = { 14 },
+ [TX_AMP_TEST_D] = { 14 },
+ [TX_AMP_1G_A] = { 12 },
+ [TX_AMP_1G_B] = { 13 },
+ [TX_AMP_1G_C] = { 9 },
+ [TX_AMP_1G_D] = { 9 },
+ [TX_AMP_100M_A] = { 4 },
+ [TX_AMP_100M_B] = { 4 },
+ [TX_AMP_10M_A] = { 0 },
+ [TX_AMP_10M_B] = { 0 },
+ [R50_A] = { 0 },
+ [R50_B] = { 0 },
+ [R50_C] = { -4 },
+ [R50_D] = { -4 },
+ },
+ },
+ }
+};
+
+static const u8 en751221_zcal_to_r50ohm[64] = {
+ 125, 125, 125, 125, 125, 125, 124, 121, 118, 115, 112, 110, 108, 105, 103, 101,
+ 99, 97, 95, 77, 75, 73, 72, 70, 68, 67, 65, 64, 63, 45, 44, 43,
+ 41, 40, 39, 38, 37, 36, 35, 34, 32, 32, 31, 30, 13, 12, 11, 10,
+ 9, 8, 8, 7, 6, 5, 5, 4, 3, 2, 2, 1, 0, 0, 0, 0
+};
+
static int airoha_cal_cycle(struct phy_device *phydev, int devad,
u32 regnum, u16 mask, u16 cal_val)
{
@@ -276,6 +343,21 @@ static int airoha_cal_cycle(struct phy_device *phydev, int devad,
return ret;
}
+/* EN751221 also mirrors RG_BG_RASEL into CHIP SCU register 0x16c. */
+static void en751221_gphy_mirror_rext(struct phy_device *phydev, u8 zcal)
+{
+ struct regmap *chip_scu;
+
+ chip_scu = syscon_regmap_lookup_by_compatible("econet,en751221-chip-scu");
+ if (IS_ERR(chip_scu)) {
+ phydev_err(phydev, "CHIP SCU unavailable for REXT mirror: %ld\n",
+ PTR_ERR(chip_scu));
+ return;
+ }
+ regmap_update_bits(chip_scu, 0x16c, ECONET_GPHY_CHIPSCU_RASEL_MASK,
+ FIELD_PREP(ECONET_GPHY_CHIPSCU_RASEL_MASK, zcal >> 3));
+}
+
static int airoha_rext_cal_sw(struct phy_device *phydev)
{
int calibration_polarity;
@@ -349,6 +431,10 @@ static int airoha_rext_cal_sw(struct phy_device *phydev)
MTK_PHY_RG_BG_RASEL_MASK,
FIELD_PREP(MTK_PHY_RG_BG_RASEL_MASK, zcal_ctrl >> 3));
+ if (phydev->phy_id == ECONET_GPHY_ID_EN7526C ||
+ phydev->phy_id == ECONET_GPHY_ID_EN751221)
+ en751221_gphy_mirror_rext(phydev, zcal_ctrl);
+
phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);
return 0;
@@ -1369,6 +1455,106 @@ static int airoha_phy_tx_amp_compensation(struct phy_device *phydev)
return 0;
}
+static int en751221_gphy_config_init(struct phy_device *phydev)
+{
+ struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
+ int ret;
+
+ shared->mdi_resister_type = MDI_0R;
+
+ if (phydev->phy_id == ECONET_GPHY_ID_EN751221)
+ shared->tx_amp_compensation_tbl = &en751221_tx_amp_compensation_tbl[0];
+ else
+ shared->tx_amp_compensation_tbl = &en751221_tx_amp_compensation_tbl[1];
+
+ shared->r50_cal_tbl = en751221_zcal_to_r50ohm;
+
+ phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
+
+ /* Global MMD (devad 0x1f) settings. */
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x273, 0x1000);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x272, 0x3cff);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x269, 0x4344);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x044, 0x0030);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x27c, 0x0808);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x27b, 0x1177);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x268, 0x0728);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x269, 0x244f);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x271, 0x4e13);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x417, 0x7775);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x024, 0xc007);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x025, 0x003f);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x021, 0x800a);
+
+ /* Local MMD (devad 0x1e) settings. */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x000, 0x01b0);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x001, 0x01be);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x002, 0x01be);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x003, 0x0090);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x004, 0x0205);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x005, 0x0204);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x006, 0x039c);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x007, 0x03c0);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x008, 0x03bc);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x009, 0x0297);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00a, 0x0005);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00b, 0x0006);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x014, 0x0040);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x044, 0x0060);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x176, 0x5500);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x177, 0x0055);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x041, 0x3333);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0a6, 0x0350);
+
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+ __mtk_tr_write(phydev, 0x1, 0xf, 0x00, 0x00002b);
+ __mtk_tr_write(phydev, 0x1, 0xf, 0x03, 0x082422);
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+ /*
+ * 1000BASE-T master/slave resolution fails about once in ten
+ * reconnects, so force this PHY to master mode.
+ */
+ ret = phy_write(phydev, MII_CTRL1000,
+ ADVERTISE_1000FULL | CTL1000_PREFER_MASTER |
+ CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER);
+ if (ret)
+ return ret;
+
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_1);
+ __phy_write(phydev, 0x14, 0x3a14);
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+ if (phydev->phy_id == ECONET_GPHY_ID_EN7526C) {
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x201, 0x4002);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x03d, 0x0c00);
+ } else {
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x012, 0x2c10);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x017, 0x0410);
+ }
+
+ 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;
+
+ return 0;
+}
+
+static int en751221_gphy_match(struct phy_device *phydev,
+ const struct phy_driver *phydrv)
+{
+ return phydev->phy_id == ECONET_GPHY_ID_EN751221 ||
+ phydev->phy_id == ECONET_GPHY_ID_EN7526C;
+}
+
static int an7581_phy_config_init(struct phy_device *phydev)
{
struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
@@ -1585,6 +1771,7 @@ static int an7581_phy_config_init(struct phy_device *phydev)
static int an7581_phy_probe(struct phy_device *phydev)
{
+ int port0 = AIROHA_DEFAULT_PORT0_ADDR;
struct airoha_socphy_shared *shared;
struct mtk_socphy_priv *priv;
struct pinctrl *pinctrl;
@@ -1596,8 +1783,11 @@ static int an7581_phy_probe(struct phy_device *phydev)
dev_err(&phydev->mdio.bus->dev,
"Failed to setup PHY LED pinctrl\n");
- ret = devm_phy_package_join(&phydev->mdio.dev, phydev,
- AIROHA_DEFAULT_PORT0_ADDR,
+ if (phydev->phy_id == ECONET_GPHY_ID_EN7526C ||
+ phydev->phy_id == ECONET_GPHY_ID_EN751221)
+ port0 = ECONET_GPHY_PORT0_ADDR;
+
+ ret = devm_phy_package_join(&phydev->mdio.dev, phydev, port0,
sizeof(struct airoha_socphy_shared));
if (ret)
return ret;
@@ -1608,7 +1798,7 @@ static int an7581_phy_probe(struct phy_device *phydev)
if (!priv)
return -ENOMEM;
- if (phydev->mdio.addr == AIROHA_DEFAULT_PORT0_ADDR)
+ if (phydev->mdio.addr == port0)
shared->phydev_p0 = phydev;
phydev->priv = priv;
@@ -1797,6 +1987,22 @@ static struct phy_driver mtk_socphy_driver[] = {
.read_page = mtk_phy_read_page,
.write_page = mtk_phy_write_page,
},
+ {
+ .name = "EcoNet EN751221 GPHY",
+ .config_init = en751221_gphy_config_init,
+ .config_intr = genphy_no_config_intr,
+ .handle_interrupt = genphy_handle_interrupt_no_ack,
+ .match_phy_device = en751221_gphy_match,
+ .probe = an7581_phy_probe,
+ .led_blink_set = mt798x_phy_led_blink_set,
+ .led_brightness_set = mt798x_phy_led_brightness_set,
+ .led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+ .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,
+ }
};
module_phy_driver(mtk_socphy_driver);
@@ -1804,6 +2010,8 @@ module_phy_driver(mtk_socphy_driver);
static const struct mdio_device_id __maybe_unused airoha_socphy_tbl[] = {
{ PHY_ID_MATCH_EXACT(AIROHA_GPHY_ID_AN7581) },
{ PHY_ID_MATCH_EXACT(AIROHA_GPHY_ID_AN7583) },
+ { PHY_ID_MATCH_EXACT(ECONET_GPHY_ID_EN751221) },
+ { PHY_ID_MATCH_EXACT(ECONET_GPHY_ID_EN7526C) },
{ }
};
diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.h b/drivers/net/phy/mediatek/mtk-ge-soc.h
index 834b61dbc690..1f38b4c81860 100644
--- a/drivers/net/phy/mediatek/mtk-ge-soc.h
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.h
@@ -9,6 +9,8 @@
#define MTK_GPHY_ID_MT7988 0x03a29481
#define AIROHA_GPHY_ID_AN7581 0x03a294c1
#define AIROHA_GPHY_ID_AN7583 0xc0ff0420
+#define ECONET_GPHY_ID_EN751221 0x03a29451
+#define ECONET_GPHY_ID_EN7526C 0x03a29471
#define MTK_EXT_PAGE_ACCESS 0x1f
#define MTK_PHY_PAGE_STANDARD 0x0000
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 net-next 0/3] net: phy: mediatek: support EcoNet EN751221 gbit SoC PHY
2026-08-26 20:21 [PATCH v2 net-next 0/3] net: phy: mediatek: support EcoNet EN751221 gbit SoC PHY Caleb James DeLisle
` (2 preceding siblings ...)
2026-08-26 20:21 ` [PATCH v2 net-next 3/3] net: phy: mediatek: support EcoNet EN751221 gbit SoC PHY Caleb James DeLisle
@ 2026-08-27 8:19 ` Paolo Abeni
3 siblings, 0 replies; 5+ messages in thread
From: Paolo Abeni @ 2026-08-27 8:19 UTC (permalink / raw)
To: Caleb James DeLisle, netdev, ansuelsmth
Cc: andrew, hkallweit1, linux, davem, edumazet, kuba, daniel, dqfext,
SkyLake.Huang, matthias.bgg, angelogioacchino.delregno,
linux-kernel, linux-arm-kernel, linux-mediatek
On 8/26/26 10:21 PM, Caleb James DeLisle wrote:
> NOTE: This patchset bases on https://lore.kernel.org/netdev/20260708102341.53919-1-ansuelsmth@gmail.com/
>
> Add support for the EcoNet EN751221 SoC gigabit PHY, as identified by
> product IDs 9451, and 9471.
## Form letter - net-next-closed
net-next pull request for v7.3 has already been merged, and therefore
the net-next tree is closed for new drivers, features, code refactoring
and optimizations. We are currently accepting bug fixes only.
Please repost when net-next reopens after Aug 31st.
RFC patches sent for review only are obviously welcome at any time.
See:
https://www.kernel.org/doc/html/next/process/maintainer-netdev.html#development-cycle
--
pw-bot: defer
pv-bot: closed
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-27 8:19 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-26 20:21 [PATCH v2 net-next 0/3] net: phy: mediatek: support EcoNet EN751221 gbit SoC PHY Caleb James DeLisle
2026-08-26 20:21 ` [PATCH v2 net-next 1/3] net: phy: mediatek: move mtk_cal_cycle_wait to mtk-phy-lib Caleb James DeLisle
2026-08-26 20:21 ` [PATCH v2 net-next 2/3] net: phy: mediatek: bug fixes to airoha-ge-soc.c Caleb James DeLisle
2026-08-26 20:21 ` [PATCH v2 net-next 3/3] net: phy: mediatek: support EcoNet EN751221 gbit SoC PHY Caleb James DeLisle
2026-08-27 8:19 ` [PATCH v2 net-next 0/3] " Paolo Abeni
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).