Skip to content

Commit

Permalink
drivers/net/phy: add helpers to get/set PLCA configuration
Browse files Browse the repository at this point in the history
This patch adds support in phylib to read/write PLCA configuration for
Ethernet PHYs that support the OPEN Alliance "10BASE-T1S PLCA
Management Registers" specifications. These can be found at
https://www.opensig.org/about/specifications/

Signed-off-by: Piergiorgio Beruto <piergiorgio.beruto@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
pberuto authored and davem330 committed Jan 11, 2023
1 parent a23a1e5 commit 4933234
Show file tree
Hide file tree
Showing 4 changed files with 246 additions and 0 deletions.
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -16620,6 +16620,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
46 changes: 46 additions & 0 deletions drivers/net/phy/mdio-open-alliance.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* 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>

/* NOTE: all OATC14 registers are located in 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 BIT(15) /* PLCA enable */
#define MDIO_OATC14_PLCA_RST BIT(14) /* 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 BIT(15) /* 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

/* Version Identifiers */
#define OATC14_IDM 0x0a00

#endif /* __MDIO_OPEN_ALLIANCE__ */
193 changes: 193 additions & 0 deletions drivers/net/phy/phy-c45.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include <linux/mii.h>
#include <linux/phy.h>

#include "mdio-open-alliance.h"

/**
* genphy_c45_baset1_able - checks if the PMA has BASE-T1 extended abilities
* @phydev: target phy_device struct
Expand Down Expand Up @@ -931,6 +933,197 @@ int genphy_c45_fast_retrain(struct phy_device *phydev, bool enable)
}
EXPORT_SYMBOL_GPL(genphy_c45_fast_retrain);

/**
* genphy_c45_plca_get_cfg - get PLCA configuration from standard registers
* @phydev: target phy_device struct
* @plca_cfg: output structure to store the PLCA configuration
*
* Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA
* Management Registers specifications, this function can be used to retrieve
* the current PLCA configuration from the standard registers in MMD 31.
*/
int genphy_c45_plca_get_cfg(struct phy_device *phydev,
struct phy_plca_cfg *plca_cfg)
{
int ret;

ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_IDVER);
if (ret < 0)
return ret;

if ((ret & MDIO_OATC14_PLCA_IDM) != OATC14_IDM)
return -ENODEV;

plca_cfg->version = ret & ~MDIO_OATC14_PLCA_IDM;

ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_CTRL0);
if (ret < 0)
return ret;

plca_cfg->enabled = !!(ret & MDIO_OATC14_PLCA_EN);

ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_CTRL1);
if (ret < 0)
return ret;

plca_cfg->node_cnt = (ret & MDIO_OATC14_PLCA_NCNT) >> 8;
plca_cfg->node_id = (ret & MDIO_OATC14_PLCA_ID);

ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_TOTMR);
if (ret < 0)
return ret;

plca_cfg->to_tmr = ret & MDIO_OATC14_PLCA_TOT;

ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_BURST);
if (ret < 0)
return ret;

plca_cfg->burst_cnt = (ret & MDIO_OATC14_PLCA_MAXBC) >> 8;
plca_cfg->burst_tmr = (ret & MDIO_OATC14_PLCA_BTMR);

return 0;
}
EXPORT_SYMBOL_GPL(genphy_c45_plca_get_cfg);

/**
* genphy_c45_plca_set_cfg - set PLCA configuration using standard registers
* @phydev: target phy_device struct
* @plca_cfg: structure containing the PLCA configuration. Fields set to -1 are
* not to be changed.
*
* Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA
* Management Registers specifications, this function can be used to modify
* the PLCA configuration using the standard registers in MMD 31.
*/
int genphy_c45_plca_set_cfg(struct phy_device *phydev,
const struct phy_plca_cfg *plca_cfg)
{
int ret;
u16 val;

// PLCA IDVER is read-only
if (plca_cfg->version >= 0)
return -EINVAL;

// first of all, disable PLCA if required
if (plca_cfg->enabled == 0) {
ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,
MDIO_OATC14_PLCA_CTRL0,
MDIO_OATC14_PLCA_EN);

if (ret < 0)
return ret;
}

