Skip to content

Commit

Permalink
drivers/net/phy: add driver for the onsemi NCN26000 10BASE-T1S PHY
Browse files Browse the repository at this point in the history
Add support for the onsemi NCN26000 10BASE-T1S industrial Ethernet PHY.
The driver supports Point-to-Multipoint operation without
auto-negotiation and with link control handling. The PLCA RS support
will be included on a separate patch.

Signed-off-by: Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
  • Loading branch information
pberuto authored and intel-lab-lkp committed Dec 5, 2022
1 parent e3f89ea commit 91aaf14
Show file tree
Hide file tree
Showing 7 changed files with 433 additions and 0 deletions.
8 changes: 8 additions & 0 deletions MAINTAINERS
Expand Up @@ -15357,6 +15357,13 @@ L: linux-mips@vger.kernel.org
S: Maintained
F: arch/mips/boot/dts/ralink/omega2p.dts

ONSEMI ETHERNET PHY DRIVERS
M: Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
L: netdev@vger.kernel.org
S: Supported
W: http://www.onsemi.com
F: drivers/net/phy/ncn*

OP-TEE DRIVER
M: Jens Wiklander <jens.wiklander@linaro.org>
L: op-tee@lists.trustedfirmware.org
Expand Down Expand Up @@ -16400,6 +16407,7 @@ PLCA RECONCILIATION SUBLAYER (IEEE802.3 Clause 148)
M: Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/phy/mdio-open-alliance.h
F: net/ethtool/plca.c

PLDMFW LIBRARY
Expand Down
7 changes: 7 additions & 0 deletions drivers/net/phy/Kconfig
Expand Up @@ -267,6 +267,13 @@ config NATIONAL_PHY
help
Currently supports the DP83865 PHY.

config NCN26000_PHY
tristate "onsemi 10BASE-T1S Ethernet PHY"
help
Adds support for the onsemi 10BASE-T1S Ethernet PHY.
Currently supports the NCN26000 10BASE-T1S Industrial PHY
with MII interface.

config NXP_C45_TJA11XX_PHY
tristate "NXP C45 TJA11XX PHYs"
depends on PTP_1588_CLOCK_OPTIONAL
Expand Down
1 change: 1 addition & 0 deletions drivers/net/phy/Makefile
Expand Up @@ -77,6 +77,7 @@ obj-$(CONFIG_MICROCHIP_T1_PHY) += microchip_t1.o
obj-$(CONFIG_MICROSEMI_PHY) += mscc/
obj-$(CONFIG_MOTORCOMM_PHY) += motorcomm.o
obj-$(CONFIG_NATIONAL_PHY) += national.o
obj-$(CONFIG_NCN26000_PHY) += ncn26000.o
obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja11xx.o
obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
Expand Down
44 changes: 44 additions & 0 deletions drivers/net/phy/mdio-open-alliance.h
@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* mdio-open-alliance.h - definition of OPEN Alliance SIG standard registers
*/

#ifndef __MDIO_OPEN_ALLIANCE__
#define __MDIO_OPEN_ALLIANCE__

#include <linux/mdio.h>

/* MDIO Manageable Devices (MMDs). */
#define MDIO_MMD_OATC14 MDIO_MMD_VEND2

/* Open Alliance TC14 (10BASE-T1S) registers */
#define MDIO_OATC14_PLCA_IDVER 0xca00 /* PLCA ID and version */
#define MDIO_OATC14_PLCA_CTRL0 0xca01 /* PLCA Control register 0 */
#define MDIO_OATC14_PLCA_CTRL1 0xca02 /* PLCA Control register 1 */
#define MDIO_OATC14_PLCA_STATUS 0xca03 /* PLCA Status register */
#define MDIO_OATC14_PLCA_TOTMR 0xca04 /* PLCA TO Timer register */
#define MDIO_OATC14_PLCA_BURST 0xca05 /* PLCA BURST mode register */

/* Open Alliance TC14 PLCA IDVER register */
#define MDIO_OATC14_PLCA_IDM 0xff00 /* PLCA MAP ID */
#define MDIO_OATC14_PLCA_VER 0x00ff /* PLCA MAP version */

/* Open Alliance TC14 PLCA CTRL0 register */
#define MDIO_OATC14_PLCA_EN 0x8000 /* PLCA enable */
#define MDIO_OATC14_PLCA_RST 0x4000 /* PLCA reset */

/* Open Alliance TC14 PLCA CTRL1 register */
#define MDIO_OATC14_PLCA_NCNT 0xff00 /* PLCA node count */
#define MDIO_OATC14_PLCA_ID 0x00ff /* PLCA local node ID */

/* Open Alliance TC14 PLCA STATUS register */
#define MDIO_OATC14_PLCA_PST 0x8000 /* PLCA status indication */

