mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
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: Quentin Schulz <quentin.schulz@bootlin.com> Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com> Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
ab2bf93393
commit
7d272e63e0
@@ -375,8 +375,12 @@ struct vsc8531_private {
|
||||
unsigned long egr_flows;
|
||||
#endif
|
||||
|
||||
struct mii_timestamper mii_ts;
|
||||
|
||||
bool input_clk_init;
|
||||
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
|
||||
* pair of two PHYs that share a 1588 engine. PHY0 and PHY2 are coupled.
|
||||
@@ -386,8 +390,19 @@ struct vsc8531_private {
|
||||
unsigned int ts_base_addr;
|
||||
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 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)
|
||||
@@ -416,20 +431,34 @@ static inline void vsc8584_config_macsec_intr(struct phy_device *phydev)
|
||||
|
||||
#if IS_ENABLED(CONFIG_NETWORK_PHY_TIMESTAMPING)
|
||||
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_probe_once(struct phy_device *phydev);
|
||||
int vsc8584_ptp_probe(struct phy_device *phydev);
|
||||
irqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev);
|
||||
#else
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline irqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev)
|
||||
{
|
||||
return IRQ_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _MSCC_PHY_H_ */
|
||||
|
||||
@@ -1475,12 +1475,20 @@ err:
|
||||
|
||||
static irqreturn_t vsc8584_handle_interrupt(struct phy_device *phydev)
|
||||
{
|
||||
irqreturn_t ret;
|
||||
int irq_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;
|
||||
|
||||
/* 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)
|
||||
vsc8584_handle_macsec_interrupt(phydev);
|
||||
|
||||
@@ -1920,6 +1928,7 @@ static int vsc85xx_config_intr(struct phy_device *phydev)
|
||||
|
||||
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
|
||||
vsc8584_config_macsec_intr(phydev);
|
||||
vsc8584_config_ts_intr(phydev);
|
||||
|
||||
rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
|
||||
MII_VSC85XX_INT_MASK_MASK);
|
||||
@@ -2033,8 +2042,8 @@ static int vsc8584_probe(struct phy_device *phydev)
|
||||
phydev->priv = vsc8531;
|
||||
|
||||
vsc8584_get_base_addr(phydev);
|
||||
devm_phy_package_join(&phydev->mdio.dev, phydev,
|
||||
vsc8531->base_addr, 0);
|
||||
devm_phy_package_join(&phydev->mdio.dev, phydev, vsc8531->base_addr,
|
||||
sizeof(struct vsc85xx_shared_private));
|
||||
|
||||
vsc8531->nleds = 4;
|
||||
vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
|
||||
@@ -2045,6 +2054,12 @@ static int vsc8584_probe(struct phy_device *phydev)
|
||||
if (!vsc8531->stats)
|
||||
return -ENOMEM;
|
||||
|
||||
if (phy_package_probe_once(phydev)) {
|
||||
ret = vsc8584_ptp_probe_once(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = vsc8584_ptp_probe(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user