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