/* Open Alliance TC14 PLCA TOTMR register */
#define MDIO_OATC14_PLCA_TOT 0x00ff

/* Open Alliance TC14 PLCA BURST register */
#define MDIO_OATC14_PLCA_MAXBC 0xff00
#define MDIO_OATC14_PLCA_BTMR 0x00ff

#endif /* __MDIO_OPEN_ALLIANCE__ */
187 changes: 187 additions & 0 deletions drivers/net/phy/ncn26000.c
@@ -0,0 +1,187 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
* Driver for the onsemi 10BASE-T1S NCN26000 PHYs family.
*
* Copyright 2022 onsemi
*/
#include <linux/kernel.h>
#include <linux/bitfield.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/phy.h>

#include "mdio-open-alliance.h"

#define PHY_ID_NCN26000 0x180FF5A1

#define NCN26000_REG_IRQ_CTL 16
#define NCN26000_REG_IRQ_STATUS 17

// the NCN26000 maps link_ctrl to BMCR_ANENABLE
#define NCN26000_BCMR_LINK_CTRL_BIT BMCR_ANENABLE

// the NCN26000 maps link_status to BMSR_ANEGCOMPLETE
#define NCN26000_BMSR_LINK_STATUS_BIT BMSR_ANEGCOMPLETE

#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 TO_TMR_DEFAULT 32

struct ncn26000_priv {
u16 enabled_irqs;
};

// module parameter: if set, the link status is derived from the PLCA status
// default: false
static bool link_status_plca;
module_param(link_status_plca, bool, 0644);

// driver callbacks

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_OATC14, MDIO_OATC14_PLCA_TOTMR,
TO_TMR_DEFAULT);
}

static int ncn26000_config_aneg(struct phy_device *phydev)
{
// Note: the NCN26000 supports only P2MP link mode. Therefore, AN is not
// supported. However, this function is invoked by phylib to enable the
// PHY, regardless of the AN support.
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);
}

static int ncn26000_get_features(struct phy_device *phydev)
{
linkmode_zero(phydev->supported);
linkmode_set_bit(ETHTOOL_LINK_MODE_MII_BIT, phydev->supported);

linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT,
phydev->supported);

linkmode_copy(phydev->advertising, phydev->supported);
return 0;
}

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. Thus, report the link
// status by testing the appropriate BMSR bit according to the module's
// parameter configuration.
const int lstatus_flag = link_status_plca ?
BMSR_LSTATUS : NCN26000_BMSR_LINK_STATUS_BIT;

int ret;

ret = phy_read(phydev, MII_BMSR);
if (unlikely(ret < 0))
return ret;

// update link status
phydev->link = (ret & lstatus_flag) ? 1 : 0;

// handle more IRQs here

return 0;
}

static irqreturn_t ncn26000_handle_interrupt(struct phy_device *phydev)
{
const struct ncn26000_priv *const priv = phydev->priv;
int ret;

// clear the latched bits in MII_BMSR
phy_read(phydev, MII_BMSR);

// read and aknowledge the IRQ status register
ret = phy_read(phydev, NCN26000_REG_IRQ_STATUS);

if (unlikely(ret < 0) || (ret & priv->enabled_irqs) == 0)
return IRQ_NONE;

phy_trigger_machine(phydev);
return IRQ_HANDLED;
}

static int ncn26000_config_intr(struct phy_device *phydev)
{
int ret;
struct ncn26000_priv *priv = phydev->priv;

if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
// acknowledge IRQs
ret = phy_read(phydev, NCN26000_REG_IRQ_STATUS);
if (ret < 0)
return ret;

// get link status notifications
priv->enabled_irqs = NCN26000_IRQ_LINKST_BIT;
} else {
// disable all IRQs
priv->enabled_irqs = 0;
}

ret = phy_write(phydev, NCN26000_REG_IRQ_CTL, priv->enabled_irqs);
if (ret != 0)
return ret;

return 0;
}

static int ncn26000_probe(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
struct ncn26000_priv *priv;

priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;

phydev->priv = priv;

return 0;
}

static struct phy_driver ncn26000_driver[] = {
{
PHY_ID_MATCH_MODEL(PHY_ID_NCN26000),
.name = "NCN26000",
.probe = ncn26000_probe,
.get_features = ncn26000_get_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,
},
};

module_phy_driver(ncn26000_driver);

MODULE_DEVICE_TABLE(mdio, ncn26000_tbl);
MODULE_AUTHOR("Piergiorgio Beruto");
MODULE_DESCRIPTION("onsemi 10BASE-T1S PHY driver");
MODULE_LICENSE("Dual BSD/GPL");

0 comments on commit 91aaf14

Please sign in to comment.