public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [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

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