// check if we need to set the PLCA node count, node ID, or both
if (plca_cfg->node_cnt >= 0 || plca_cfg->node_id >= 0) {
/* if one between node count and node ID is -not- to be
* changed, read the register to later perform merge/purge of
* the configuration as appropriate
*/
if (plca_cfg->node_cnt < 0 || plca_cfg->node_id < 0) {
ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
MDIO_OATC14_PLCA_CTRL1);

if (ret < 0)
return ret;

val = ret;
}

if (plca_cfg->node_cnt >= 0)
val = (val & ~MDIO_OATC14_PLCA_NCNT) |
(plca_cfg->node_cnt << 8);

if (plca_cfg->node_id >= 0)
val = (val & ~MDIO_OATC14_PLCA_ID) |
(plca_cfg->node_id);

ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
MDIO_OATC14_PLCA_CTRL1, val);

if (ret < 0)
return ret;
}

if (plca_cfg->to_tmr >= 0) {
ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
MDIO_OATC14_PLCA_TOTMR,
plca_cfg->to_tmr);

if (ret < 0)
return ret;
}

// check if we need to set the PLCA burst count, burst timer, or both
if (plca_cfg->burst_cnt >= 0 || plca_cfg->burst_tmr >= 0) {
/* if one between burst count and burst timer is -not- to be
* changed, read the register to later perform merge/purge of
* the configuration as appropriate
*/
if (plca_cfg->burst_cnt < 0 || plca_cfg->burst_tmr < 0) {
ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
MDIO_OATC14_PLCA_BURST);

if (ret < 0)
return ret;

val = ret;
}

if (plca_cfg->burst_cnt >= 0)
val = (val & ~MDIO_OATC14_PLCA_MAXBC) |
(plca_cfg->burst_cnt << 8);

if (plca_cfg->burst_tmr >= 0)
val = (val & ~MDIO_OATC14_PLCA_BTMR) |
(plca_cfg->burst_tmr);

ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
MDIO_OATC14_PLCA_BURST, val);

if (ret < 0)
return ret;
}

// if we need to enable PLCA, do it at the end
if (plca_cfg->enabled > 0) {
ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
MDIO_OATC14_PLCA_CTRL0,
MDIO_OATC14_PLCA_EN);

if (ret < 0)
return ret;
}

return 0;
}
EXPORT_SYMBOL_GPL(genphy_c45_plca_set_cfg);

/**
* genphy_c45_plca_get_status - get PLCA status from standard registers
* @phydev: target phy_device struct
* @plca_st: output structure to store the PLCA status
*
* Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA
* Management Registers specifications, this function can be used to retrieve
* the current PLCA status information from the standard registers in MMD 31.
*/
int genphy_c45_plca_get_status(struct phy_device *phydev,
struct phy_plca_status *plca_st)
{
int ret;

ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_STATUS);
if (ret < 0)
return ret;

plca_st->pst = !!(ret & MDIO_OATC14_PLCA_PST);
return 0;
}
EXPORT_SYMBOL_GPL(genphy_c45_plca_get_status);

struct phy_driver genphy_c45_driver = {
.phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff,
Expand Down
6 changes: 6 additions & 0 deletions include/linux/phy.h
Original file line number Diff line number Diff line change
Expand Up @@ -1753,6 +1753,12 @@ int genphy_c45_loopback(struct phy_device *phydev, bool enable);
int genphy_c45_pma_resume(struct phy_device *phydev);
int genphy_c45_pma_suspend(struct phy_device *phydev);
int genphy_c45_fast_retrain(struct phy_device *phydev, bool enable);
int genphy_c45_plca_get_cfg(struct phy_device *phydev,
struct phy_plca_cfg *plca_cfg);
int genphy_c45_plca_set_cfg(struct phy_device *phydev,
const struct phy_plca_cfg *plca_cfg);
int genphy_c45_plca_get_status(struct phy_device *phydev,
struct phy_plca_status *plca_st);

/* Generic C45 PHY driver */
extern struct phy_driver genphy_c45_driver;
Expand Down

0 comments on commit 4933234

Please sign in to comment.