162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT) 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for Microsemi VSC85xx PHYs - timestamping and PHC support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: Quentin Schulz & Antoine Tenart 662306a36Sopenharmony_ci * License: Dual MIT/GPL 762306a36Sopenharmony_ci * Copyright (c) 2020 Microsemi Corporation 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1162306a36Sopenharmony_ci#include <linux/ip.h> 1262306a36Sopenharmony_ci#include <linux/net_tstamp.h> 1362306a36Sopenharmony_ci#include <linux/mii.h> 1462306a36Sopenharmony_ci#include <linux/phy.h> 1562306a36Sopenharmony_ci#include <linux/ptp_classify.h> 1662306a36Sopenharmony_ci#include <linux/ptp_clock_kernel.h> 1762306a36Sopenharmony_ci#include <linux/udp.h> 1862306a36Sopenharmony_ci#include <asm/unaligned.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "mscc.h" 2162306a36Sopenharmony_ci#include "mscc_ptp.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* Two PHYs share the same 1588 processor and it's to be entirely configured 2462306a36Sopenharmony_ci * through the base PHY of this processor. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci/* phydev->bus->mdio_lock should be locked when using this function */ 2762306a36Sopenharmony_cistatic int phy_ts_base_write(struct phy_device *phydev, u32 regnum, u16 val) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci WARN_ON_ONCE(!mutex_is_locked(&phydev->mdio.bus->mdio_lock)); 3262306a36Sopenharmony_ci return __mdiobus_write(phydev->mdio.bus, priv->ts_base_addr, regnum, 3362306a36Sopenharmony_ci val); 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* phydev->bus->mdio_lock should be locked when using this function */ 3762306a36Sopenharmony_cistatic int phy_ts_base_read(struct phy_device *phydev, u32 regnum) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci WARN_ON_ONCE(!mutex_is_locked(&phydev->mdio.bus->mdio_lock)); 4262306a36Sopenharmony_ci return __mdiobus_read(phydev->mdio.bus, priv->ts_base_addr, regnum); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cienum ts_blk_hw { 4662306a36Sopenharmony_ci INGRESS_ENGINE_0, 4762306a36Sopenharmony_ci EGRESS_ENGINE_0, 4862306a36Sopenharmony_ci INGRESS_ENGINE_1, 4962306a36Sopenharmony_ci EGRESS_ENGINE_1, 5062306a36Sopenharmony_ci INGRESS_ENGINE_2, 5162306a36Sopenharmony_ci EGRESS_ENGINE_2, 5262306a36Sopenharmony_ci PROCESSOR_0, 5362306a36Sopenharmony_ci PROCESSOR_1, 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cienum ts_blk { 5762306a36Sopenharmony_ci INGRESS, 5862306a36Sopenharmony_ci EGRESS, 5962306a36Sopenharmony_ci PROCESSOR, 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic u32 vsc85xx_ts_read_csr(struct phy_device *phydev, enum ts_blk blk, 6362306a36Sopenharmony_ci u16 addr) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 6662306a36Sopenharmony_ci bool base_port = phydev->mdio.addr == priv->ts_base_addr; 6762306a36Sopenharmony_ci u32 val, cnt = 0; 6862306a36Sopenharmony_ci enum ts_blk_hw blk_hw; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci switch (blk) { 7162306a36Sopenharmony_ci case INGRESS: 7262306a36Sopenharmony_ci blk_hw = base_port ? INGRESS_ENGINE_0 : INGRESS_ENGINE_1; 7362306a36Sopenharmony_ci break; 7462306a36Sopenharmony_ci case EGRESS: 7562306a36Sopenharmony_ci blk_hw = base_port ? EGRESS_ENGINE_0 : EGRESS_ENGINE_1; 7662306a36Sopenharmony_ci break; 7762306a36Sopenharmony_ci case PROCESSOR: 7862306a36Sopenharmony_ci default: 7962306a36Sopenharmony_ci blk_hw = base_port ? PROCESSOR_0 : PROCESSOR_1; 8062306a36Sopenharmony_ci break; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci phy_lock_mdio_bus(phydev); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci phy_ts_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_1588); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci phy_ts_base_write(phydev, MSCC_PHY_TS_BIU_ADDR_CNTL, BIU_ADDR_EXE | 8862306a36Sopenharmony_ci BIU_ADDR_READ | BIU_BLK_ID(blk_hw) | 8962306a36Sopenharmony_ci BIU_CSR_ADDR(addr)); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci do { 9262306a36Sopenharmony_ci val = phy_ts_base_read(phydev, MSCC_PHY_TS_BIU_ADDR_CNTL); 9362306a36Sopenharmony_ci } while (!(val & BIU_ADDR_EXE) && cnt++ < BIU_ADDR_CNT_MAX); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci val = phy_ts_base_read(phydev, MSCC_PHY_TS_CSR_DATA_MSB); 9662306a36Sopenharmony_ci val <<= 16; 9762306a36Sopenharmony_ci val |= phy_ts_base_read(phydev, MSCC_PHY_TS_CSR_DATA_LSB); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci phy_ts_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci phy_unlock_mdio_bus(phydev); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return val; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic void vsc85xx_ts_write_csr(struct phy_device *phydev, enum ts_blk blk, 10762306a36Sopenharmony_ci u16 addr, u32 val) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 11062306a36Sopenharmony_ci bool base_port = phydev->mdio.addr == priv->ts_base_addr; 11162306a36Sopenharmony_ci u32 reg, bypass, cnt = 0, lower = val & 0xffff, upper = val >> 16; 11262306a36Sopenharmony_ci bool cond = (addr == MSCC_PHY_PTP_LTC_CTRL || 11362306a36Sopenharmony_ci addr == MSCC_PHY_1588_INGR_VSC85XX_INT_MASK || 11462306a36Sopenharmony_ci addr == MSCC_PHY_1588_VSC85XX_INT_MASK || 11562306a36Sopenharmony_ci addr == MSCC_PHY_1588_INGR_VSC85XX_INT_STATUS || 11662306a36Sopenharmony_ci addr == MSCC_PHY_1588_VSC85XX_INT_STATUS) && 11762306a36Sopenharmony_ci blk == PROCESSOR; 11862306a36Sopenharmony_ci enum ts_blk_hw blk_hw; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci switch (blk) { 12162306a36Sopenharmony_ci case INGRESS: 12262306a36Sopenharmony_ci blk_hw = base_port ? INGRESS_ENGINE_0 : INGRESS_ENGINE_1; 12362306a36Sopenharmony_ci break; 12462306a36Sopenharmony_ci case EGRESS: 12562306a36Sopenharmony_ci blk_hw = base_port ? EGRESS_ENGINE_0 : EGRESS_ENGINE_1; 12662306a36Sopenharmony_ci break; 12762306a36Sopenharmony_ci case PROCESSOR: 12862306a36Sopenharmony_ci default: 12962306a36Sopenharmony_ci blk_hw = base_port ? PROCESSOR_0 : PROCESSOR_1; 13062306a36Sopenharmony_ci break; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci phy_lock_mdio_bus(phydev); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci bypass = phy_ts_base_read(phydev, MSCC_PHY_BYPASS_CONTROL); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci phy_ts_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_1588); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (!cond || upper) 14062306a36Sopenharmony_ci phy_ts_base_write(phydev, MSCC_PHY_TS_CSR_DATA_MSB, upper); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci phy_ts_base_write(phydev, MSCC_PHY_TS_CSR_DATA_LSB, lower); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci phy_ts_base_write(phydev, MSCC_PHY_TS_BIU_ADDR_CNTL, BIU_ADDR_EXE | 14562306a36Sopenharmony_ci BIU_ADDR_WRITE | BIU_BLK_ID(blk_hw) | 14662306a36Sopenharmony_ci BIU_CSR_ADDR(addr)); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci do { 14962306a36Sopenharmony_ci reg = phy_ts_base_read(phydev, MSCC_PHY_TS_BIU_ADDR_CNTL); 15062306a36Sopenharmony_ci } while (!(reg & BIU_ADDR_EXE) && cnt++ < BIU_ADDR_CNT_MAX); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci phy_ts_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (cond && upper) 15562306a36Sopenharmony_ci phy_ts_base_write(phydev, MSCC_PHY_BYPASS_CONTROL, bypass); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci phy_unlock_mdio_bus(phydev); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/* Pick bytes from PTP header */ 16162306a36Sopenharmony_ci#define PTP_HEADER_TRNSP_MSG 26 16262306a36Sopenharmony_ci#define PTP_HEADER_DOMAIN_NUM 25 16362306a36Sopenharmony_ci#define PTP_HEADER_BYTE_8_31(x) (31 - (x)) 16462306a36Sopenharmony_ci#define MAC_ADDRESS_BYTE(x) ((x) + (35 - ETH_ALEN + 1)) 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int vsc85xx_ts_fsb_init(struct phy_device *phydev) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci u8 sig_sel[16] = {}; 16962306a36Sopenharmony_ci signed char i, pos = 0; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* Seq ID is 2B long and starts at 30th byte */ 17262306a36Sopenharmony_ci for (i = 1; i >= 0; i--) 17362306a36Sopenharmony_ci sig_sel[pos++] = PTP_HEADER_BYTE_8_31(30 + i); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* DomainNum */ 17662306a36Sopenharmony_ci sig_sel[pos++] = PTP_HEADER_DOMAIN_NUM; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* MsgType */ 17962306a36Sopenharmony_ci sig_sel[pos++] = PTP_HEADER_TRNSP_MSG; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* MAC address is 6B long */ 18262306a36Sopenharmony_ci for (i = ETH_ALEN - 1; i >= 0; i--) 18362306a36Sopenharmony_ci sig_sel[pos++] = MAC_ADDRESS_BYTE(i); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* Fill the last bytes of the signature to reach a 16B signature */ 18662306a36Sopenharmony_ci for (; pos < ARRAY_SIZE(sig_sel); pos++) 18762306a36Sopenharmony_ci sig_sel[pos] = PTP_HEADER_TRNSP_MSG; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci for (i = 0; i <= 2; i++) { 19062306a36Sopenharmony_ci u32 val = 0; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci for (pos = i * 5 + 4; pos >= i * 5; pos--) 19362306a36Sopenharmony_ci val = (val << 6) | sig_sel[pos]; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, EGRESS, MSCC_PHY_ANA_FSB_REG(i), 19662306a36Sopenharmony_ci val); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, EGRESS, MSCC_PHY_ANA_FSB_REG(3), 20062306a36Sopenharmony_ci sig_sel[15]); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic const u32 vsc85xx_egr_latency[] = { 20662306a36Sopenharmony_ci /* Copper Egress */ 20762306a36Sopenharmony_ci 1272, /* 1000Mbps */ 20862306a36Sopenharmony_ci 12516, /* 100Mbps */ 20962306a36Sopenharmony_ci 125444, /* 10Mbps */ 21062306a36Sopenharmony_ci /* Fiber Egress */ 21162306a36Sopenharmony_ci 1277, /* 1000Mbps */ 21262306a36Sopenharmony_ci 12537, /* 100Mbps */ 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic const u32 vsc85xx_egr_latency_macsec[] = { 21662306a36Sopenharmony_ci /* Copper Egress ON */ 21762306a36Sopenharmony_ci 3496, /* 1000Mbps */ 21862306a36Sopenharmony_ci 34760, /* 100Mbps */ 21962306a36Sopenharmony_ci 347844, /* 10Mbps */ 22062306a36Sopenharmony_ci /* Fiber Egress ON */ 22162306a36Sopenharmony_ci 3502, /* 1000Mbps */ 22262306a36Sopenharmony_ci 34780, /* 100Mbps */ 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic const u32 vsc85xx_ingr_latency[] = { 22662306a36Sopenharmony_ci /* Copper Ingress */ 22762306a36Sopenharmony_ci 208, /* 1000Mbps */ 22862306a36Sopenharmony_ci 304, /* 100Mbps */ 22962306a36Sopenharmony_ci 2023, /* 10Mbps */ 23062306a36Sopenharmony_ci /* Fiber Ingress */ 23162306a36Sopenharmony_ci 98, /* 1000Mbps */ 23262306a36Sopenharmony_ci 197, /* 100Mbps */ 23362306a36Sopenharmony_ci}; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic const u32 vsc85xx_ingr_latency_macsec[] = { 23662306a36Sopenharmony_ci /* Copper Ingress */ 23762306a36Sopenharmony_ci 2408, /* 1000Mbps */ 23862306a36Sopenharmony_ci 22300, /* 100Mbps */ 23962306a36Sopenharmony_ci 222009, /* 10Mbps */ 24062306a36Sopenharmony_ci /* Fiber Ingress */ 24162306a36Sopenharmony_ci 2299, /* 1000Mbps */ 24262306a36Sopenharmony_ci 22192, /* 100Mbps */ 24362306a36Sopenharmony_ci}; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic void vsc85xx_ts_set_latencies(struct phy_device *phydev) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci u32 val, ingr_latency, egr_latency; 24862306a36Sopenharmony_ci u8 idx; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* No need to set latencies of packets if the PHY is not connected */ 25162306a36Sopenharmony_ci if (!phydev->link) 25262306a36Sopenharmony_ci return; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_STALL_LATENCY, 25562306a36Sopenharmony_ci STALL_EGR_LATENCY(phydev->speed)); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci switch (phydev->speed) { 25862306a36Sopenharmony_ci case SPEED_100: 25962306a36Sopenharmony_ci idx = 1; 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci case SPEED_1000: 26262306a36Sopenharmony_ci idx = 0; 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci default: 26562306a36Sopenharmony_ci idx = 2; 26662306a36Sopenharmony_ci break; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci ingr_latency = IS_ENABLED(CONFIG_MACSEC) ? 27062306a36Sopenharmony_ci vsc85xx_ingr_latency_macsec[idx] : vsc85xx_ingr_latency[idx]; 27162306a36Sopenharmony_ci egr_latency = IS_ENABLED(CONFIG_MACSEC) ? 27262306a36Sopenharmony_ci vsc85xx_egr_latency_macsec[idx] : vsc85xx_egr_latency[idx]; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_INGR_LOCAL_LATENCY, 27562306a36Sopenharmony_ci PTP_INGR_LOCAL_LATENCY(ingr_latency)); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 27862306a36Sopenharmony_ci MSCC_PHY_PTP_INGR_TSP_CTRL); 27962306a36Sopenharmony_ci val |= PHY_PTP_INGR_TSP_CTRL_LOAD_DELAYS; 28062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_INGR_TSP_CTRL, 28162306a36Sopenharmony_ci val); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_LOCAL_LATENCY, 28462306a36Sopenharmony_ci PTP_EGR_LOCAL_LATENCY(egr_latency)); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_TSP_CTRL); 28762306a36Sopenharmony_ci val |= PHY_PTP_EGR_TSP_CTRL_LOAD_DELAYS; 28862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_TSP_CTRL, val); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic int vsc85xx_ts_disable_flows(struct phy_device *phydev, enum ts_blk blk) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci u8 i; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_NXT_PROT_NXT_COMP, 0); 29662306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_NXT_PROT_UDP_CHKSUM, 29762306a36Sopenharmony_ci IP1_NXT_PROT_UDP_CHKSUM_WIDTH(2)); 29862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP2_NXT_PROT_NXT_COMP, 0); 29962306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP2_NXT_PROT_UDP_CHKSUM, 30062306a36Sopenharmony_ci IP2_NXT_PROT_UDP_CHKSUM_WIDTH(2)); 30162306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_PHY_ANA_MPLS_COMP_NXT_COMP, 0); 30262306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_PHY_ANA_ETH1_NTX_PROT, 0); 30362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_PHY_ANA_ETH2_NTX_PROT, 0); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci for (i = 0; i < COMP_MAX_FLOWS; i++) { 30662306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_FLOW_ENA(i), 30762306a36Sopenharmony_ci IP1_FLOW_VALID_CH0 | IP1_FLOW_VALID_CH1); 30862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP2_FLOW_ENA(i), 30962306a36Sopenharmony_ci IP2_FLOW_VALID_CH0 | IP2_FLOW_VALID_CH1); 31062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_ETH1_FLOW_ENA(i), 31162306a36Sopenharmony_ci ETH1_FLOW_VALID_CH0 | ETH1_FLOW_VALID_CH1); 31262306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_ETH2_FLOW_ENA(i), 31362306a36Sopenharmony_ci ETH2_FLOW_VALID_CH0 | ETH2_FLOW_VALID_CH1); 31462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_MPLS_FLOW_CTRL(i), 31562306a36Sopenharmony_ci MPLS_FLOW_VALID_CH0 | MPLS_FLOW_VALID_CH1); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (i >= PTP_COMP_MAX_FLOWS) 31862306a36Sopenharmony_ci continue; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_PTP_FLOW_ENA(i), 0); 32162306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 32262306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_DOMAIN_RANGE(i), 0); 32362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 32462306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_MASK_UPPER(i), 0); 32562306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 32662306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_MASK_LOWER(i), 0); 32762306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 32862306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_MATCH_UPPER(i), 0); 32962306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 33062306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_MATCH_LOWER(i), 0); 33162306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 33262306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_PTP_ACTION(i), 0); 33362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 33462306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_PTP_ACTION2(i), 0); 33562306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 33662306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_PTP_0_FIELD(i), 0); 33762306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_OAM_PTP_FLOW_ENA(i), 33862306a36Sopenharmony_ci 0); 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci return 0; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int vsc85xx_ts_eth_cmp1_sig(struct phy_device *phydev) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci u32 val; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, EGRESS, MSCC_PHY_ANA_ETH1_NTX_PROT); 34962306a36Sopenharmony_ci val &= ~ANA_ETH1_NTX_PROT_SIG_OFF_MASK; 35062306a36Sopenharmony_ci val |= ANA_ETH1_NTX_PROT_SIG_OFF(0); 35162306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, EGRESS, MSCC_PHY_ANA_ETH1_NTX_PROT, val); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, EGRESS, MSCC_PHY_ANA_FSB_CFG); 35462306a36Sopenharmony_ci val &= ~ANA_FSB_ADDR_FROM_BLOCK_SEL_MASK; 35562306a36Sopenharmony_ci val |= ANA_FSB_ADDR_FROM_ETH1; 35662306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, EGRESS, MSCC_PHY_ANA_FSB_CFG, val); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return 0; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic struct vsc85xx_ptphdr *get_ptp_header_l4(struct sk_buff *skb, 36262306a36Sopenharmony_ci struct iphdr *iphdr, 36362306a36Sopenharmony_ci struct udphdr *udphdr) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci if (iphdr->version != 4 || iphdr->protocol != IPPROTO_UDP) 36662306a36Sopenharmony_ci return NULL; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return (struct vsc85xx_ptphdr *)(((unsigned char *)udphdr) + UDP_HLEN); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic struct vsc85xx_ptphdr *get_ptp_header_tx(struct sk_buff *skb) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct ethhdr *ethhdr = eth_hdr(skb); 37462306a36Sopenharmony_ci struct udphdr *udphdr; 37562306a36Sopenharmony_ci struct iphdr *iphdr; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (ethhdr->h_proto == htons(ETH_P_1588)) 37862306a36Sopenharmony_ci return (struct vsc85xx_ptphdr *)(((unsigned char *)ethhdr) + 37962306a36Sopenharmony_ci skb_mac_header_len(skb)); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (ethhdr->h_proto != htons(ETH_P_IP)) 38262306a36Sopenharmony_ci return NULL; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci iphdr = ip_hdr(skb); 38562306a36Sopenharmony_ci udphdr = udp_hdr(skb); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci return get_ptp_header_l4(skb, iphdr, udphdr); 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic struct vsc85xx_ptphdr *get_ptp_header_rx(struct sk_buff *skb, 39162306a36Sopenharmony_ci enum hwtstamp_rx_filters rx_filter) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct udphdr *udphdr; 39462306a36Sopenharmony_ci struct iphdr *iphdr; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (rx_filter == HWTSTAMP_FILTER_PTP_V2_L2_EVENT) 39762306a36Sopenharmony_ci return (struct vsc85xx_ptphdr *)skb->data; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci iphdr = (struct iphdr *)skb->data; 40062306a36Sopenharmony_ci udphdr = (struct udphdr *)(skb->data + iphdr->ihl * 4); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return get_ptp_header_l4(skb, iphdr, udphdr); 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic int get_sig(struct sk_buff *skb, u8 *sig) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct vsc85xx_ptphdr *ptphdr = get_ptp_header_tx(skb); 40862306a36Sopenharmony_ci struct ethhdr *ethhdr = eth_hdr(skb); 40962306a36Sopenharmony_ci unsigned int i; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (!ptphdr) 41262306a36Sopenharmony_ci return -EOPNOTSUPP; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci sig[0] = (__force u16)ptphdr->seq_id >> 8; 41562306a36Sopenharmony_ci sig[1] = (__force u16)ptphdr->seq_id & GENMASK(7, 0); 41662306a36Sopenharmony_ci sig[2] = ptphdr->domain; 41762306a36Sopenharmony_ci sig[3] = ptphdr->tsmt & GENMASK(3, 0); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci memcpy(&sig[4], ethhdr->h_dest, ETH_ALEN); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* Fill the last bytes of the signature to reach a 16B signature */ 42262306a36Sopenharmony_ci for (i = 10; i < 16; i++) 42362306a36Sopenharmony_ci sig[i] = ptphdr->tsmt & GENMASK(3, 0); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic void vsc85xx_dequeue_skb(struct vsc85xx_ptp *ptp) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct skb_shared_hwtstamps shhwtstamps; 43162306a36Sopenharmony_ci struct vsc85xx_ts_fifo fifo; 43262306a36Sopenharmony_ci struct sk_buff *skb; 43362306a36Sopenharmony_ci u8 skb_sig[16], *p; 43462306a36Sopenharmony_ci int i, len; 43562306a36Sopenharmony_ci u32 reg; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci memset(&fifo, 0, sizeof(fifo)); 43862306a36Sopenharmony_ci p = (u8 *)&fifo; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci reg = vsc85xx_ts_read_csr(ptp->phydev, PROCESSOR, 44162306a36Sopenharmony_ci MSCC_PHY_PTP_EGR_TS_FIFO(0)); 44262306a36Sopenharmony_ci if (reg & PTP_EGR_TS_FIFO_EMPTY) 44362306a36Sopenharmony_ci return; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci *p++ = reg & 0xff; 44662306a36Sopenharmony_ci *p++ = (reg >> 8) & 0xff; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* Read the current FIFO item. Reading FIFO6 pops the next one. */ 44962306a36Sopenharmony_ci for (i = 1; i < 7; i++) { 45062306a36Sopenharmony_ci reg = vsc85xx_ts_read_csr(ptp->phydev, PROCESSOR, 45162306a36Sopenharmony_ci MSCC_PHY_PTP_EGR_TS_FIFO(i)); 45262306a36Sopenharmony_ci *p++ = reg & 0xff; 45362306a36Sopenharmony_ci *p++ = (reg >> 8) & 0xff; 45462306a36Sopenharmony_ci *p++ = (reg >> 16) & 0xff; 45562306a36Sopenharmony_ci *p++ = (reg >> 24) & 0xff; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci len = skb_queue_len(&ptp->tx_queue); 45962306a36Sopenharmony_ci if (len < 1) 46062306a36Sopenharmony_ci return; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci while (len--) { 46362306a36Sopenharmony_ci skb = __skb_dequeue(&ptp->tx_queue); 46462306a36Sopenharmony_ci if (!skb) 46562306a36Sopenharmony_ci return; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* Can't get the signature of the packet, won't ever 46862306a36Sopenharmony_ci * be able to have one so let's dequeue the packet. 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_ci if (get_sig(skb, skb_sig) < 0) { 47162306a36Sopenharmony_ci kfree_skb(skb); 47262306a36Sopenharmony_ci continue; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Check if we found the signature we were looking for. */ 47662306a36Sopenharmony_ci if (!memcmp(skb_sig, fifo.sig, sizeof(fifo.sig))) { 47762306a36Sopenharmony_ci memset(&shhwtstamps, 0, sizeof(shhwtstamps)); 47862306a36Sopenharmony_ci shhwtstamps.hwtstamp = ktime_set(fifo.secs, fifo.ns); 47962306a36Sopenharmony_ci skb_complete_tx_timestamp(skb, &shhwtstamps); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* Valid signature but does not match the one of the 48562306a36Sopenharmony_ci * packet in the FIFO right now, reschedule it for later 48662306a36Sopenharmony_ci * packets. 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_ci __skb_queue_tail(&ptp->tx_queue, skb); 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic void vsc85xx_get_tx_ts(struct vsc85xx_ptp *ptp) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci u32 reg; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci do { 49762306a36Sopenharmony_ci vsc85xx_dequeue_skb(ptp); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* If other timestamps are available in the FIFO, process them. */ 50062306a36Sopenharmony_ci reg = vsc85xx_ts_read_csr(ptp->phydev, PROCESSOR, 50162306a36Sopenharmony_ci MSCC_PHY_PTP_EGR_TS_FIFO_CTRL); 50262306a36Sopenharmony_ci } while (PTP_EGR_FIFO_LEVEL_LAST_READ(reg) > 1); 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic int vsc85xx_ptp_cmp_init(struct phy_device *phydev, enum ts_blk blk) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = phydev->priv; 50862306a36Sopenharmony_ci bool base = phydev->mdio.addr == vsc8531->ts_base_addr; 50962306a36Sopenharmony_ci static const u8 msgs[] = { 51062306a36Sopenharmony_ci PTP_MSGTYPE_SYNC, 51162306a36Sopenharmony_ci PTP_MSGTYPE_DELAY_REQ 51262306a36Sopenharmony_ci }; 51362306a36Sopenharmony_ci u32 val; 51462306a36Sopenharmony_ci u8 i; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(msgs); i++) { 51762306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_PTP_FLOW_ENA(i), 51862306a36Sopenharmony_ci base ? PTP_FLOW_VALID_CH0 : 51962306a36Sopenharmony_ci PTP_FLOW_VALID_CH1); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, blk, 52262306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_DOMAIN_RANGE(i)); 52362306a36Sopenharmony_ci val &= ~PTP_FLOW_DOMAIN_RANGE_ENA; 52462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 52562306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_DOMAIN_RANGE(i), val); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 52862306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_MATCH_UPPER(i), 52962306a36Sopenharmony_ci msgs[i] << 24); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 53262306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_MASK_UPPER(i), 53362306a36Sopenharmony_ci PTP_FLOW_MSG_TYPE_MASK); 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return 0; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic int vsc85xx_eth_cmp1_init(struct phy_device *phydev, enum ts_blk blk) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = phydev->priv; 54262306a36Sopenharmony_ci bool base = phydev->mdio.addr == vsc8531->ts_base_addr; 54362306a36Sopenharmony_ci u32 val; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_PHY_ANA_ETH1_NXT_PROT_TAG, 0); 54662306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_PHY_ANA_ETH1_NTX_PROT_VLAN_TPID, 54762306a36Sopenharmony_ci ANA_ETH1_NTX_PROT_VLAN_TPID(ETH_P_8021AD)); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_ETH1_FLOW_ENA(0), 55062306a36Sopenharmony_ci base ? ETH1_FLOW_VALID_CH0 : ETH1_FLOW_VALID_CH1); 55162306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_ETH1_FLOW_MATCH_MODE(0), 55262306a36Sopenharmony_ci ANA_ETH1_FLOW_MATCH_VLAN_TAG2); 55362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_ETH1_FLOW_ADDR_MATCH1(0), 0); 55462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_ETH1_FLOW_ADDR_MATCH2(0), 0); 55562306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 55662306a36Sopenharmony_ci MSCC_ANA_ETH1_FLOW_VLAN_RANGE_I_TAG(0), 0); 55762306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_ETH1_FLOW_VLAN_TAG1(0), 0); 55862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 55962306a36Sopenharmony_ci MSCC_ANA_ETH1_FLOW_VLAN_TAG2_I_TAG(0), 0); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, blk, 56262306a36Sopenharmony_ci MSCC_ANA_ETH1_FLOW_MATCH_MODE(0)); 56362306a36Sopenharmony_ci val &= ~ANA_ETH1_FLOW_MATCH_VLAN_TAG_MASK; 56462306a36Sopenharmony_ci val |= ANA_ETH1_FLOW_MATCH_VLAN_VERIFY; 56562306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_ETH1_FLOW_MATCH_MODE(0), 56662306a36Sopenharmony_ci val); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return 0; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic int vsc85xx_ip_cmp1_init(struct phy_device *phydev, enum ts_blk blk) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = phydev->priv; 57462306a36Sopenharmony_ci bool base = phydev->mdio.addr == vsc8531->ts_base_addr; 57562306a36Sopenharmony_ci u32 val; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_NXT_PROT_MATCH2_UPPER, 57862306a36Sopenharmony_ci PTP_EV_PORT); 57962306a36Sopenharmony_ci /* Match on dest port only, ignore src */ 58062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_NXT_PROT_MASK2_UPPER, 58162306a36Sopenharmony_ci 0xffff); 58262306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_NXT_PROT_MATCH2_LOWER, 58362306a36Sopenharmony_ci 0); 58462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_NXT_PROT_MASK2_LOWER, 0); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, blk, MSCC_ANA_IP1_FLOW_ENA(0)); 58762306a36Sopenharmony_ci val &= ~IP1_FLOW_ENA_CHANNEL_MASK_MASK; 58862306a36Sopenharmony_ci val |= base ? IP1_FLOW_VALID_CH0 : IP1_FLOW_VALID_CH1; 58962306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_FLOW_ENA(0), val); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* Match all IPs */ 59262306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_FLOW_MATCH_UPPER(0), 0); 59362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_FLOW_MASK_UPPER(0), 0); 59462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_FLOW_MATCH_UPPER_MID(0), 59562306a36Sopenharmony_ci 0); 59662306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_FLOW_MASK_UPPER_MID(0), 59762306a36Sopenharmony_ci 0); 59862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_FLOW_MATCH_LOWER_MID(0), 59962306a36Sopenharmony_ci 0); 60062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_FLOW_MASK_LOWER_MID(0), 60162306a36Sopenharmony_ci 0); 60262306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_FLOW_MATCH_LOWER(0), 0); 60362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_FLOW_MASK_LOWER(0), 0); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_PTP_IP_CHKSUM_SEL, 0); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return 0; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic int vsc85xx_adjfine(struct ptp_clock_info *info, long scaled_ppm) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct vsc85xx_ptp *ptp = container_of(info, struct vsc85xx_ptp, caps); 61362306a36Sopenharmony_ci struct phy_device *phydev = ptp->phydev; 61462306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 61562306a36Sopenharmony_ci u64 adj = 0; 61662306a36Sopenharmony_ci u32 val; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if (abs(scaled_ppm) < 66 || abs(scaled_ppm) > 65536UL * 1000000UL) 61962306a36Sopenharmony_ci return 0; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci adj = div64_u64(1000000ULL * 65536ULL, abs(scaled_ppm)); 62262306a36Sopenharmony_ci if (adj > 1000000000L) 62362306a36Sopenharmony_ci adj = 1000000000L; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci val = PTP_AUTO_ADJ_NS_ROLLOVER(adj); 62662306a36Sopenharmony_ci val |= scaled_ppm > 0 ? PTP_AUTO_ADJ_ADD_1NS : PTP_AUTO_ADJ_SUB_1NS; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci mutex_lock(&priv->phc_lock); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* Update the ppb val in nano seconds to the auto adjust reg. */ 63162306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_AUTO_ADJ, 63262306a36Sopenharmony_ci val); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* The auto adjust update val is set to 0 after write operation. */ 63562306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_CTRL); 63662306a36Sopenharmony_ci val |= PTP_LTC_CTRL_AUTO_ADJ_UPDATE; 63762306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_CTRL, val); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci mutex_unlock(&priv->phc_lock); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci return 0; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic int __vsc85xx_gettime(struct ptp_clock_info *info, struct timespec64 *ts) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct vsc85xx_ptp *ptp = container_of(info, struct vsc85xx_ptp, caps); 64762306a36Sopenharmony_ci struct phy_device *phydev = ptp->phydev; 64862306a36Sopenharmony_ci struct vsc85xx_shared_private *shared = 64962306a36Sopenharmony_ci (struct vsc85xx_shared_private *)phydev->shared->priv; 65062306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 65162306a36Sopenharmony_ci u32 val; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_CTRL); 65462306a36Sopenharmony_ci val |= PTP_LTC_CTRL_SAVE_ENA; 65562306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_CTRL, val); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Local Time Counter (LTC) is put in SAVE* regs on rising edge of 65862306a36Sopenharmony_ci * LOAD_SAVE pin. 65962306a36Sopenharmony_ci */ 66062306a36Sopenharmony_ci mutex_lock(&shared->gpio_lock); 66162306a36Sopenharmony_ci gpiod_set_value(priv->load_save, 1); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 66462306a36Sopenharmony_ci MSCC_PHY_PTP_LTC_SAVED_SEC_MSB); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci ts->tv_sec = ((time64_t)val) << 32; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 66962306a36Sopenharmony_ci MSCC_PHY_PTP_LTC_SAVED_SEC_LSB); 67062306a36Sopenharmony_ci ts->tv_sec += val; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci ts->tv_nsec = vsc85xx_ts_read_csr(phydev, PROCESSOR, 67362306a36Sopenharmony_ci MSCC_PHY_PTP_LTC_SAVED_NS); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci gpiod_set_value(priv->load_save, 0); 67662306a36Sopenharmony_ci mutex_unlock(&shared->gpio_lock); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci return 0; 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic int vsc85xx_gettime(struct ptp_clock_info *info, struct timespec64 *ts) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci struct vsc85xx_ptp *ptp = container_of(info, struct vsc85xx_ptp, caps); 68462306a36Sopenharmony_ci struct phy_device *phydev = ptp->phydev; 68562306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci mutex_lock(&priv->phc_lock); 68862306a36Sopenharmony_ci __vsc85xx_gettime(info, ts); 68962306a36Sopenharmony_ci mutex_unlock(&priv->phc_lock); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return 0; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int __vsc85xx_settime(struct ptp_clock_info *info, 69562306a36Sopenharmony_ci const struct timespec64 *ts) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct vsc85xx_ptp *ptp = container_of(info, struct vsc85xx_ptp, caps); 69862306a36Sopenharmony_ci struct phy_device *phydev = ptp->phydev; 69962306a36Sopenharmony_ci struct vsc85xx_shared_private *shared = 70062306a36Sopenharmony_ci (struct vsc85xx_shared_private *)phydev->shared->priv; 70162306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 70262306a36Sopenharmony_ci u32 val; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_LOAD_SEC_MSB, 70562306a36Sopenharmony_ci PTP_LTC_LOAD_SEC_MSB(ts->tv_sec)); 70662306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_LOAD_SEC_LSB, 70762306a36Sopenharmony_ci PTP_LTC_LOAD_SEC_LSB(ts->tv_sec)); 70862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_LOAD_NS, 70962306a36Sopenharmony_ci PTP_LTC_LOAD_NS(ts->tv_nsec)); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_CTRL); 71262306a36Sopenharmony_ci val |= PTP_LTC_CTRL_LOAD_ENA; 71362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_CTRL, val); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* Local Time Counter (LTC) is set from LOAD* regs on rising edge of 71662306a36Sopenharmony_ci * LOAD_SAVE pin. 71762306a36Sopenharmony_ci */ 71862306a36Sopenharmony_ci mutex_lock(&shared->gpio_lock); 71962306a36Sopenharmony_ci gpiod_set_value(priv->load_save, 1); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci val &= ~PTP_LTC_CTRL_LOAD_ENA; 72262306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_CTRL, val); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci gpiod_set_value(priv->load_save, 0); 72562306a36Sopenharmony_ci mutex_unlock(&shared->gpio_lock); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci return 0; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic int vsc85xx_settime(struct ptp_clock_info *info, 73162306a36Sopenharmony_ci const struct timespec64 *ts) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci struct vsc85xx_ptp *ptp = container_of(info, struct vsc85xx_ptp, caps); 73462306a36Sopenharmony_ci struct phy_device *phydev = ptp->phydev; 73562306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci mutex_lock(&priv->phc_lock); 73862306a36Sopenharmony_ci __vsc85xx_settime(info, ts); 73962306a36Sopenharmony_ci mutex_unlock(&priv->phc_lock); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci return 0; 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic int vsc85xx_adjtime(struct ptp_clock_info *info, s64 delta) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci struct vsc85xx_ptp *ptp = container_of(info, struct vsc85xx_ptp, caps); 74762306a36Sopenharmony_ci struct phy_device *phydev = ptp->phydev; 74862306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 74962306a36Sopenharmony_ci u32 val; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* Can't recover that big of an offset. Let's set the time directly. */ 75262306a36Sopenharmony_ci if (abs(delta) >= NSEC_PER_SEC) { 75362306a36Sopenharmony_ci struct timespec64 ts; 75462306a36Sopenharmony_ci u64 now; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci mutex_lock(&priv->phc_lock); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci __vsc85xx_gettime(info, &ts); 75962306a36Sopenharmony_ci now = ktime_to_ns(timespec64_to_ktime(ts)); 76062306a36Sopenharmony_ci ts = ns_to_timespec64(now + delta); 76162306a36Sopenharmony_ci __vsc85xx_settime(info, &ts); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci mutex_unlock(&priv->phc_lock); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci return 0; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci mutex_lock(&priv->phc_lock); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci val = PTP_LTC_OFFSET_VAL(abs(delta)) | PTP_LTC_OFFSET_ADJ; 77162306a36Sopenharmony_ci if (delta > 0) 77262306a36Sopenharmony_ci val |= PTP_LTC_OFFSET_ADD; 77362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_OFFSET, val); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci mutex_unlock(&priv->phc_lock); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return 0; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic int vsc85xx_eth1_next_comp(struct phy_device *phydev, enum ts_blk blk, 78162306a36Sopenharmony_ci u32 next_comp, u32 etype) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci u32 val; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, blk, MSCC_PHY_ANA_ETH1_NTX_PROT); 78662306a36Sopenharmony_ci val &= ~ANA_ETH1_NTX_PROT_COMPARATOR_MASK; 78762306a36Sopenharmony_ci val |= next_comp; 78862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_PHY_ANA_ETH1_NTX_PROT, val); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci val = ANA_ETH1_NXT_PROT_ETYPE_MATCH(etype) | 79162306a36Sopenharmony_ci ANA_ETH1_NXT_PROT_ETYPE_MATCH_ENA; 79262306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 79362306a36Sopenharmony_ci MSCC_PHY_ANA_ETH1_NXT_PROT_ETYPE_MATCH, val); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci return 0; 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic int vsc85xx_ip1_next_comp(struct phy_device *phydev, enum ts_blk blk, 79962306a36Sopenharmony_ci u32 next_comp, u32 header) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_NXT_PROT_NXT_COMP, 80262306a36Sopenharmony_ci ANA_IP1_NXT_PROT_NXT_COMP_BYTES_HDR(header) | 80362306a36Sopenharmony_ci next_comp); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci return 0; 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_cistatic int vsc85xx_ts_ptp_action_flow(struct phy_device *phydev, enum ts_blk blk, u8 flow, enum ptp_cmd cmd) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci u32 val; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci /* Check non-zero reserved field */ 81362306a36Sopenharmony_ci val = PTP_FLOW_PTP_0_FIELD_PTP_FRAME | PTP_FLOW_PTP_0_FIELD_RSVRD_CHECK; 81462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 81562306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_PTP_0_FIELD(flow), val); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci val = PTP_FLOW_PTP_ACTION_CORR_OFFSET(8) | 81862306a36Sopenharmony_ci PTP_FLOW_PTP_ACTION_TIME_OFFSET(8) | 81962306a36Sopenharmony_ci PTP_FLOW_PTP_ACTION_PTP_CMD(cmd == PTP_SAVE_IN_TS_FIFO ? 82062306a36Sopenharmony_ci PTP_NOP : cmd); 82162306a36Sopenharmony_ci if (cmd == PTP_SAVE_IN_TS_FIFO) 82262306a36Sopenharmony_ci val |= PTP_FLOW_PTP_ACTION_SAVE_LOCAL_TIME; 82362306a36Sopenharmony_ci else if (cmd == PTP_WRITE_NS) 82462306a36Sopenharmony_ci val |= PTP_FLOW_PTP_ACTION_MOD_FRAME_STATUS_UPDATE | 82562306a36Sopenharmony_ci PTP_FLOW_PTP_ACTION_MOD_FRAME_STATUS_BYTE_OFFSET(6); 82662306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_PTP_FLOW_PTP_ACTION(flow), 82762306a36Sopenharmony_ci val); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (cmd == PTP_WRITE_1588) 83062306a36Sopenharmony_ci /* Rewrite timestamp directly in frame */ 83162306a36Sopenharmony_ci val = PTP_FLOW_PTP_ACTION2_REWRITE_OFFSET(34) | 83262306a36Sopenharmony_ci PTP_FLOW_PTP_ACTION2_REWRITE_BYTES(10); 83362306a36Sopenharmony_ci else if (cmd == PTP_SAVE_IN_TS_FIFO) 83462306a36Sopenharmony_ci /* no rewrite */ 83562306a36Sopenharmony_ci val = PTP_FLOW_PTP_ACTION2_REWRITE_OFFSET(0) | 83662306a36Sopenharmony_ci PTP_FLOW_PTP_ACTION2_REWRITE_BYTES(0); 83762306a36Sopenharmony_ci else 83862306a36Sopenharmony_ci /* Write in reserved field */ 83962306a36Sopenharmony_ci val = PTP_FLOW_PTP_ACTION2_REWRITE_OFFSET(16) | 84062306a36Sopenharmony_ci PTP_FLOW_PTP_ACTION2_REWRITE_BYTES(4); 84162306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 84262306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_PTP_ACTION2(flow), val); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci return 0; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic int vsc85xx_ptp_conf(struct phy_device *phydev, enum ts_blk blk, 84862306a36Sopenharmony_ci bool one_step, bool enable) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci static const u8 msgs[] = { 85162306a36Sopenharmony_ci PTP_MSGTYPE_SYNC, 85262306a36Sopenharmony_ci PTP_MSGTYPE_DELAY_REQ 85362306a36Sopenharmony_ci }; 85462306a36Sopenharmony_ci u32 val; 85562306a36Sopenharmony_ci u8 i; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(msgs); i++) { 85862306a36Sopenharmony_ci if (blk == INGRESS) 85962306a36Sopenharmony_ci vsc85xx_ts_ptp_action_flow(phydev, blk, msgs[i], 86062306a36Sopenharmony_ci PTP_WRITE_NS); 86162306a36Sopenharmony_ci else if (msgs[i] == PTP_MSGTYPE_SYNC && one_step) 86262306a36Sopenharmony_ci /* no need to know Sync t when sending in one_step */ 86362306a36Sopenharmony_ci vsc85xx_ts_ptp_action_flow(phydev, blk, msgs[i], 86462306a36Sopenharmony_ci PTP_WRITE_1588); 86562306a36Sopenharmony_ci else 86662306a36Sopenharmony_ci vsc85xx_ts_ptp_action_flow(phydev, blk, msgs[i], 86762306a36Sopenharmony_ci PTP_SAVE_IN_TS_FIFO); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, blk, 87062306a36Sopenharmony_ci MSCC_ANA_PTP_FLOW_ENA(i)); 87162306a36Sopenharmony_ci val &= ~PTP_FLOW_ENA; 87262306a36Sopenharmony_ci if (enable) 87362306a36Sopenharmony_ci val |= PTP_FLOW_ENA; 87462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_PTP_FLOW_ENA(i), 87562306a36Sopenharmony_ci val); 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci return 0; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic int vsc85xx_eth1_conf(struct phy_device *phydev, enum ts_blk blk, 88262306a36Sopenharmony_ci bool enable) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = phydev->priv; 88562306a36Sopenharmony_ci u32 val = ANA_ETH1_FLOW_ADDR_MATCH2_DEST; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (vsc8531->ptp->rx_filter == HWTSTAMP_FILTER_PTP_V2_L2_EVENT) { 88862306a36Sopenharmony_ci /* PTP over Ethernet multicast address for SYNC and DELAY msg */ 88962306a36Sopenharmony_ci u8 ptp_multicast[6] = {0x01, 0x1b, 0x19, 0x00, 0x00, 0x00}; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci val |= ANA_ETH1_FLOW_ADDR_MATCH2_FULL_ADDR | 89262306a36Sopenharmony_ci get_unaligned_be16(&ptp_multicast[4]); 89362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 89462306a36Sopenharmony_ci MSCC_ANA_ETH1_FLOW_ADDR_MATCH2(0), val); 89562306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 89662306a36Sopenharmony_ci MSCC_ANA_ETH1_FLOW_ADDR_MATCH1(0), 89762306a36Sopenharmony_ci get_unaligned_be32(ptp_multicast)); 89862306a36Sopenharmony_ci } else { 89962306a36Sopenharmony_ci val |= ANA_ETH1_FLOW_ADDR_MATCH2_ANY_MULTICAST; 90062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 90162306a36Sopenharmony_ci MSCC_ANA_ETH1_FLOW_ADDR_MATCH2(0), val); 90262306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, 90362306a36Sopenharmony_ci MSCC_ANA_ETH1_FLOW_ADDR_MATCH1(0), 0); 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, blk, MSCC_ANA_ETH1_FLOW_ENA(0)); 90762306a36Sopenharmony_ci val &= ~ETH1_FLOW_ENA; 90862306a36Sopenharmony_ci if (enable) 90962306a36Sopenharmony_ci val |= ETH1_FLOW_ENA; 91062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_ETH1_FLOW_ENA(0), val); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci return 0; 91362306a36Sopenharmony_ci} 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_cistatic int vsc85xx_ip1_conf(struct phy_device *phydev, enum ts_blk blk, 91662306a36Sopenharmony_ci bool enable) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci u32 val; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_NXT_PROT_IP1_MODE, 92162306a36Sopenharmony_ci ANA_IP1_NXT_PROT_IPV4 | 92262306a36Sopenharmony_ci ANA_IP1_NXT_PROT_FLOW_OFFSET_IPV4); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci /* Matching UDP protocol number */ 92562306a36Sopenharmony_ci val = ANA_IP1_NXT_PROT_IP_MATCH1_PROT_MASK(0xff) | 92662306a36Sopenharmony_ci ANA_IP1_NXT_PROT_IP_MATCH1_PROT_MATCH(IPPROTO_UDP) | 92762306a36Sopenharmony_ci ANA_IP1_NXT_PROT_IP_MATCH1_PROT_OFF(9); 92862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_NXT_PROT_IP_MATCH1, 92962306a36Sopenharmony_ci val); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci /* End of IP protocol, start of next protocol (UDP) */ 93262306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_NXT_PROT_OFFSET2, 93362306a36Sopenharmony_ci ANA_IP1_NXT_PROT_OFFSET2(20)); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, blk, 93662306a36Sopenharmony_ci MSCC_ANA_IP1_NXT_PROT_UDP_CHKSUM); 93762306a36Sopenharmony_ci val &= ~(IP1_NXT_PROT_UDP_CHKSUM_OFF_MASK | 93862306a36Sopenharmony_ci IP1_NXT_PROT_UDP_CHKSUM_WIDTH_MASK); 93962306a36Sopenharmony_ci val |= IP1_NXT_PROT_UDP_CHKSUM_WIDTH(2); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci val &= ~(IP1_NXT_PROT_UDP_CHKSUM_UPDATE | 94262306a36Sopenharmony_ci IP1_NXT_PROT_UDP_CHKSUM_CLEAR); 94362306a36Sopenharmony_ci /* UDP checksum offset in IPv4 packet 94462306a36Sopenharmony_ci * according to: https://tools.ietf.org/html/rfc768 94562306a36Sopenharmony_ci */ 94662306a36Sopenharmony_ci val |= IP1_NXT_PROT_UDP_CHKSUM_OFF(26) | IP1_NXT_PROT_UDP_CHKSUM_CLEAR; 94762306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_NXT_PROT_UDP_CHKSUM, 94862306a36Sopenharmony_ci val); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, blk, MSCC_ANA_IP1_FLOW_ENA(0)); 95162306a36Sopenharmony_ci val &= ~(IP1_FLOW_MATCH_ADDR_MASK | IP1_FLOW_ENA); 95262306a36Sopenharmony_ci val |= IP1_FLOW_MATCH_DEST_SRC_ADDR; 95362306a36Sopenharmony_ci if (enable) 95462306a36Sopenharmony_ci val |= IP1_FLOW_ENA; 95562306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, blk, MSCC_ANA_IP1_FLOW_ENA(0), val); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci return 0; 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cistatic int vsc85xx_ts_engine_init(struct phy_device *phydev, bool one_step) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = phydev->priv; 96362306a36Sopenharmony_ci bool ptp_l4, base = phydev->mdio.addr == vsc8531->ts_base_addr; 96462306a36Sopenharmony_ci u8 eng_id = base ? 0 : 1; 96562306a36Sopenharmony_ci u32 val; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci ptp_l4 = vsc8531->ptp->rx_filter == HWTSTAMP_FILTER_PTP_V2_L4_EVENT; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 97062306a36Sopenharmony_ci MSCC_PHY_PTP_ANALYZER_MODE); 97162306a36Sopenharmony_ci /* Disable INGRESS and EGRESS so engine eng_id can be reconfigured */ 97262306a36Sopenharmony_ci val &= ~(PTP_ANALYZER_MODE_EGR_ENA(BIT(eng_id)) | 97362306a36Sopenharmony_ci PTP_ANALYZER_MODE_INGR_ENA(BIT(eng_id))); 97462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_ANALYZER_MODE, 97562306a36Sopenharmony_ci val); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if (vsc8531->ptp->rx_filter == HWTSTAMP_FILTER_PTP_V2_L2_EVENT) { 97862306a36Sopenharmony_ci vsc85xx_eth1_next_comp(phydev, INGRESS, 97962306a36Sopenharmony_ci ANA_ETH1_NTX_PROT_PTP_OAM, ETH_P_1588); 98062306a36Sopenharmony_ci vsc85xx_eth1_next_comp(phydev, EGRESS, 98162306a36Sopenharmony_ci ANA_ETH1_NTX_PROT_PTP_OAM, ETH_P_1588); 98262306a36Sopenharmony_ci } else { 98362306a36Sopenharmony_ci vsc85xx_eth1_next_comp(phydev, INGRESS, 98462306a36Sopenharmony_ci ANA_ETH1_NTX_PROT_IP_UDP_ACH_1, 98562306a36Sopenharmony_ci ETH_P_IP); 98662306a36Sopenharmony_ci vsc85xx_eth1_next_comp(phydev, EGRESS, 98762306a36Sopenharmony_ci ANA_ETH1_NTX_PROT_IP_UDP_ACH_1, 98862306a36Sopenharmony_ci ETH_P_IP); 98962306a36Sopenharmony_ci /* Header length of IPv[4/6] + UDP */ 99062306a36Sopenharmony_ci vsc85xx_ip1_next_comp(phydev, INGRESS, 99162306a36Sopenharmony_ci ANA_ETH1_NTX_PROT_PTP_OAM, 28); 99262306a36Sopenharmony_ci vsc85xx_ip1_next_comp(phydev, EGRESS, 99362306a36Sopenharmony_ci ANA_ETH1_NTX_PROT_PTP_OAM, 28); 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci vsc85xx_eth1_conf(phydev, INGRESS, 99762306a36Sopenharmony_ci vsc8531->ptp->rx_filter != HWTSTAMP_FILTER_NONE); 99862306a36Sopenharmony_ci vsc85xx_ip1_conf(phydev, INGRESS, 99962306a36Sopenharmony_ci ptp_l4 && vsc8531->ptp->rx_filter != HWTSTAMP_FILTER_NONE); 100062306a36Sopenharmony_ci vsc85xx_ptp_conf(phydev, INGRESS, one_step, 100162306a36Sopenharmony_ci vsc8531->ptp->rx_filter != HWTSTAMP_FILTER_NONE); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci vsc85xx_eth1_conf(phydev, EGRESS, 100462306a36Sopenharmony_ci vsc8531->ptp->tx_type != HWTSTAMP_TX_OFF); 100562306a36Sopenharmony_ci vsc85xx_ip1_conf(phydev, EGRESS, 100662306a36Sopenharmony_ci ptp_l4 && vsc8531->ptp->tx_type != HWTSTAMP_TX_OFF); 100762306a36Sopenharmony_ci vsc85xx_ptp_conf(phydev, EGRESS, one_step, 100862306a36Sopenharmony_ci vsc8531->ptp->tx_type != HWTSTAMP_TX_OFF); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci val &= ~PTP_ANALYZER_MODE_EGR_ENA(BIT(eng_id)); 101162306a36Sopenharmony_ci if (vsc8531->ptp->tx_type != HWTSTAMP_TX_OFF) 101262306a36Sopenharmony_ci val |= PTP_ANALYZER_MODE_EGR_ENA(BIT(eng_id)); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci val &= ~PTP_ANALYZER_MODE_INGR_ENA(BIT(eng_id)); 101562306a36Sopenharmony_ci if (vsc8531->ptp->rx_filter != HWTSTAMP_FILTER_NONE) 101662306a36Sopenharmony_ci val |= PTP_ANALYZER_MODE_INGR_ENA(BIT(eng_id)); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_ANALYZER_MODE, 101962306a36Sopenharmony_ci val); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci return 0; 102262306a36Sopenharmony_ci} 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_civoid vsc85xx_link_change_notify(struct phy_device *phydev) 102562306a36Sopenharmony_ci{ 102662306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci mutex_lock(&priv->ts_lock); 102962306a36Sopenharmony_ci vsc85xx_ts_set_latencies(phydev); 103062306a36Sopenharmony_ci mutex_unlock(&priv->ts_lock); 103162306a36Sopenharmony_ci} 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_cistatic void vsc85xx_ts_reset_fifo(struct phy_device *phydev) 103462306a36Sopenharmony_ci{ 103562306a36Sopenharmony_ci u32 val; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 103862306a36Sopenharmony_ci MSCC_PHY_PTP_EGR_TS_FIFO_CTRL); 103962306a36Sopenharmony_ci val |= PTP_EGR_TS_FIFO_RESET; 104062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_TS_FIFO_CTRL, 104162306a36Sopenharmony_ci val); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci val &= ~PTP_EGR_TS_FIFO_RESET; 104462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_TS_FIFO_CTRL, 104562306a36Sopenharmony_ci val); 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cistatic int vsc85xx_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) 104962306a36Sopenharmony_ci{ 105062306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = 105162306a36Sopenharmony_ci container_of(mii_ts, struct vsc8531_private, mii_ts); 105262306a36Sopenharmony_ci struct phy_device *phydev = vsc8531->ptp->phydev; 105362306a36Sopenharmony_ci struct hwtstamp_config cfg; 105462306a36Sopenharmony_ci bool one_step = false; 105562306a36Sopenharmony_ci u32 val; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) 105862306a36Sopenharmony_ci return -EFAULT; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci switch (cfg.tx_type) { 106162306a36Sopenharmony_ci case HWTSTAMP_TX_ONESTEP_SYNC: 106262306a36Sopenharmony_ci one_step = true; 106362306a36Sopenharmony_ci break; 106462306a36Sopenharmony_ci case HWTSTAMP_TX_ON: 106562306a36Sopenharmony_ci break; 106662306a36Sopenharmony_ci case HWTSTAMP_TX_OFF: 106762306a36Sopenharmony_ci break; 106862306a36Sopenharmony_ci default: 106962306a36Sopenharmony_ci return -ERANGE; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci vsc8531->ptp->tx_type = cfg.tx_type; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci switch (cfg.rx_filter) { 107562306a36Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 107662306a36Sopenharmony_ci break; 107762306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 107862306a36Sopenharmony_ci /* ETH->IP->UDP->PTP */ 107962306a36Sopenharmony_ci break; 108062306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 108162306a36Sopenharmony_ci /* ETH->PTP */ 108262306a36Sopenharmony_ci break; 108362306a36Sopenharmony_ci default: 108462306a36Sopenharmony_ci return -ERANGE; 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci vsc8531->ptp->rx_filter = cfg.rx_filter; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci mutex_lock(&vsc8531->ts_lock); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci __skb_queue_purge(&vsc8531->ptp->tx_queue); 109262306a36Sopenharmony_ci __skb_queue_head_init(&vsc8531->ptp->tx_queue); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci /* Disable predictor while configuring the 1588 block */ 109562306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 109662306a36Sopenharmony_ci MSCC_PHY_PTP_INGR_PREDICTOR); 109762306a36Sopenharmony_ci val &= ~PTP_INGR_PREDICTOR_EN; 109862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_INGR_PREDICTOR, 109962306a36Sopenharmony_ci val); 110062306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 110162306a36Sopenharmony_ci MSCC_PHY_PTP_EGR_PREDICTOR); 110262306a36Sopenharmony_ci val &= ~PTP_EGR_PREDICTOR_EN; 110362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_PREDICTOR, 110462306a36Sopenharmony_ci val); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci /* Bypass egress or ingress blocks if timestamping isn't used */ 110762306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, MSCC_PHY_PTP_IFACE_CTRL); 110862306a36Sopenharmony_ci val &= ~(PTP_IFACE_CTRL_EGR_BYPASS | PTP_IFACE_CTRL_INGR_BYPASS); 110962306a36Sopenharmony_ci if (vsc8531->ptp->tx_type == HWTSTAMP_TX_OFF) 111062306a36Sopenharmony_ci val |= PTP_IFACE_CTRL_EGR_BYPASS; 111162306a36Sopenharmony_ci if (vsc8531->ptp->rx_filter == HWTSTAMP_FILTER_NONE) 111262306a36Sopenharmony_ci val |= PTP_IFACE_CTRL_INGR_BYPASS; 111362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_IFACE_CTRL, val); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci /* Resetting FIFO so that it's empty after reconfiguration */ 111662306a36Sopenharmony_ci vsc85xx_ts_reset_fifo(phydev); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci vsc85xx_ts_engine_init(phydev, one_step); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci /* Re-enable predictors now */ 112162306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 112262306a36Sopenharmony_ci MSCC_PHY_PTP_INGR_PREDICTOR); 112362306a36Sopenharmony_ci val |= PTP_INGR_PREDICTOR_EN; 112462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_INGR_PREDICTOR, 112562306a36Sopenharmony_ci val); 112662306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 112762306a36Sopenharmony_ci MSCC_PHY_PTP_EGR_PREDICTOR); 112862306a36Sopenharmony_ci val |= PTP_EGR_PREDICTOR_EN; 112962306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_PREDICTOR, 113062306a36Sopenharmony_ci val); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci vsc8531->ptp->configured = 1; 113362306a36Sopenharmony_ci mutex_unlock(&vsc8531->ts_lock); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic int vsc85xx_ts_info(struct mii_timestamper *mii_ts, 113962306a36Sopenharmony_ci struct ethtool_ts_info *info) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = 114262306a36Sopenharmony_ci container_of(mii_ts, struct vsc8531_private, mii_ts); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci info->phc_index = ptp_clock_index(vsc8531->ptp->ptp_clock); 114562306a36Sopenharmony_ci info->so_timestamping = 114662306a36Sopenharmony_ci SOF_TIMESTAMPING_TX_HARDWARE | 114762306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 114862306a36Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 114962306a36Sopenharmony_ci info->tx_types = 115062306a36Sopenharmony_ci (1 << HWTSTAMP_TX_OFF) | 115162306a36Sopenharmony_ci (1 << HWTSTAMP_TX_ON) | 115262306a36Sopenharmony_ci (1 << HWTSTAMP_TX_ONESTEP_SYNC); 115362306a36Sopenharmony_ci info->rx_filters = 115462306a36Sopenharmony_ci (1 << HWTSTAMP_FILTER_NONE) | 115562306a36Sopenharmony_ci (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | 115662306a36Sopenharmony_ci (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT); 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci return 0; 115962306a36Sopenharmony_ci} 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_cistatic void vsc85xx_txtstamp(struct mii_timestamper *mii_ts, 116262306a36Sopenharmony_ci struct sk_buff *skb, int type) 116362306a36Sopenharmony_ci{ 116462306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = 116562306a36Sopenharmony_ci container_of(mii_ts, struct vsc8531_private, mii_ts); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (!vsc8531->ptp->configured) 116862306a36Sopenharmony_ci return; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci if (vsc8531->ptp->tx_type == HWTSTAMP_TX_OFF) { 117162306a36Sopenharmony_ci kfree_skb(skb); 117262306a36Sopenharmony_ci return; 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci mutex_lock(&vsc8531->ts_lock); 117862306a36Sopenharmony_ci __skb_queue_tail(&vsc8531->ptp->tx_queue, skb); 117962306a36Sopenharmony_ci mutex_unlock(&vsc8531->ts_lock); 118062306a36Sopenharmony_ci} 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_cistatic bool vsc85xx_rxtstamp(struct mii_timestamper *mii_ts, 118362306a36Sopenharmony_ci struct sk_buff *skb, int type) 118462306a36Sopenharmony_ci{ 118562306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = 118662306a36Sopenharmony_ci container_of(mii_ts, struct vsc8531_private, mii_ts); 118762306a36Sopenharmony_ci struct skb_shared_hwtstamps *shhwtstamps = NULL; 118862306a36Sopenharmony_ci struct vsc85xx_ptphdr *ptphdr; 118962306a36Sopenharmony_ci struct timespec64 ts; 119062306a36Sopenharmony_ci unsigned long ns; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if (!vsc8531->ptp->configured) 119362306a36Sopenharmony_ci return false; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (vsc8531->ptp->rx_filter == HWTSTAMP_FILTER_NONE || 119662306a36Sopenharmony_ci type == PTP_CLASS_NONE) 119762306a36Sopenharmony_ci return false; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci vsc85xx_gettime(&vsc8531->ptp->caps, &ts); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci ptphdr = get_ptp_header_rx(skb, vsc8531->ptp->rx_filter); 120262306a36Sopenharmony_ci if (!ptphdr) 120362306a36Sopenharmony_ci return false; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci shhwtstamps = skb_hwtstamps(skb); 120662306a36Sopenharmony_ci memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci ns = ntohl(ptphdr->rsrvd2); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci /* nsec is in reserved field */ 121162306a36Sopenharmony_ci if (ts.tv_nsec < ns) 121262306a36Sopenharmony_ci ts.tv_sec--; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci shhwtstamps->hwtstamp = ktime_set(ts.tv_sec, ns); 121562306a36Sopenharmony_ci netif_rx(skb); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci return true; 121862306a36Sopenharmony_ci} 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_cistatic const struct ptp_clock_info vsc85xx_clk_caps = { 122162306a36Sopenharmony_ci .owner = THIS_MODULE, 122262306a36Sopenharmony_ci .name = "VSC85xx timer", 122362306a36Sopenharmony_ci .max_adj = S32_MAX, 122462306a36Sopenharmony_ci .n_alarm = 0, 122562306a36Sopenharmony_ci .n_pins = 0, 122662306a36Sopenharmony_ci .n_ext_ts = 0, 122762306a36Sopenharmony_ci .n_per_out = 0, 122862306a36Sopenharmony_ci .pps = 0, 122962306a36Sopenharmony_ci .adjtime = &vsc85xx_adjtime, 123062306a36Sopenharmony_ci .adjfine = &vsc85xx_adjfine, 123162306a36Sopenharmony_ci .gettime64 = &vsc85xx_gettime, 123262306a36Sopenharmony_ci .settime64 = &vsc85xx_settime, 123362306a36Sopenharmony_ci}; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic struct vsc8531_private *vsc8584_base_priv(struct phy_device *phydev) 123662306a36Sopenharmony_ci{ 123762306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = phydev->priv; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci if (vsc8531->ts_base_addr != phydev->mdio.addr) { 124062306a36Sopenharmony_ci struct mdio_device *dev; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci dev = phydev->mdio.bus->mdio_map[vsc8531->ts_base_addr]; 124362306a36Sopenharmony_ci phydev = container_of(dev, struct phy_device, mdio); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci return phydev->priv; 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci return vsc8531; 124962306a36Sopenharmony_ci} 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_cistatic bool vsc8584_is_1588_input_clk_configured(struct phy_device *phydev) 125262306a36Sopenharmony_ci{ 125362306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = vsc8584_base_priv(phydev); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci return vsc8531->input_clk_init; 125662306a36Sopenharmony_ci} 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_cistatic void vsc8584_set_input_clk_configured(struct phy_device *phydev) 125962306a36Sopenharmony_ci{ 126062306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = vsc8584_base_priv(phydev); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci vsc8531->input_clk_init = true; 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_cistatic int __vsc8584_init_ptp(struct phy_device *phydev) 126662306a36Sopenharmony_ci{ 126762306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = phydev->priv; 126862306a36Sopenharmony_ci static const u32 ltc_seq_e[] = { 0, 400000, 0, 0, 0 }; 126962306a36Sopenharmony_ci static const u8 ltc_seq_a[] = { 8, 6, 5, 4, 2 }; 127062306a36Sopenharmony_ci u32 val; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci if (!vsc8584_is_1588_input_clk_configured(phydev)) { 127362306a36Sopenharmony_ci phy_lock_mdio_bus(phydev); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci /* 1588_DIFF_INPUT_CLK configuration: Use an external clock for 127662306a36Sopenharmony_ci * the LTC, as per 3.13.29 in the VSC8584 datasheet. 127762306a36Sopenharmony_ci */ 127862306a36Sopenharmony_ci phy_ts_base_write(phydev, MSCC_EXT_PAGE_ACCESS, 127962306a36Sopenharmony_ci MSCC_PHY_PAGE_1588); 128062306a36Sopenharmony_ci phy_ts_base_write(phydev, 29, 0x7ae0); 128162306a36Sopenharmony_ci phy_ts_base_write(phydev, 30, 0xb71c); 128262306a36Sopenharmony_ci phy_ts_base_write(phydev, MSCC_EXT_PAGE_ACCESS, 128362306a36Sopenharmony_ci MSCC_PHY_PAGE_STANDARD); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci phy_unlock_mdio_bus(phydev); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci vsc8584_set_input_clk_configured(phydev); 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci /* Disable predictor before configuring the 1588 block */ 129162306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 129262306a36Sopenharmony_ci MSCC_PHY_PTP_INGR_PREDICTOR); 129362306a36Sopenharmony_ci val &= ~PTP_INGR_PREDICTOR_EN; 129462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_INGR_PREDICTOR, 129562306a36Sopenharmony_ci val); 129662306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 129762306a36Sopenharmony_ci MSCC_PHY_PTP_EGR_PREDICTOR); 129862306a36Sopenharmony_ci val &= ~PTP_EGR_PREDICTOR_EN; 129962306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_PREDICTOR, 130062306a36Sopenharmony_ci val); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci /* By default, the internal clock of fixed rate 250MHz is used */ 130362306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_CTRL); 130462306a36Sopenharmony_ci val &= ~PTP_LTC_CTRL_CLK_SEL_MASK; 130562306a36Sopenharmony_ci val |= PTP_LTC_CTRL_CLK_SEL_INTERNAL_250; 130662306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_CTRL, val); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_SEQUENCE); 130962306a36Sopenharmony_ci val &= ~PTP_LTC_SEQUENCE_A_MASK; 131062306a36Sopenharmony_ci val |= PTP_LTC_SEQUENCE_A(ltc_seq_a[PHC_CLK_250MHZ]); 131162306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_SEQUENCE, val); 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_SEQ); 131462306a36Sopenharmony_ci val &= ~(PTP_LTC_SEQ_ERR_MASK | PTP_LTC_SEQ_ADD_SUB); 131562306a36Sopenharmony_ci if (ltc_seq_e[PHC_CLK_250MHZ]) 131662306a36Sopenharmony_ci val |= PTP_LTC_SEQ_ADD_SUB; 131762306a36Sopenharmony_ci val |= PTP_LTC_SEQ_ERR(ltc_seq_e[PHC_CLK_250MHZ]); 131862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_SEQ, val); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_LTC_1PPS_WIDTH_ADJ, 132162306a36Sopenharmony_ci PPS_WIDTH_ADJ); 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_INGR_DELAY_FIFO, 132462306a36Sopenharmony_ci IS_ENABLED(CONFIG_MACSEC) ? 132562306a36Sopenharmony_ci PTP_INGR_DELAY_FIFO_DEPTH_MACSEC : 132662306a36Sopenharmony_ci PTP_INGR_DELAY_FIFO_DEPTH_DEFAULT); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_DELAY_FIFO, 132962306a36Sopenharmony_ci IS_ENABLED(CONFIG_MACSEC) ? 133062306a36Sopenharmony_ci PTP_EGR_DELAY_FIFO_DEPTH_MACSEC : 133162306a36Sopenharmony_ci PTP_EGR_DELAY_FIFO_DEPTH_DEFAULT); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci /* Enable n-phase sampler for Viper Rev-B */ 133462306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 133562306a36Sopenharmony_ci MSCC_PHY_PTP_ACCUR_CFG_STATUS); 133662306a36Sopenharmony_ci val &= ~(PTP_ACCUR_PPS_OUT_BYPASS | PTP_ACCUR_PPS_IN_BYPASS | 133762306a36Sopenharmony_ci PTP_ACCUR_EGR_SOF_BYPASS | PTP_ACCUR_INGR_SOF_BYPASS | 133862306a36Sopenharmony_ci PTP_ACCUR_LOAD_SAVE_BYPASS); 133962306a36Sopenharmony_ci val |= PTP_ACCUR_PPS_OUT_CALIB_ERR | PTP_ACCUR_PPS_OUT_CALIB_DONE | 134062306a36Sopenharmony_ci PTP_ACCUR_PPS_IN_CALIB_ERR | PTP_ACCUR_PPS_IN_CALIB_DONE | 134162306a36Sopenharmony_ci PTP_ACCUR_EGR_SOF_CALIB_ERR | PTP_ACCUR_EGR_SOF_CALIB_DONE | 134262306a36Sopenharmony_ci PTP_ACCUR_INGR_SOF_CALIB_ERR | PTP_ACCUR_INGR_SOF_CALIB_DONE | 134362306a36Sopenharmony_ci PTP_ACCUR_LOAD_SAVE_CALIB_ERR | PTP_ACCUR_LOAD_SAVE_CALIB_DONE; 134462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_ACCUR_CFG_STATUS, 134562306a36Sopenharmony_ci val); 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 134862306a36Sopenharmony_ci MSCC_PHY_PTP_ACCUR_CFG_STATUS); 134962306a36Sopenharmony_ci val |= PTP_ACCUR_CALIB_TRIGG; 135062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_ACCUR_CFG_STATUS, 135162306a36Sopenharmony_ci val); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 135462306a36Sopenharmony_ci MSCC_PHY_PTP_ACCUR_CFG_STATUS); 135562306a36Sopenharmony_ci val &= ~PTP_ACCUR_CALIB_TRIGG; 135662306a36Sopenharmony_ci val |= PTP_ACCUR_PPS_OUT_CALIB_ERR | PTP_ACCUR_PPS_OUT_CALIB_DONE | 135762306a36Sopenharmony_ci PTP_ACCUR_PPS_IN_CALIB_ERR | PTP_ACCUR_PPS_IN_CALIB_DONE | 135862306a36Sopenharmony_ci PTP_ACCUR_EGR_SOF_CALIB_ERR | PTP_ACCUR_EGR_SOF_CALIB_DONE | 135962306a36Sopenharmony_ci PTP_ACCUR_INGR_SOF_CALIB_ERR | PTP_ACCUR_INGR_SOF_CALIB_DONE | 136062306a36Sopenharmony_ci PTP_ACCUR_LOAD_SAVE_CALIB_ERR | PTP_ACCUR_LOAD_SAVE_CALIB_DONE; 136162306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_ACCUR_CFG_STATUS, 136262306a36Sopenharmony_ci val); 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 136562306a36Sopenharmony_ci MSCC_PHY_PTP_ACCUR_CFG_STATUS); 136662306a36Sopenharmony_ci val |= PTP_ACCUR_CALIB_TRIGG; 136762306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_ACCUR_CFG_STATUS, 136862306a36Sopenharmony_ci val); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 137162306a36Sopenharmony_ci MSCC_PHY_PTP_ACCUR_CFG_STATUS); 137262306a36Sopenharmony_ci val &= ~PTP_ACCUR_CALIB_TRIGG; 137362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_ACCUR_CFG_STATUS, 137462306a36Sopenharmony_ci val); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci /* Do not access FIFO via SI */ 137762306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 137862306a36Sopenharmony_ci MSCC_PHY_PTP_TSTAMP_FIFO_SI); 137962306a36Sopenharmony_ci val &= ~PTP_TSTAMP_FIFO_SI_EN; 138062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_TSTAMP_FIFO_SI, 138162306a36Sopenharmony_ci val); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 138462306a36Sopenharmony_ci MSCC_PHY_PTP_INGR_REWRITER_CTRL); 138562306a36Sopenharmony_ci val &= ~PTP_INGR_REWRITER_REDUCE_PREAMBLE; 138662306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_INGR_REWRITER_CTRL, 138762306a36Sopenharmony_ci val); 138862306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 138962306a36Sopenharmony_ci MSCC_PHY_PTP_EGR_REWRITER_CTRL); 139062306a36Sopenharmony_ci val &= ~PTP_EGR_REWRITER_REDUCE_PREAMBLE; 139162306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_REWRITER_CTRL, 139262306a36Sopenharmony_ci val); 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci /* Put the flag that indicates the frame has been modified to bit 7 */ 139562306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 139662306a36Sopenharmony_ci MSCC_PHY_PTP_INGR_REWRITER_CTRL); 139762306a36Sopenharmony_ci val |= PTP_INGR_REWRITER_FLAG_BIT_OFF(7) | PTP_INGR_REWRITER_FLAG_VAL; 139862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_INGR_REWRITER_CTRL, 139962306a36Sopenharmony_ci val); 140062306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 140162306a36Sopenharmony_ci MSCC_PHY_PTP_EGR_REWRITER_CTRL); 140262306a36Sopenharmony_ci val |= PTP_EGR_REWRITER_FLAG_BIT_OFF(7); 140362306a36Sopenharmony_ci val &= ~PTP_EGR_REWRITER_FLAG_VAL; 140462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_REWRITER_CTRL, 140562306a36Sopenharmony_ci val); 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci /* 30bit mode for RX timestamp, only the nanoseconds are kept in 140862306a36Sopenharmony_ci * reserved field. 140962306a36Sopenharmony_ci */ 141062306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 141162306a36Sopenharmony_ci MSCC_PHY_PTP_INGR_TSP_CTRL); 141262306a36Sopenharmony_ci val |= PHY_PTP_INGR_TSP_CTRL_FRACT_NS; 141362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_INGR_TSP_CTRL, 141462306a36Sopenharmony_ci val); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_TSP_CTRL); 141762306a36Sopenharmony_ci val |= PHY_PTP_EGR_TSP_CTRL_FRACT_NS; 141862306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_TSP_CTRL, val); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 142162306a36Sopenharmony_ci MSCC_PHY_PTP_SERIAL_TOD_IFACE); 142262306a36Sopenharmony_ci val |= PTP_SERIAL_TOD_IFACE_LS_AUTO_CLR; 142362306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_SERIAL_TOD_IFACE, 142462306a36Sopenharmony_ci val); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci vsc85xx_ts_fsb_init(phydev); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci /* Set the Egress timestamp FIFO configuration and status register */ 142962306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 143062306a36Sopenharmony_ci MSCC_PHY_PTP_EGR_TS_FIFO_CTRL); 143162306a36Sopenharmony_ci val &= ~(PTP_EGR_TS_FIFO_SIG_BYTES_MASK | PTP_EGR_TS_FIFO_THRESH_MASK); 143262306a36Sopenharmony_ci /* 16 bytes for the signature, 10 for the timestamp in the TS FIFO */ 143362306a36Sopenharmony_ci val |= PTP_EGR_TS_FIFO_SIG_BYTES(16) | PTP_EGR_TS_FIFO_THRESH(7); 143462306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_EGR_TS_FIFO_CTRL, 143562306a36Sopenharmony_ci val); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci vsc85xx_ts_reset_fifo(phydev); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci val = PTP_IFACE_CTRL_CLK_ENA; 144062306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_MACSEC)) 144162306a36Sopenharmony_ci val |= PTP_IFACE_CTRL_GMII_PROT; 144262306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_IFACE_CTRL, val); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci vsc85xx_ts_set_latencies(phydev); 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, MSCC_PHY_PTP_VERSION_CODE); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, MSCC_PHY_PTP_IFACE_CTRL); 144962306a36Sopenharmony_ci val |= PTP_IFACE_CTRL_EGR_BYPASS; 145062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_IFACE_CTRL, val); 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci vsc85xx_ts_disable_flows(phydev, EGRESS); 145362306a36Sopenharmony_ci vsc85xx_ts_disable_flows(phydev, INGRESS); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci val = vsc85xx_ts_read_csr(phydev, PROCESSOR, 145662306a36Sopenharmony_ci MSCC_PHY_PTP_ANALYZER_MODE); 145762306a36Sopenharmony_ci /* Disable INGRESS and EGRESS so engine eng_id can be reconfigured */ 145862306a36Sopenharmony_ci val &= ~(PTP_ANALYZER_MODE_EGR_ENA_MASK | 145962306a36Sopenharmony_ci PTP_ANALYZER_MODE_INGR_ENA_MASK | 146062306a36Sopenharmony_ci PTP_ANA_INGR_ENCAP_FLOW_MODE_MASK | 146162306a36Sopenharmony_ci PTP_ANA_EGR_ENCAP_FLOW_MODE_MASK); 146262306a36Sopenharmony_ci /* Strict matching in flow (packets should match flows from the same 146362306a36Sopenharmony_ci * index in all enabled comparators (except PTP)). 146462306a36Sopenharmony_ci */ 146562306a36Sopenharmony_ci val |= PTP_ANA_SPLIT_ENCAP_FLOW | PTP_ANA_INGR_ENCAP_FLOW_MODE(0x7) | 146662306a36Sopenharmony_ci PTP_ANA_EGR_ENCAP_FLOW_MODE(0x7); 146762306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_PTP_ANALYZER_MODE, 146862306a36Sopenharmony_ci val); 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci /* Initialized for ingress and egress flows: 147162306a36Sopenharmony_ci * - The Ethernet comparator. 147262306a36Sopenharmony_ci * - The IP comparator. 147362306a36Sopenharmony_ci * - The PTP comparator. 147462306a36Sopenharmony_ci */ 147562306a36Sopenharmony_ci vsc85xx_eth_cmp1_init(phydev, INGRESS); 147662306a36Sopenharmony_ci vsc85xx_ip_cmp1_init(phydev, INGRESS); 147762306a36Sopenharmony_ci vsc85xx_ptp_cmp_init(phydev, INGRESS); 147862306a36Sopenharmony_ci vsc85xx_eth_cmp1_init(phydev, EGRESS); 147962306a36Sopenharmony_ci vsc85xx_ip_cmp1_init(phydev, EGRESS); 148062306a36Sopenharmony_ci vsc85xx_ptp_cmp_init(phydev, EGRESS); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci vsc85xx_ts_eth_cmp1_sig(phydev); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci vsc8531->mii_ts.rxtstamp = vsc85xx_rxtstamp; 148562306a36Sopenharmony_ci vsc8531->mii_ts.txtstamp = vsc85xx_txtstamp; 148662306a36Sopenharmony_ci vsc8531->mii_ts.hwtstamp = vsc85xx_hwtstamp; 148762306a36Sopenharmony_ci vsc8531->mii_ts.ts_info = vsc85xx_ts_info; 148862306a36Sopenharmony_ci phydev->mii_ts = &vsc8531->mii_ts; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci memcpy(&vsc8531->ptp->caps, &vsc85xx_clk_caps, sizeof(vsc85xx_clk_caps)); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci vsc8531->ptp->ptp_clock = ptp_clock_register(&vsc8531->ptp->caps, 149362306a36Sopenharmony_ci &phydev->mdio.dev); 149462306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(vsc8531->ptp->ptp_clock); 149562306a36Sopenharmony_ci} 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_civoid vsc8584_config_ts_intr(struct phy_device *phydev) 149862306a36Sopenharmony_ci{ 149962306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci mutex_lock(&priv->ts_lock); 150262306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, MSCC_PHY_1588_VSC85XX_INT_MASK, 150362306a36Sopenharmony_ci VSC85XX_1588_INT_MASK_MASK); 150462306a36Sopenharmony_ci mutex_unlock(&priv->ts_lock); 150562306a36Sopenharmony_ci} 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ciint vsc8584_ptp_init(struct phy_device *phydev) 150862306a36Sopenharmony_ci{ 150962306a36Sopenharmony_ci switch (phydev->phy_id & phydev->drv->phy_id_mask) { 151062306a36Sopenharmony_ci case PHY_ID_VSC8572: 151162306a36Sopenharmony_ci case PHY_ID_VSC8574: 151262306a36Sopenharmony_ci case PHY_ID_VSC8575: 151362306a36Sopenharmony_ci case PHY_ID_VSC8582: 151462306a36Sopenharmony_ci case PHY_ID_VSC8584: 151562306a36Sopenharmony_ci return __vsc8584_init_ptp(phydev); 151662306a36Sopenharmony_ci } 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci return 0; 151962306a36Sopenharmony_ci} 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ciirqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev) 152262306a36Sopenharmony_ci{ 152362306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 152462306a36Sopenharmony_ci int rc; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci mutex_lock(&priv->ts_lock); 152762306a36Sopenharmony_ci rc = vsc85xx_ts_read_csr(phydev, PROCESSOR, 152862306a36Sopenharmony_ci MSCC_PHY_1588_VSC85XX_INT_STATUS); 152962306a36Sopenharmony_ci /* Ack the PTP interrupt */ 153062306a36Sopenharmony_ci vsc85xx_ts_write_csr(phydev, PROCESSOR, 153162306a36Sopenharmony_ci MSCC_PHY_1588_VSC85XX_INT_STATUS, rc); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci if (!(rc & VSC85XX_1588_INT_MASK_MASK)) { 153462306a36Sopenharmony_ci mutex_unlock(&priv->ts_lock); 153562306a36Sopenharmony_ci return IRQ_NONE; 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci if (rc & VSC85XX_1588_INT_FIFO_ADD) { 153962306a36Sopenharmony_ci vsc85xx_get_tx_ts(priv->ptp); 154062306a36Sopenharmony_ci } else if (rc & VSC85XX_1588_INT_FIFO_OVERFLOW) { 154162306a36Sopenharmony_ci __skb_queue_purge(&priv->ptp->tx_queue); 154262306a36Sopenharmony_ci vsc85xx_ts_reset_fifo(phydev); 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci mutex_unlock(&priv->ts_lock); 154662306a36Sopenharmony_ci return IRQ_HANDLED; 154762306a36Sopenharmony_ci} 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ciint vsc8584_ptp_probe(struct phy_device *phydev) 155062306a36Sopenharmony_ci{ 155162306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = phydev->priv; 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci vsc8531->ptp = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531->ptp), 155462306a36Sopenharmony_ci GFP_KERNEL); 155562306a36Sopenharmony_ci if (!vsc8531->ptp) 155662306a36Sopenharmony_ci return -ENOMEM; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci mutex_init(&vsc8531->phc_lock); 155962306a36Sopenharmony_ci mutex_init(&vsc8531->ts_lock); 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci /* Retrieve the shared load/save GPIO. Request it as non exclusive as 156262306a36Sopenharmony_ci * the same GPIO can be requested by all the PHYs of the same package. 156362306a36Sopenharmony_ci * This GPIO must be used with the gpio_lock taken (the lock is shared 156462306a36Sopenharmony_ci * between all PHYs). 156562306a36Sopenharmony_ci */ 156662306a36Sopenharmony_ci vsc8531->load_save = devm_gpiod_get_optional(&phydev->mdio.dev, "load-save", 156762306a36Sopenharmony_ci GPIOD_FLAGS_BIT_NONEXCLUSIVE | 156862306a36Sopenharmony_ci GPIOD_OUT_LOW); 156962306a36Sopenharmony_ci if (IS_ERR(vsc8531->load_save)) { 157062306a36Sopenharmony_ci phydev_err(phydev, "Can't get load-save GPIO (%ld)\n", 157162306a36Sopenharmony_ci PTR_ERR(vsc8531->load_save)); 157262306a36Sopenharmony_ci return PTR_ERR(vsc8531->load_save); 157362306a36Sopenharmony_ci } 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci vsc8531->ptp->phydev = phydev; 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci return 0; 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ciint vsc8584_ptp_probe_once(struct phy_device *phydev) 158162306a36Sopenharmony_ci{ 158262306a36Sopenharmony_ci struct vsc85xx_shared_private *shared = 158362306a36Sopenharmony_ci (struct vsc85xx_shared_private *)phydev->shared->priv; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci /* Initialize shared GPIO lock */ 158662306a36Sopenharmony_ci mutex_init(&shared->gpio_lock); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci return 0; 158962306a36Sopenharmony_ci} 1590