Commit 7d272e63 authored by Antoine Tenart's avatar Antoine Tenart Committed by David S. Miller

net: phy: mscc: timestamping and PHC support

This patch adds support for PHC and timestamping operations for the MSCC
PHY. PTP 1-step and 2-step modes are supported, over Ethernet and UDP.

To get and set the PHC time, a GPIO has to be used and changes are only
retrieved or committed when on a rising edge. The same GPIO is shared by
all PHYs, so the granularity of the lock protecting it has to be
different from the ones protecting the 1588 registers (the VSC8584 PHY
has 2 1588 blocks, and a single load/save pin).
Co-developed-by: default avatarQuentin Schulz <quentin.schulz@bootlin.com>
Signed-off-by: default avatarQuentin Schulz <quentin.schulz@bootlin.com>
Signed-off-by: default avatarAntoine Tenart <antoine.tenart@bootlin.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ab2bf933
...@@ -375,8 +375,12 @@ struct vsc8531_private { ...@@ -375,8 +375,12 @@ struct vsc8531_private {
unsigned long egr_flows; unsigned long egr_flows;
#endif #endif
struct mii_timestamper mii_ts;
bool input_clk_init; bool input_clk_init;
struct vsc85xx_ptp *ptp; struct vsc85xx_ptp *ptp;
/* LOAD/SAVE GPIO pin, used for retrieving or setting time to the PHC. */
struct gpio_desc *load_save;
/* For multiple port PHYs; the MDIO address of the base PHY in the /* For multiple port PHYs; the MDIO address of the base PHY in the
* pair of two PHYs that share a 1588 engine. PHY0 and PHY2 are coupled. * pair of two PHYs that share a 1588 engine. PHY0 and PHY2 are coupled.
...@@ -386,8 +390,19 @@ struct vsc8531_private { ...@@ -386,8 +390,19 @@ struct vsc8531_private {
unsigned int ts_base_addr; unsigned int ts_base_addr;
u8 ts_base_phy; u8 ts_base_phy;
/* ts_lock: used for per-PHY timestamping operations. */ /* ts_lock: used for per-PHY timestamping operations.
* phc_lock: used for per-PHY PHC opertations.
*/
struct mutex ts_lock; struct mutex ts_lock;
struct mutex phc_lock;
};
/* Shared structure between the PHYs of the same package.
* gpio_lock: used for PHC operations. Common for all PHYs as the load/save GPIO
* is shared.
*/
struct vsc85xx_shared_private {
struct mutex gpio_lock;
}; };
#if IS_ENABLED(CONFIG_OF_MDIO) #if IS_ENABLED(CONFIG_OF_MDIO)
...@@ -416,20 +431,34 @@ static inline void vsc8584_config_macsec_intr(struct phy_device *phydev) ...@@ -416,20 +431,34 @@ static inline void vsc8584_config_macsec_intr(struct phy_device *phydev)
#if IS_ENABLED(CONFIG_NETWORK_PHY_TIMESTAMPING) #if IS_ENABLED(CONFIG_NETWORK_PHY_TIMESTAMPING)
void vsc85xx_link_change_notify(struct phy_device *phydev); void vsc85xx_link_change_notify(struct phy_device *phydev);
void vsc8584_config_ts_intr(struct phy_device *phydev);
int vsc8584_ptp_init(struct phy_device *phydev); int vsc8584_ptp_init(struct phy_device *phydev);
int vsc8584_ptp_probe_once(struct phy_device *phydev);
int vsc8584_ptp_probe(struct phy_device *phydev); int vsc8584_ptp_probe(struct phy_device *phydev);
irqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev);
#else #else
static inline void vsc85xx_link_change_notify(struct phy_device *phydev) static inline void vsc85xx_link_change_notify(struct phy_device *phydev)
{ {
} }
static inline void vsc8584_config_ts_intr(struct phy_device *phydev)
{
}
static inline int vsc8584_ptp_init(struct phy_device *phydev) static inline int vsc8584_ptp_init(struct phy_device *phydev)
{ {
return 0; return 0;
} }
static inline int vsc8584_ptp_probe_once(struct phy_device *phydev)
{
return 0;
}
static inline int vsc8584_ptp_probe(struct phy_device *phydev) static inline int vsc8584_ptp_probe(struct phy_device *phydev)
{ {
return 0; return 0;
} }
static inline irqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev)
{
return IRQ_NONE;
}
#endif #endif
#endif /* _MSCC_PHY_H_ */ #endif /* _MSCC_PHY_H_ */
...@@ -1475,12 +1475,20 @@ static int vsc8584_config_init(struct phy_device *phydev) ...@@ -1475,12 +1475,20 @@ static int vsc8584_config_init(struct phy_device *phydev)
static irqreturn_t vsc8584_handle_interrupt(struct phy_device *phydev) static irqreturn_t vsc8584_handle_interrupt(struct phy_device *phydev)
{ {
irqreturn_t ret;
int irq_status; int irq_status;
irq_status = phy_read(phydev, MII_VSC85XX_INT_STATUS); irq_status = phy_read(phydev, MII_VSC85XX_INT_STATUS);
if (irq_status < 0 || !(irq_status & MII_VSC85XX_INT_MASK_MASK)) if (irq_status < 0)
return IRQ_NONE; return IRQ_NONE;
/* Timestamping IRQ does not set a bit in the global INT_STATUS, so
* irq_status would be 0.
*/
ret = vsc8584_handle_ts_interrupt(phydev);
if (!(irq_status & MII_VSC85XX_INT_MASK_MASK))
return ret;
if (irq_status & MII_VSC85XX_INT_MASK_EXT) if (irq_status & MII_VSC85XX_INT_MASK_EXT)
vsc8584_handle_macsec_interrupt(phydev); vsc8584_handle_macsec_interrupt(phydev);
...@@ -1920,6 +1928,7 @@ static int vsc85xx_config_intr(struct phy_device *phydev) ...@@ -1920,6 +1928,7 @@ static int vsc85xx_config_intr(struct phy_device *phydev)
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
vsc8584_config_macsec_intr(phydev); vsc8584_config_macsec_intr(phydev);
vsc8584_config_ts_intr(phydev);
rc = phy_write(phydev, MII_VSC85XX_INT_MASK, rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
MII_VSC85XX_INT_MASK_MASK); MII_VSC85XX_INT_MASK_MASK);
...@@ -2033,8 +2042,8 @@ static int vsc8584_probe(struct phy_device *phydev) ...@@ -2033,8 +2042,8 @@ static int vsc8584_probe(struct phy_device *phydev)
phydev->priv = vsc8531; phydev->priv = vsc8531;
vsc8584_get_base_addr(phydev); vsc8584_get_base_addr(phydev);
devm_phy_package_join(&phydev->mdio.dev, phydev, devm_phy_package_join(&phydev->mdio.dev, phydev, vsc8531->base_addr,
vsc8531->base_addr, 0); sizeof(struct vsc85xx_shared_private));
vsc8531->nleds = 4; vsc8531->nleds = 4;
vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES; vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
...@@ -2045,6 +2054,12 @@ static int vsc8584_probe(struct phy_device *phydev) ...@@ -2045,6 +2054,12 @@ static int vsc8584_probe(struct phy_device *phydev)
if (!vsc8531->stats) if (!vsc8531->stats)
return -ENOMEM; return -ENOMEM;
if (phy_package_probe_once(phydev)) {
ret = vsc8584_ptp_probe_once(phydev);
if (ret)
return ret;
}
ret = vsc8584_ptp_probe(phydev); ret = vsc8584_ptp_probe(phydev);
if (ret) if (ret)
return ret; return ret;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment