Add generic Clause 45 helpers to support the Open Alliance TC10 10BASE-T1S Sleep/Wake-up specification. This patch introduces register definitions for the TC10 sleep/wake status and control registers and adds generic suspend/resume helpers for OATC10-compliant PHYs. The new genphy_c45_oatc10_suspend() helper verifies low-power capability, caches the current PLCA configuration, and requests entry into the low-power sleep state. Since all PHY configuration is lost while sleeping, the PLCA configuration is stored in the phy_device structure for restoration after wake-up. The corresponding genphy_c45_oatc10_resume() helper reinitializes the PHY after wake-up and restores the cached PLCA configuration using driver callbacks. Additionally, the PLCA configuration structure is moved into struct phy_device to allow persistent storage across suspend/resume cycles. These helpers allow PHY drivers for TC10 10BASE-T1S devices to implement sleep and wake-up handling in a consistent way without duplicating common logic. Open Alliance TC10 10BASE-T1S Sleep/Wake-up Specification ref: https://opensig.org/wp-content/uploads/2024/01/TC14_TC10_JWG_10BASE-T1S-Sleep-Wake-up-Specification_1.0_final.pdf Signed-off-by: Parthiban Veerasooran --- drivers/net/phy/mdio-open-alliance.h | 13 ++++ drivers/net/phy/phy-c45.c | 82 ++++++++++++++++++++++++++ include/linux/phy.h | 88 +++++++++++++++------------- 3 files changed, 141 insertions(+), 42 deletions(-) diff --git a/drivers/net/phy/mdio-open-alliance.h b/drivers/net/phy/mdio-open-alliance.h index 449d0fb67093..62946be9fb78 100644 --- a/drivers/net/phy/mdio-open-alliance.h +++ b/drivers/net/phy/mdio-open-alliance.h @@ -78,6 +78,19 @@ /* SQI is supported using 3 bits means 8 levels (0-7) */ #define OATC14_SQI_MAX_LEVEL 7 +/* Open Alliance 10BASE-T1S Sleep/Wake-up Registers + * Specification: + * "10BASE-T1S Sleep/Wake-up Specification" + * https://opensig.org/wp-content/uploads/2024/01/TC14_TC10_JWG_10BASE-T1S-Sleep-Wake-up-Specification_1.0_final.pdf + */ +/* Sleep/Wake-up Status Register */ +#define MDIO_OATC10_WS_STATUS 0xd000 +#define OATC10_WS_STATUS_LPCAP BIT(15) /* PM client capability */ + +/* Sleep/Wake-up Control Register */ +#define MDIO_OATC10_WS_CONTROL 0xd001 +#define OATC10_WS_CONTROL_LPREQ BIT(15) /* Request low power */ + /* Bus Short/Open Status: * 0 0 - no fault; everything is ok. (Default) * 0 1 - detected as an open or missing termination(s) diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index d48aa7231b37..627eaae9e60f 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -1832,3 +1832,85 @@ int genphy_c45_oatc14_get_sqi(struct phy_device *phydev) return ret & OATC14_DCQ_SQI_VALUE; } EXPORT_SYMBOL(genphy_c45_oatc14_get_sqi); + +/** + * genphy_c45_oatc10_suspend - Suspend OATC10 PHY into low power state + * @phydev: PHY device to suspend + * + * Puts an OATC10 PHY into low power sleep state. + * + * The function performs the following steps: + * 1. Verify low power capability is supported + * 2. Cache current PLCA configuration for restoration on wake + * 3. Set the low power request bit to enter sleep state + * + * Return: + * * 0 on successful entry to low power state + * * -EOPNOTSUPP if PHY doesn't support low power capability + * * Negative error code on register read/write failures + */ +int genphy_c45_oatc10_suspend(struct phy_device *phydev) +{ + int ret; + + /* Check for Low Power capability */ + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC10_WS_STATUS); + if (ret < 0) + return ret; + + if (!(ret & OATC10_WS_STATUS_LPCAP)) + return -EOPNOTSUPP; + + /* Cache PLCA settings for later use. These values must be restored when + * the PHY wakes up from the low-power sleep state, as all configured + * settings are lost. + */ + ret = genphy_c45_plca_get_cfg(phydev, &phydev->plca_cfg); + if (ret) + return ret; + + phydev->plca_cfg.version = -1; + + if (phydev->state == PHY_UP) + /* Put the PHY into low power sleep state */ + return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, + MDIO_OATC10_WS_CONTROL, + OATC10_WS_CONTROL_LPREQ); + + return 0; +} +EXPORT_SYMBOL(genphy_c45_oatc10_suspend); + +/** + * genphy_c45_oatc10_resume - Resume OATC10 PHY from low-power sleep state + * @phydev: PHY device to resume + * + * Resume a PHY from suspend state. When the PHY wakes up from the low-power + * sleep state, all configured settings are lost. This function reinitializes + * the PHY configuration settings. + * + * Return: 0 on success, negative errno on failure + */ +int genphy_c45_oatc10_resume(struct phy_device *phydev) +{ + int ret; + + if (!phydev->suspended) + return 0; + + /* When the PHY wakes up from the low-power sleep state, it needs to be + * reinitialized as all configured settings are lost. + */ + if (phydev->drv->config_init) { + ret = phydev->drv->config_init(phydev); + if (ret) + return ret; + } + + /* Reconfigure the PHY with cached PLCA settings */ + if (phydev->drv->set_plca_cfg) + return phydev->drv->set_plca_cfg(phydev, &phydev->plca_cfg); + + return 0; +} +EXPORT_SYMBOL(genphy_c45_oatc10_resume); diff --git a/include/linux/phy.h b/include/linux/phy.h index 5de4b172cd0b..9bee520ac421 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -555,6 +555,48 @@ struct phy_oatc14_sqi_capability { u8 sqiplus_bits; }; +/** + * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision + * Avoidance) Reconciliation Sublayer. + * + * @version: read-only PLCA register map version. -1 = not available. Ignored + * when setting the configuration. Format is the same as reported by the PLCA + * IDVER register (31.CA00). -1 = not available. + * @enabled: PLCA configured mode (enabled/disabled). -1 = not available / don't + * set. 0 = disabled, anything else = enabled. + * @node_id: the PLCA local node identifier. -1 = not available / don't set. + * Allowed values [0 .. 254]. 255 = node disabled. + * @node_cnt: the PLCA node count (maximum number of nodes having a TO). Only + * meaningful for the coordinator (node_id = 0). -1 = not available / don't + * set. Allowed values [1 .. 255]. + * @to_tmr: The value of the PLCA to_timer in bit-times, which determines the + * PLCA transmit opportunity window opening. See IEEE802.3 Clause 148 for + * more details. The to_timer shall be set equal over all nodes. + * -1 = not available / don't set. Allowed values [0 .. 255]. + * @burst_cnt: controls how many additional frames a node is allowed to send in + * single transmit opportunity (TO). The default value of 0 means that the + * node is allowed exactly one frame per TO. A value of 1 allows two frames + * per TO, and so on. -1 = not available / don't set. + * Allowed values [0 .. 255]. + * @burst_tmr: controls how many bit times to wait for the MAC to send a new + * frame before interrupting the burst. This value should be set to a value + * greater than the MAC inter-packet gap (which is typically 96 bits). + * -1 = not available / don't set. Allowed values [0 .. 255]. + * + * A structure containing configuration parameters for setting/getting the PLCA + * RS configuration. The driver does not need to implement all the parameters, + * but should report what is actually used. + */ +struct phy_plca_cfg { + int version; + int enabled; + int node_id; + int node_cnt; + int to_tmr; + int burst_cnt; + int burst_tmr; +}; + /** * struct phy_device - An instance of a PHY * @@ -655,6 +697,7 @@ struct phy_oatc14_sqi_capability { * @shared: Pointer to private data shared by phys in one package * @priv: Pointer to driver private data * @oatc14_sqi_capability: SQI capability information for OATC14 10Base-T1S PHY + * @plca_cfg: Cache PLCA configuration for OATC10 compliance 10Base-T1S PHY * * interrupts currently only supports enabled or disabled, * but could be changed in the future to support enabling @@ -807,6 +850,7 @@ struct phy_device { #endif struct phy_oatc14_sqi_capability oatc14_sqi_capability; + struct phy_plca_cfg plca_cfg; }; /* Generic phy_device::dev_flags */ @@ -858,48 +902,6 @@ enum link_inband_signalling { LINK_INBAND_BYPASS = BIT(2), }; -/** - * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision - * Avoidance) Reconciliation Sublayer. - * - * @version: read-only PLCA register map version. -1 = not available. Ignored - * when setting the configuration. Format is the same as reported by the PLCA - * IDVER register (31.CA00). -1 = not available. - * @enabled: PLCA configured mode (enabled/disabled). -1 = not available / don't - * set. 0 = disabled, anything else = enabled. - * @node_id: the PLCA local node identifier. -1 = not available / don't set. - * Allowed values [0 .. 254]. 255 = node disabled. - * @node_cnt: the PLCA node count (maximum number of nodes having a TO). Only - * meaningful for the coordinator (node_id = 0). -1 = not available / don't - * set. Allowed values [1 .. 255]. - * @to_tmr: The value of the PLCA to_timer in bit-times, which determines the - * PLCA transmit opportunity window opening. See IEEE802.3 Clause 148 for - * more details. The to_timer shall be set equal over all nodes. - * -1 = not available / don't set. Allowed values [0 .. 255]. - * @burst_cnt: controls how many additional frames a node is allowed to send in - * single transmit opportunity (TO). The default value of 0 means that the - * node is allowed exactly one frame per TO. A value of 1 allows two frames - * per TO, and so on. -1 = not available / don't set. - * Allowed values [0 .. 255]. - * @burst_tmr: controls how many bit times to wait for the MAC to send a new - * frame before interrupting the burst. This value should be set to a value - * greater than the MAC inter-packet gap (which is typically 96 bits). - * -1 = not available / don't set. Allowed values [0 .. 255]. - * - * A structure containing configuration parameters for setting/getting the PLCA - * RS configuration. The driver does not need to implement all the parameters, - * but should report what is actually used. - */ -struct phy_plca_cfg { - int version; - int enabled; - int node_id; - int node_cnt; - int to_tmr; - int burst_cnt; - int burst_tmr; -}; - /** * struct phy_plca_status - Status of the PLCA (Physical Layer Collision * Avoidance) Reconciliation Sublayer. @@ -2333,6 +2335,8 @@ int genphy_c45_oatc14_cable_test_get_status(struct phy_device *phydev, bool *finished); int genphy_c45_oatc14_get_sqi_max(struct phy_device *phydev); int genphy_c45_oatc14_get_sqi(struct phy_device *phydev); +int genphy_c45_oatc10_suspend(struct phy_device *phydev); +int genphy_c45_oatc10_resume(struct phy_device *phydev); /* The gen10g_* functions are the old Clause 45 stub */ int gen10g_config_aneg(struct phy_device *phydev); -- 2.34.1