* [PATCH net-next 2/5] net: phy: ncn26000: add support for TS2500 internal PHY
@ 2026-05-01 19:15 Selvamani Rajagopal
2026-05-01 19:50 ` Andrew Lunn
0 siblings, 1 reply; 2+ messages in thread
From: Selvamani Rajagopal @ 2026-05-01 19:15 UTC (permalink / raw)
To: Piergiorgio Beruto, andrew@lunn.ch, hkallweit1@gmail.com,
linux@armlinux.org.uk, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Support for onsemi's IEEE 802.3cg compliant Ethernet Transceiver
with integrated Media Access Controller (MACPHY). NCN26010 and
TS2500 are supported.
Updated MAINTAINERS file
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
MAINTAINERS | 11 ++-
drivers/net/phy/ncn26000.c | 193 +++++++++++++++++++++++++------------
2 files changed, 144 insertions(+), 60 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 27a073f53..36c1b2f02 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19934,12 +19934,21 @@ S: Maintained
F: arch/mips/boot/dts/ralink/omega2p.dts
ONSEMI ETHERNET PHY DRIVERS
-M: Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
+M: Piergiorgio Beruto <pier.beruto@onsemi.com>
+M: Selva Rajagopal <selvamani.rajagopal@onsemi.com>
L: netdev@vger.kernel.org
S: Supported
W: http://www.onsemi.com
F: drivers/net/phy/ncn*
+ONSEMI NCN260xx/TS2500 10BASE-T1S MACPHY ETHERNET DRIVER
+M: Piergiorgio Beruto <pier.beruto@onsemi.com>
+M: Selva Rajagopal <selvamani.rajagopal@onsemi.com>
+L: netdev@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/net/onnn,ncn260xx.yaml
+F: drivers/net/ethernet/onsemi/ncn260xx/ncn*
+
OP-TEE DRIVER
M: Jens Wiklander <jens.wiklander@linaro.org>
L: op-tee@lists.trustedfirmware.org (moderated for non-subscribers)
diff --git a/drivers/net/phy/ncn26000.c b/drivers/net/phy/ncn26000.c
index cabdd83c6..d4bb4b230 100644
--- a/drivers/net/phy/ncn26000.c
+++ b/drivers/net/phy/ncn26000.c
@@ -2,7 +2,7 @@
/*
* Driver for the onsemi 10BASE-T1S NCN26000 PHYs family.
*
- * Copyright 2022 onsemi
+ * Copyright 2026 onsemi
*/
#include <linux/kernel.h>
#include <linux/bitfield.h>
@@ -11,39 +11,43 @@
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/phy.h>
+#include <linux/ethtool.h>
+#include <linux/ethtool_netlink.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
#include "mdio-open-alliance.h"
#define PHY_ID_NCN26000 0x180FF5A1
+#define PHY_ID_TS2500 0x180FF411
-#define NCN26000_REG_IRQ_CTL 16
-#define NCN26000_REG_IRQ_STATUS 17
+#define TO_TMR_DEFAULT 32
-// the NCN26000 maps link_ctrl to BMCR_ANENABLE
-#define NCN26000_BCMR_LINK_CTRL_BIT BMCR_ANENABLE
+#define NCN26000_REG_IRQ_CTL 16
+#define NCN26000_REG_IRQ_STATUS 17
-// the NCN26000 maps link_status to BMSR_ANEGCOMPLETE
-#define NCN26000_BMSR_LINK_STATUS_BIT BMSR_ANEGCOMPLETE
+/* clause 45 vendor specific registers */
+#define NCN26000_REG_PHYCFG1_MMD MDIO_MMD_VEND2
+#define NCN26000_REG_PHYCFG1 0x8001
#define NCN26000_IRQ_LINKST_BIT BIT(0)
-#define NCN26000_IRQ_PLCAST_BIT BIT(1)
-#define NCN26000_IRQ_LJABBER_BIT BIT(2)
-#define NCN26000_IRQ_RJABBER_BIT BIT(3)
-#define NCN26000_IRQ_PLCAREC_BIT BIT(4)
-#define NCN26000_IRQ_PHYSCOL_BIT BIT(5)
-#define NCN26000_IRQ_RESET_BIT BIT(15)
-#define TO_TMR_DEFAULT 32
+#define NCN26000_PHYCFG1_ENI BIT(7)
+#define NCN26000_PHYCFG1_ENI_MASK BIT(7)
+/* Default value of the PLCA TO_TIMER should be 32. NCN26000 reports
+ * as 24. This is fixed in next version, in TS2500.
+ */
static int ncn26000_config_init(struct phy_device *phydev)
{
- /* HW bug workaround: the default value of the PLCA TO_TIMER should be
- * 32, where the current version of NCN26000 reports 24. This will be
- * fixed in future PHY versions. For the time being, we force the
- * correct default here.
- */
- return phy_write_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_TOTMR,
- TO_TMR_DEFAULT);
+ const struct phy_driver *pdrv = phydev->drv;
+ int ret = 0;
+
+ if (pdrv && pdrv->phy_id == PHY_ID_NCN26000)
+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2,
+ MDIO_OATC14_PLCA_TOTMR,
+ 0xFFFF, TO_TMR_DEFAULT);
+ return ret;
}
static int ncn26000_config_aneg(struct phy_device *phydev)
@@ -55,17 +59,20 @@ static int ncn26000_config_aneg(struct phy_device *phydev)
phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
phydev->mdix = ETH_TP_MDI;
- // bring up the link
- return phy_write(phydev, MII_BMCR, NCN26000_BCMR_LINK_CTRL_BIT);
+ /* NCN2600x maps link_ctrl to BMCR_ANENABLE */
+ return phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
}
+/* Link status mapped to BMSR_ANEGCOMPLETE. */
static int ncn26000_read_status(struct phy_device *phydev)
{
- /* The NCN26000 reports NCN26000_LINK_STATUS_BIT if the link status of
- * the PHY is up. It further reports the logical AND of the link status
- * and the PLCA status in the BMSR_LSTATUS bit.
- */
- int ret;
+ u16 status_check = BMSR_ANEGCOMPLETE;
+ int ret = 0;
+
+ phydev->duplex = DUPLEX_HALF;
+ phydev->speed = SPEED_10;
+ phydev->autoneg = AUTONEG_DISABLE;
+ phydev->pause = 0;
/* The link state is latched low so that momentary link
* drops can be detected. Do not double-read the status
@@ -76,7 +83,7 @@ static int ncn26000_read_status(struct phy_device *phydev)
ret = phy_read(phydev, MII_BMSR);
if (ret < 0)
return ret;
- else if (ret & NCN26000_BMSR_LINK_STATUS_BIT)
+ if (ret & status_check)
goto upd_link;
}
@@ -85,30 +92,54 @@ static int ncn26000_read_status(struct phy_device *phydev)
return ret;
upd_link:
- // update link status
- if (ret & NCN26000_BMSR_LINK_STATUS_BIT) {
+ /* Update link status */
+ if (ret & status_check)
phydev->link = 1;
- phydev->pause = 0;
- phydev->duplex = DUPLEX_HALF;
- phydev->speed = SPEED_10;
- } else {
+ else
phydev->link = 0;
- phydev->duplex = DUPLEX_UNKNOWN;
- phydev->speed = SPEED_UNKNOWN;
- }
return 0;
}
+/* We capture calls to PLCA set config to intercept PLCA enable/disable
+ * requests and set the proprietary ENI mode accordingly
+ */
+static int ncn26000_plca_set_cfg(struct phy_device *phydev,
+ const struct phy_plca_cfg *plca_cfg)
+{
+ int ret = genphy_c45_plca_set_cfg(phydev, plca_cfg);
+ u16 cfg_enabled = 0;
+ int ctl0 = 0;
+
+ if (ret || plca_cfg->enabled < 0)
+ return ret;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_CTRL1);
+ if (ret >= 0) {
+ ctl0 = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+ MDIO_OATC14_PLCA_CTRL0);
+ if (ctl0 >= 0)
+ dev_info(&phydev->mdio.dev, "PLCA %s: node id=%d, count=%d",
+ (ctl0 & MDIO_OATC14_PLCA_EN) ? "ON" : "OFF",
+ ret & MDIO_OATC14_PLCA_ID,
+ (ret & MDIO_OATC14_PLCA_NCNT) >> 8);
+ }
+
+ cfg_enabled = (plca_cfg->enabled) ? NCN26000_PHYCFG1_ENI : 0;
+ return phy_modify_mmd(phydev, NCN26000_REG_PHYCFG1_MMD,
+ NCN26000_REG_PHYCFG1,
+ NCN26000_PHYCFG1_ENI_MASK, cfg_enabled);
+}
+
static irqreturn_t ncn26000_handle_interrupt(struct phy_device *phydev)
{
int ret;
- // read and aknowledge the IRQ status register
+ /* Read and acknowledge the IRQ status register */
ret = phy_read(phydev, NCN26000_REG_IRQ_STATUS);
- // check only link status changes
- if (ret < 0 || (ret & NCN26000_REG_IRQ_STATUS) == 0)
+ /* Check only link status changes */
+ if (ret < 0 || ((ret & NCN26000_IRQ_LINKST_BIT) == 0))
return IRQ_NONE;
phy_trigger_machine(phydev);
@@ -117,20 +148,17 @@ static irqreturn_t ncn26000_handle_interrupt(struct phy_device *phydev)
static int ncn26000_config_intr(struct phy_device *phydev)
{
+ u16 irqe = 0;
int ret;
- u16 irqe;
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
- // acknowledge IRQs
+ /* Acknowledge IRQs */
ret = phy_read(phydev, NCN26000_REG_IRQ_STATUS);
if (ret < 0)
return ret;
- // get link status notifications
+ /* Get link status notifications */
irqe = NCN26000_IRQ_LINKST_BIT;
- } else {
- // disable all IRQs
- irqe = 0;
}
ret = phy_write(phydev, NCN26000_REG_IRQ_CTL, irqe);
@@ -140,20 +168,66 @@ static int ncn26000_config_intr(struct phy_device *phydev)
return 0;
}
+static void ncn26000_remove(struct phy_device *phydev)
+{
+ phydev->priv = NULL;
+}
+
+static int ncn26000_read_mmd(struct phy_device *phydev, int dev, u16 reg)
+{
+ struct mii_bus *bus = phydev->mdio.bus;
+ int addr = phydev->mdio.addr;
+
+ return __mdiobus_c45_read(bus, addr, dev, reg);
+}
+
+static int ncn26000_write_mmd(struct phy_device *phydev, int dev,
+ u16 reg, u16 val)
+{
+ struct mii_bus *bus = phydev->mdio.bus;
+ int addr = phydev->mdio.addr;
+
+ return __mdiobus_c45_write(bus, addr, dev, reg, val);
+}
+
static struct phy_driver ncn26000_driver[] = {
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_TS2500),
+ .name = "TS2500",
+ .features = PHY_BASIC_T1S_P2MP_FEATURES,
+ .remove = ncn26000_remove,
+ .config_init = ncn26000_config_init,
+ .config_intr = ncn26000_config_intr,
+ .config_aneg = ncn26000_config_aneg,
+ .read_status = ncn26000_read_status,
+ .handle_interrupt = ncn26000_handle_interrupt,
+ .set_plca_cfg = ncn26000_plca_set_cfg,
+ .get_plca_cfg = genphy_c45_plca_get_cfg,
+ .get_plca_status = genphy_c45_plca_get_status,
+ .soft_reset = genphy_soft_reset,
+ .get_sqi = genphy_c45_oatc14_get_sqi,
+ .get_sqi_max = genphy_c45_oatc14_get_sqi_max,
+ .read_mmd = ncn26000_read_mmd,
+ .write_mmd = ncn26000_write_mmd,
+ .cable_test_get_status = genphy_c45_oatc14_cable_test_get_status,
+ .cable_test_start = genphy_c45_oatc14_cable_test_start,
+ },
{
PHY_ID_MATCH_MODEL(PHY_ID_NCN26000),
- .name = "NCN26000",
- .features = PHY_BASIC_T1S_P2MP_FEATURES,
- .config_init = ncn26000_config_init,
- .config_intr = ncn26000_config_intr,
- .config_aneg = ncn26000_config_aneg,
- .read_status = ncn26000_read_status,
- .handle_interrupt = ncn26000_handle_interrupt,
- .get_plca_cfg = genphy_c45_plca_get_cfg,
- .set_plca_cfg = genphy_c45_plca_set_cfg,
- .get_plca_status = genphy_c45_plca_get_status,
- .soft_reset = genphy_soft_reset,
+ .name = "NCN26000",
+ .features = PHY_BASIC_T1S_P2MP_FEATURES,
+ .remove = ncn26000_remove,
+ .config_init = ncn26000_config_init,
+ .config_intr = ncn26000_config_intr,
+ .config_aneg = ncn26000_config_aneg,
+ .read_status = ncn26000_read_status,
+ .handle_interrupt = ncn26000_handle_interrupt,
+ .set_plca_cfg = ncn26000_plca_set_cfg,
+ .get_plca_cfg = genphy_c45_plca_get_cfg,
+ .get_plca_status = genphy_c45_plca_get_status,
+ .soft_reset = genphy_soft_reset,
+ .read_mmd = ncn26000_read_mmd,
+ .write_mmd = ncn26000_write_mmd,
},
};
@@ -161,11 +235,12 @@ module_phy_driver(ncn26000_driver);
static const struct mdio_device_id __maybe_unused ncn26000_tbl[] = {
{ PHY_ID_MATCH_MODEL(PHY_ID_NCN26000) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_TS2500) },
{ }
};
MODULE_DEVICE_TABLE(mdio, ncn26000_tbl);
-MODULE_AUTHOR("Piergiorgio Beruto");
+MODULE_AUTHOR("Piergiorgio Beruto <Pier.Beruto@onsemi.com>");
MODULE_DESCRIPTION("onsemi 10BASE-T1S PHY driver");
MODULE_LICENSE("Dual BSD/GPL");
--
2.43.0
Public Information
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH net-next 2/5] net: phy: ncn26000: add support for TS2500 internal PHY
2026-05-01 19:15 [PATCH net-next 2/5] net: phy: ncn26000: add support for TS2500 internal PHY Selvamani Rajagopal
@ 2026-05-01 19:50 ` Andrew Lunn
0 siblings, 0 replies; 2+ messages in thread
From: Andrew Lunn @ 2026-05-01 19:50 UTC (permalink / raw)
To: Selvamani Rajagopal
Cc: Piergiorgio Beruto, hkallweit1@gmail.com, linux@armlinux.org.uk,
davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
> +/* clause 45 vendor specific registers */
> +#define NCN26000_REG_PHYCFG1_MMD MDIO_MMD_VEND2
Please use MDIO_MMD_VEND2 rather than obfuscating it.
There is a lot going on in this patch, with no real explanation in the
commit message. Please break it up into a number of smaller commits
with good commit messages.
Andrew
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-05-01 19:50 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-01 19:15 [PATCH net-next 2/5] net: phy: ncn26000: add support for TS2500 internal PHY Selvamani Rajagopal
2026-05-01 19:50 ` Andrew Lunn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox