1b050f2f1SRadu Pirea (NXP OSS) // SPDX-License-Identifier: GPL-2.0 2b050f2f1SRadu Pirea (NXP OSS) /* NXP C45 PHY driver 3b050f2f1SRadu Pirea (NXP OSS) * Copyright (C) 2021 NXP 4b050f2f1SRadu Pirea (NXP OSS) * Author: Radu Pirea <radu-nicolae.pirea@oss.nxp.com> 5b050f2f1SRadu Pirea (NXP OSS) */ 6b050f2f1SRadu Pirea (NXP OSS) 7b050f2f1SRadu Pirea (NXP OSS) #include <linux/delay.h> 8b050f2f1SRadu Pirea (NXP OSS) #include <linux/ethtool.h> 9b050f2f1SRadu Pirea (NXP OSS) #include <linux/ethtool_netlink.h> 10b050f2f1SRadu Pirea (NXP OSS) #include <linux/kernel.h> 11b050f2f1SRadu Pirea (NXP OSS) #include <linux/mii.h> 12b050f2f1SRadu Pirea (NXP OSS) #include <linux/module.h> 13b050f2f1SRadu Pirea (NXP OSS) #include <linux/phy.h> 14b050f2f1SRadu Pirea (NXP OSS) #include <linux/processor.h> 15b050f2f1SRadu Pirea (NXP OSS) #include <linux/property.h> 16514def5dSRadu Pirea (NXP OSS) #include <linux/ptp_classify.h> 17514def5dSRadu Pirea (NXP OSS) #include <linux/ptp_clock_kernel.h> 18514def5dSRadu Pirea (NXP OSS) #include <linux/net_tstamp.h> 19b050f2f1SRadu Pirea (NXP OSS) 20b050f2f1SRadu Pirea (NXP OSS) #define PHY_ID_TJA_1103 0x001BB010 21b050f2f1SRadu Pirea (NXP OSS) 22b050f2f1SRadu Pirea (NXP OSS) #define PMAPMD_B100T1_PMAPMD_CTL 0x0834 23b050f2f1SRadu Pirea (NXP OSS) #define B100T1_PMAPMD_CONFIG_EN BIT(15) 24b050f2f1SRadu Pirea (NXP OSS) #define B100T1_PMAPMD_MASTER BIT(14) 25b050f2f1SRadu Pirea (NXP OSS) #define MASTER_MODE (B100T1_PMAPMD_CONFIG_EN | \ 26b050f2f1SRadu Pirea (NXP OSS) B100T1_PMAPMD_MASTER) 27b050f2f1SRadu Pirea (NXP OSS) #define SLAVE_MODE (B100T1_PMAPMD_CONFIG_EN) 28b050f2f1SRadu Pirea (NXP OSS) 29b050f2f1SRadu Pirea (NXP OSS) #define VEND1_DEVICE_CONTROL 0x0040 30b050f2f1SRadu Pirea (NXP OSS) #define DEVICE_CONTROL_RESET BIT(15) 31b050f2f1SRadu Pirea (NXP OSS) #define DEVICE_CONTROL_CONFIG_GLOBAL_EN BIT(14) 32b050f2f1SRadu Pirea (NXP OSS) #define DEVICE_CONTROL_CONFIG_ALL_EN BIT(13) 33b050f2f1SRadu Pirea (NXP OSS) 34b2f0ca00SRadu Pirea (NXP OSS) #define VEND1_PHY_IRQ_ACK 0x80A0 35b2f0ca00SRadu Pirea (NXP OSS) #define VEND1_PHY_IRQ_EN 0x80A1 36b2f0ca00SRadu Pirea (NXP OSS) #define VEND1_PHY_IRQ_STATUS 0x80A2 37b2f0ca00SRadu Pirea (NXP OSS) #define PHY_IRQ_LINK_EVENT BIT(1) 38b2f0ca00SRadu Pirea (NXP OSS) 39b050f2f1SRadu Pirea (NXP OSS) #define VEND1_PHY_CONTROL 0x8100 40b050f2f1SRadu Pirea (NXP OSS) #define PHY_CONFIG_EN BIT(14) 41b050f2f1SRadu Pirea (NXP OSS) #define PHY_START_OP BIT(0) 42b050f2f1SRadu Pirea (NXP OSS) 43b050f2f1SRadu Pirea (NXP OSS) #define VEND1_PHY_CONFIG 0x8108 44b050f2f1SRadu Pirea (NXP OSS) #define PHY_CONFIG_AUTO BIT(0) 45b050f2f1SRadu Pirea (NXP OSS) 46b050f2f1SRadu Pirea (NXP OSS) #define VEND1_SIGNAL_QUALITY 0x8320 47b050f2f1SRadu Pirea (NXP OSS) #define SQI_VALID BIT(14) 48b050f2f1SRadu Pirea (NXP OSS) #define SQI_MASK GENMASK(2, 0) 49b050f2f1SRadu Pirea (NXP OSS) #define MAX_SQI SQI_MASK 50b050f2f1SRadu Pirea (NXP OSS) 51b050f2f1SRadu Pirea (NXP OSS) #define VEND1_CABLE_TEST 0x8330 52b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_ENABLE BIT(15) 53b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_START BIT(14) 54b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_VALID BIT(13) 55b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_OK 0x00 56b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_SHORTED 0x01 57b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_OPEN 0x02 58b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_UNKNOWN 0x07 59b050f2f1SRadu Pirea (NXP OSS) 60b050f2f1SRadu Pirea (NXP OSS) #define VEND1_PORT_CONTROL 0x8040 61b050f2f1SRadu Pirea (NXP OSS) #define PORT_CONTROL_EN BIT(14) 62b050f2f1SRadu Pirea (NXP OSS) 63514def5dSRadu Pirea (NXP OSS) #define VEND1_PORT_ABILITIES 0x8046 64514def5dSRadu Pirea (NXP OSS) #define PTP_ABILITY BIT(3) 65514def5dSRadu Pirea (NXP OSS) 66b050f2f1SRadu Pirea (NXP OSS) #define VEND1_PORT_INFRA_CONTROL 0xAC00 67b050f2f1SRadu Pirea (NXP OSS) #define PORT_INFRA_CONTROL_EN BIT(14) 68b050f2f1SRadu Pirea (NXP OSS) 69b050f2f1SRadu Pirea (NXP OSS) #define VEND1_RXID 0xAFCC 70b050f2f1SRadu Pirea (NXP OSS) #define VEND1_TXID 0xAFCD 71b050f2f1SRadu Pirea (NXP OSS) #define ID_ENABLE BIT(15) 72b050f2f1SRadu Pirea (NXP OSS) 73b050f2f1SRadu Pirea (NXP OSS) #define VEND1_ABILITIES 0xAFC4 74b050f2f1SRadu Pirea (NXP OSS) #define RGMII_ID_ABILITY BIT(15) 75b050f2f1SRadu Pirea (NXP OSS) #define RGMII_ABILITY BIT(14) 76b050f2f1SRadu Pirea (NXP OSS) #define RMII_ABILITY BIT(10) 77b050f2f1SRadu Pirea (NXP OSS) #define REVMII_ABILITY BIT(9) 78b050f2f1SRadu Pirea (NXP OSS) #define MII_ABILITY BIT(8) 79b050f2f1SRadu Pirea (NXP OSS) #define SGMII_ABILITY BIT(0) 80b050f2f1SRadu Pirea (NXP OSS) 81b050f2f1SRadu Pirea (NXP OSS) #define VEND1_MII_BASIC_CONFIG 0xAFC6 82b050f2f1SRadu Pirea (NXP OSS) #define MII_BASIC_CONFIG_REV BIT(8) 83b050f2f1SRadu Pirea (NXP OSS) #define MII_BASIC_CONFIG_SGMII 0x9 84b050f2f1SRadu Pirea (NXP OSS) #define MII_BASIC_CONFIG_RGMII 0x7 85b050f2f1SRadu Pirea (NXP OSS) #define MII_BASIC_CONFIG_RMII 0x5 86b050f2f1SRadu Pirea (NXP OSS) #define MII_BASIC_CONFIG_MII 0x4 87b050f2f1SRadu Pirea (NXP OSS) 88b050f2f1SRadu Pirea (NXP OSS) #define VEND1_SYMBOL_ERROR_COUNTER 0x8350 89b050f2f1SRadu Pirea (NXP OSS) #define VEND1_LINK_DROP_COUNTER 0x8352 90b050f2f1SRadu Pirea (NXP OSS) #define VEND1_LINK_LOSSES_AND_FAILURES 0x8353 91b050f2f1SRadu Pirea (NXP OSS) #define VEND1_R_GOOD_FRAME_CNT 0xA950 92b050f2f1SRadu Pirea (NXP OSS) #define VEND1_R_BAD_FRAME_CNT 0xA952 93b050f2f1SRadu Pirea (NXP OSS) #define VEND1_R_RXER_FRAME_CNT 0xA954 94b050f2f1SRadu Pirea (NXP OSS) #define VEND1_RX_PREAMBLE_COUNT 0xAFCE 95b050f2f1SRadu Pirea (NXP OSS) #define VEND1_TX_PREAMBLE_COUNT 0xAFCF 96b050f2f1SRadu Pirea (NXP OSS) #define VEND1_RX_IPG_LENGTH 0xAFD0 97b050f2f1SRadu Pirea (NXP OSS) #define VEND1_TX_IPG_LENGTH 0xAFD1 98b050f2f1SRadu Pirea (NXP OSS) #define COUNTER_EN BIT(15) 99b050f2f1SRadu Pirea (NXP OSS) 100514def5dSRadu Pirea (NXP OSS) #define VEND1_LTC_LOAD_CTRL 0x1105 101514def5dSRadu Pirea (NXP OSS) #define READ_LTC BIT(2) 102514def5dSRadu Pirea (NXP OSS) #define LOAD_LTC BIT(0) 103514def5dSRadu Pirea (NXP OSS) 104514def5dSRadu Pirea (NXP OSS) #define VEND1_LTC_WR_NSEC_0 0x1106 105514def5dSRadu Pirea (NXP OSS) #define VEND1_LTC_WR_NSEC_1 0x1107 106514def5dSRadu Pirea (NXP OSS) #define VEND1_LTC_WR_SEC_0 0x1108 107514def5dSRadu Pirea (NXP OSS) #define VEND1_LTC_WR_SEC_1 0x1109 108514def5dSRadu Pirea (NXP OSS) 109514def5dSRadu Pirea (NXP OSS) #define VEND1_LTC_RD_NSEC_0 0x110A 110514def5dSRadu Pirea (NXP OSS) #define VEND1_LTC_RD_NSEC_1 0x110B 111514def5dSRadu Pirea (NXP OSS) #define VEND1_LTC_RD_SEC_0 0x110C 112514def5dSRadu Pirea (NXP OSS) #define VEND1_LTC_RD_SEC_1 0x110D 113514def5dSRadu Pirea (NXP OSS) 114514def5dSRadu Pirea (NXP OSS) #define VEND1_RATE_ADJ_SUBNS_0 0x110F 115514def5dSRadu Pirea (NXP OSS) #define VEND1_RATE_ADJ_SUBNS_1 0x1110 116514def5dSRadu Pirea (NXP OSS) #define CLK_RATE_ADJ_LD BIT(15) 117514def5dSRadu Pirea (NXP OSS) #define CLK_RATE_ADJ_DIR BIT(14) 118514def5dSRadu Pirea (NXP OSS) 119514def5dSRadu Pirea (NXP OSS) #define VEND1_HW_LTC_LOCK_CTRL 0x1115 120514def5dSRadu Pirea (NXP OSS) #define HW_LTC_LOCK_EN BIT(0) 121514def5dSRadu Pirea (NXP OSS) 122514def5dSRadu Pirea (NXP OSS) #define VEND1_PTP_IRQ_EN 0x1131 123514def5dSRadu Pirea (NXP OSS) #define VEND1_PTP_IRQ_STATUS 0x1132 124514def5dSRadu Pirea (NXP OSS) #define PTP_IRQ_EGR_TS BIT(0) 125514def5dSRadu Pirea (NXP OSS) 126514def5dSRadu Pirea (NXP OSS) #define VEND1_RX_TS_INSRT_CTRL 0x114D 127514def5dSRadu Pirea (NXP OSS) #define RX_TS_INSRT_MODE2 0x02 128514def5dSRadu Pirea (NXP OSS) 129514def5dSRadu Pirea (NXP OSS) #define VEND1_EGR_RING_DATA_0 0x114E 130514def5dSRadu Pirea (NXP OSS) #define VEND1_EGR_RING_DATA_1_SEQ_ID 0x114F 131514def5dSRadu Pirea (NXP OSS) #define VEND1_EGR_RING_DATA_2_NSEC_15_0 0x1150 132514def5dSRadu Pirea (NXP OSS) #define VEND1_EGR_RING_DATA_3 0x1151 133514def5dSRadu Pirea (NXP OSS) #define VEND1_EGR_RING_CTRL 0x1154 134514def5dSRadu Pirea (NXP OSS) 135514def5dSRadu Pirea (NXP OSS) #define RING_DATA_0_DOMAIN_NUMBER GENMASK(7, 0) 136514def5dSRadu Pirea (NXP OSS) #define RING_DATA_0_MSG_TYPE GENMASK(11, 8) 137514def5dSRadu Pirea (NXP OSS) #define RING_DATA_0_SEC_4_2 GENMASK(14, 2) 138514def5dSRadu Pirea (NXP OSS) #define RING_DATA_0_TS_VALID BIT(15) 139514def5dSRadu Pirea (NXP OSS) 140514def5dSRadu Pirea (NXP OSS) #define RING_DATA_3_NSEC_29_16 GENMASK(13, 0) 141514def5dSRadu Pirea (NXP OSS) #define RING_DATA_3_SEC_1_0 GENMASK(15, 14) 142514def5dSRadu Pirea (NXP OSS) #define RING_DATA_5_SEC_16_5 GENMASK(15, 4) 143514def5dSRadu Pirea (NXP OSS) #define RING_DONE BIT(0) 144514def5dSRadu Pirea (NXP OSS) 145514def5dSRadu Pirea (NXP OSS) #define TS_SEC_MASK GENMASK(1, 0) 146514def5dSRadu Pirea (NXP OSS) 147514def5dSRadu Pirea (NXP OSS) #define VEND1_PORT_FUNC_ENABLES 0x8048 148514def5dSRadu Pirea (NXP OSS) #define PTP_ENABLE BIT(3) 149514def5dSRadu Pirea (NXP OSS) 150514def5dSRadu Pirea (NXP OSS) #define VEND1_PORT_PTP_CONTROL 0x9000 151514def5dSRadu Pirea (NXP OSS) #define PORT_PTP_CONTROL_BYPASS BIT(11) 152514def5dSRadu Pirea (NXP OSS) 153514def5dSRadu Pirea (NXP OSS) #define VEND1_PTP_CLK_PERIOD 0x1104 154514def5dSRadu Pirea (NXP OSS) #define PTP_CLK_PERIOD_100BT1 15ULL 155514def5dSRadu Pirea (NXP OSS) 156514def5dSRadu Pirea (NXP OSS) #define VEND1_EVENT_MSG_FILT 0x1148 157514def5dSRadu Pirea (NXP OSS) #define EVENT_MSG_FILT_ALL 0x0F 158514def5dSRadu Pirea (NXP OSS) #define EVENT_MSG_FILT_NONE 0x00 159514def5dSRadu Pirea (NXP OSS) 160514def5dSRadu Pirea (NXP OSS) #define VEND1_TX_PIPE_DLY_NS 0x1149 161514def5dSRadu Pirea (NXP OSS) #define VEND1_TX_PIPEDLY_SUBNS 0x114A 162514def5dSRadu Pirea (NXP OSS) #define VEND1_RX_PIPE_DLY_NS 0x114B 163514def5dSRadu Pirea (NXP OSS) #define VEND1_RX_PIPEDLY_SUBNS 0x114C 164514def5dSRadu Pirea (NXP OSS) 165b050f2f1SRadu Pirea (NXP OSS) #define RGMII_PERIOD_PS 8000U 166b050f2f1SRadu Pirea (NXP OSS) #define PS_PER_DEGREE div_u64(RGMII_PERIOD_PS, 360) 167b050f2f1SRadu Pirea (NXP OSS) #define MIN_ID_PS 1644U 168b050f2f1SRadu Pirea (NXP OSS) #define MAX_ID_PS 2260U 169b050f2f1SRadu Pirea (NXP OSS) #define DEFAULT_ID_PS 2000U 170b050f2f1SRadu Pirea (NXP OSS) 171514def5dSRadu Pirea (NXP OSS) #define PPM_TO_SUBNS_INC(ppb) div_u64(GENMASK(31, 0) * (ppb) * \ 172514def5dSRadu Pirea (NXP OSS) PTP_CLK_PERIOD_100BT1, NSEC_PER_SEC) 173514def5dSRadu Pirea (NXP OSS) 174514def5dSRadu Pirea (NXP OSS) #define NXP_C45_SKB_CB(skb) ((struct nxp_c45_skb_cb *)(skb)->cb) 175514def5dSRadu Pirea (NXP OSS) 176514def5dSRadu Pirea (NXP OSS) struct nxp_c45_skb_cb { 177514def5dSRadu Pirea (NXP OSS) struct ptp_header *header; 178514def5dSRadu Pirea (NXP OSS) unsigned int type; 179514def5dSRadu Pirea (NXP OSS) }; 180514def5dSRadu Pirea (NXP OSS) 181514def5dSRadu Pirea (NXP OSS) struct nxp_c45_hwts { 182514def5dSRadu Pirea (NXP OSS) u32 nsec; 183514def5dSRadu Pirea (NXP OSS) u32 sec; 184514def5dSRadu Pirea (NXP OSS) u8 domain_number; 185514def5dSRadu Pirea (NXP OSS) u16 sequence_id; 186514def5dSRadu Pirea (NXP OSS) u8 msg_type; 187514def5dSRadu Pirea (NXP OSS) }; 188514def5dSRadu Pirea (NXP OSS) 189b050f2f1SRadu Pirea (NXP OSS) struct nxp_c45_phy { 190514def5dSRadu Pirea (NXP OSS) struct phy_device *phydev; 191514def5dSRadu Pirea (NXP OSS) struct mii_timestamper mii_ts; 192514def5dSRadu Pirea (NXP OSS) struct ptp_clock *ptp_clock; 193514def5dSRadu Pirea (NXP OSS) struct ptp_clock_info caps; 194514def5dSRadu Pirea (NXP OSS) struct sk_buff_head tx_queue; 195514def5dSRadu Pirea (NXP OSS) struct sk_buff_head rx_queue; 196514def5dSRadu Pirea (NXP OSS) /* used to access the PTP registers atomic */ 197514def5dSRadu Pirea (NXP OSS) struct mutex ptp_lock; 198514def5dSRadu Pirea (NXP OSS) int hwts_tx; 199514def5dSRadu Pirea (NXP OSS) int hwts_rx; 200b050f2f1SRadu Pirea (NXP OSS) u32 tx_delay; 201b050f2f1SRadu Pirea (NXP OSS) u32 rx_delay; 202b050f2f1SRadu Pirea (NXP OSS) }; 203b050f2f1SRadu Pirea (NXP OSS) 204b050f2f1SRadu Pirea (NXP OSS) struct nxp_c45_phy_stats { 205b050f2f1SRadu Pirea (NXP OSS) const char *name; 206b050f2f1SRadu Pirea (NXP OSS) u8 mmd; 207b050f2f1SRadu Pirea (NXP OSS) u16 reg; 208b050f2f1SRadu Pirea (NXP OSS) u8 off; 209b050f2f1SRadu Pirea (NXP OSS) u16 mask; 210b050f2f1SRadu Pirea (NXP OSS) }; 211b050f2f1SRadu Pirea (NXP OSS) 212514def5dSRadu Pirea (NXP OSS) static bool nxp_c45_poll_txts(struct phy_device *phydev) 213514def5dSRadu Pirea (NXP OSS) { 214514def5dSRadu Pirea (NXP OSS) return phydev->irq <= 0; 215514def5dSRadu Pirea (NXP OSS) } 216514def5dSRadu Pirea (NXP OSS) 217514def5dSRadu Pirea (NXP OSS) static int _nxp_c45_ptp_gettimex64(struct ptp_clock_info *ptp, 218514def5dSRadu Pirea (NXP OSS) struct timespec64 *ts, 219514def5dSRadu Pirea (NXP OSS) struct ptp_system_timestamp *sts) 220514def5dSRadu Pirea (NXP OSS) { 221514def5dSRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps); 222514def5dSRadu Pirea (NXP OSS) 223514def5dSRadu Pirea (NXP OSS) phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_LOAD_CTRL, 224514def5dSRadu Pirea (NXP OSS) READ_LTC); 225514def5dSRadu Pirea (NXP OSS) ts->tv_nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, 226514def5dSRadu Pirea (NXP OSS) VEND1_LTC_RD_NSEC_0); 227514def5dSRadu Pirea (NXP OSS) ts->tv_nsec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, 228514def5dSRadu Pirea (NXP OSS) VEND1_LTC_RD_NSEC_1) << 16; 229514def5dSRadu Pirea (NXP OSS) ts->tv_sec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, 230514def5dSRadu Pirea (NXP OSS) VEND1_LTC_RD_SEC_0); 231514def5dSRadu Pirea (NXP OSS) ts->tv_sec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, 232514def5dSRadu Pirea (NXP OSS) VEND1_LTC_RD_SEC_1) << 16; 233514def5dSRadu Pirea (NXP OSS) 234514def5dSRadu Pirea (NXP OSS) return 0; 235514def5dSRadu Pirea (NXP OSS) } 236514def5dSRadu Pirea (NXP OSS) 237514def5dSRadu Pirea (NXP OSS) static int nxp_c45_ptp_gettimex64(struct ptp_clock_info *ptp, 238514def5dSRadu Pirea (NXP OSS) struct timespec64 *ts, 239514def5dSRadu Pirea (NXP OSS) struct ptp_system_timestamp *sts) 240514def5dSRadu Pirea (NXP OSS) { 241514def5dSRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps); 242514def5dSRadu Pirea (NXP OSS) 243514def5dSRadu Pirea (NXP OSS) mutex_lock(&priv->ptp_lock); 244514def5dSRadu Pirea (NXP OSS) _nxp_c45_ptp_gettimex64(ptp, ts, sts); 245514def5dSRadu Pirea (NXP OSS) mutex_unlock(&priv->ptp_lock); 246514def5dSRadu Pirea (NXP OSS) 247514def5dSRadu Pirea (NXP OSS) return 0; 248514def5dSRadu Pirea (NXP OSS) } 249514def5dSRadu Pirea (NXP OSS) 250514def5dSRadu Pirea (NXP OSS) static int _nxp_c45_ptp_settime64(struct ptp_clock_info *ptp, 251514def5dSRadu Pirea (NXP OSS) const struct timespec64 *ts) 252514def5dSRadu Pirea (NXP OSS) { 253514def5dSRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps); 254514def5dSRadu Pirea (NXP OSS) 255514def5dSRadu Pirea (NXP OSS) phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_NSEC_0, 256514def5dSRadu Pirea (NXP OSS) ts->tv_nsec); 257514def5dSRadu Pirea (NXP OSS) phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_NSEC_1, 258514def5dSRadu Pirea (NXP OSS) ts->tv_nsec >> 16); 259514def5dSRadu Pirea (NXP OSS) phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_SEC_0, 260514def5dSRadu Pirea (NXP OSS) ts->tv_sec); 261514def5dSRadu Pirea (NXP OSS) phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_SEC_1, 262514def5dSRadu Pirea (NXP OSS) ts->tv_sec >> 16); 263514def5dSRadu Pirea (NXP OSS) phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_LOAD_CTRL, 264514def5dSRadu Pirea (NXP OSS) LOAD_LTC); 265514def5dSRadu Pirea (NXP OSS) 266514def5dSRadu Pirea (NXP OSS) return 0; 267514def5dSRadu Pirea (NXP OSS) } 268514def5dSRadu Pirea (NXP OSS) 269514def5dSRadu Pirea (NXP OSS) static int nxp_c45_ptp_settime64(struct ptp_clock_info *ptp, 270514def5dSRadu Pirea (NXP OSS) const struct timespec64 *ts) 271514def5dSRadu Pirea (NXP OSS) { 272514def5dSRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps); 273514def5dSRadu Pirea (NXP OSS) 274514def5dSRadu Pirea (NXP OSS) mutex_lock(&priv->ptp_lock); 275514def5dSRadu Pirea (NXP OSS) _nxp_c45_ptp_settime64(ptp, ts); 276514def5dSRadu Pirea (NXP OSS) mutex_unlock(&priv->ptp_lock); 277514def5dSRadu Pirea (NXP OSS) 278514def5dSRadu Pirea (NXP OSS) return 0; 279514def5dSRadu Pirea (NXP OSS) } 280514def5dSRadu Pirea (NXP OSS) 281514def5dSRadu Pirea (NXP OSS) static int nxp_c45_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) 282514def5dSRadu Pirea (NXP OSS) { 283514def5dSRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps); 284514def5dSRadu Pirea (NXP OSS) s32 ppb = scaled_ppm_to_ppb(scaled_ppm); 285514def5dSRadu Pirea (NXP OSS) u64 subns_inc_val; 286514def5dSRadu Pirea (NXP OSS) bool inc; 287514def5dSRadu Pirea (NXP OSS) 288514def5dSRadu Pirea (NXP OSS) mutex_lock(&priv->ptp_lock); 289514def5dSRadu Pirea (NXP OSS) inc = ppb >= 0; 290514def5dSRadu Pirea (NXP OSS) ppb = abs(ppb); 291514def5dSRadu Pirea (NXP OSS) 292514def5dSRadu Pirea (NXP OSS) subns_inc_val = PPM_TO_SUBNS_INC(ppb); 293514def5dSRadu Pirea (NXP OSS) 294514def5dSRadu Pirea (NXP OSS) phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_RATE_ADJ_SUBNS_0, 295514def5dSRadu Pirea (NXP OSS) subns_inc_val); 296514def5dSRadu Pirea (NXP OSS) subns_inc_val >>= 16; 297514def5dSRadu Pirea (NXP OSS) subns_inc_val |= CLK_RATE_ADJ_LD; 298514def5dSRadu Pirea (NXP OSS) if (inc) 299514def5dSRadu Pirea (NXP OSS) subns_inc_val |= CLK_RATE_ADJ_DIR; 300514def5dSRadu Pirea (NXP OSS) 301514def5dSRadu Pirea (NXP OSS) phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_RATE_ADJ_SUBNS_1, 302514def5dSRadu Pirea (NXP OSS) subns_inc_val); 303514def5dSRadu Pirea (NXP OSS) mutex_unlock(&priv->ptp_lock); 304514def5dSRadu Pirea (NXP OSS) 305514def5dSRadu Pirea (NXP OSS) return 0; 306514def5dSRadu Pirea (NXP OSS) } 307514def5dSRadu Pirea (NXP OSS) 308514def5dSRadu Pirea (NXP OSS) static int nxp_c45_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) 309514def5dSRadu Pirea (NXP OSS) { 310514def5dSRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps); 311514def5dSRadu Pirea (NXP OSS) struct timespec64 now, then; 312514def5dSRadu Pirea (NXP OSS) 313514def5dSRadu Pirea (NXP OSS) mutex_lock(&priv->ptp_lock); 314514def5dSRadu Pirea (NXP OSS) then = ns_to_timespec64(delta); 315514def5dSRadu Pirea (NXP OSS) _nxp_c45_ptp_gettimex64(ptp, &now, NULL); 316514def5dSRadu Pirea (NXP OSS) now = timespec64_add(now, then); 317514def5dSRadu Pirea (NXP OSS) _nxp_c45_ptp_settime64(ptp, &now); 318514def5dSRadu Pirea (NXP OSS) mutex_unlock(&priv->ptp_lock); 319514def5dSRadu Pirea (NXP OSS) 320514def5dSRadu Pirea (NXP OSS) return 0; 321514def5dSRadu Pirea (NXP OSS) } 322514def5dSRadu Pirea (NXP OSS) 323514def5dSRadu Pirea (NXP OSS) static void nxp_c45_reconstruct_ts(struct timespec64 *ts, 324514def5dSRadu Pirea (NXP OSS) struct nxp_c45_hwts *hwts) 325514def5dSRadu Pirea (NXP OSS) { 326514def5dSRadu Pirea (NXP OSS) ts->tv_nsec = hwts->nsec; 327514def5dSRadu Pirea (NXP OSS) if ((ts->tv_sec & TS_SEC_MASK) < (hwts->sec & TS_SEC_MASK)) 328661fef56SVladimir Oltean ts->tv_sec -= TS_SEC_MASK + 1; 329514def5dSRadu Pirea (NXP OSS) ts->tv_sec &= ~TS_SEC_MASK; 330514def5dSRadu Pirea (NXP OSS) ts->tv_sec |= hwts->sec & TS_SEC_MASK; 331514def5dSRadu Pirea (NXP OSS) } 332514def5dSRadu Pirea (NXP OSS) 333514def5dSRadu Pirea (NXP OSS) static bool nxp_c45_match_ts(struct ptp_header *header, 334514def5dSRadu Pirea (NXP OSS) struct nxp_c45_hwts *hwts, 335514def5dSRadu Pirea (NXP OSS) unsigned int type) 336514def5dSRadu Pirea (NXP OSS) { 337514def5dSRadu Pirea (NXP OSS) return ntohs(header->sequence_id) == hwts->sequence_id && 338514def5dSRadu Pirea (NXP OSS) ptp_get_msgtype(header, type) == hwts->msg_type && 339514def5dSRadu Pirea (NXP OSS) header->domain_number == hwts->domain_number; 340514def5dSRadu Pirea (NXP OSS) } 341514def5dSRadu Pirea (NXP OSS) 342514def5dSRadu Pirea (NXP OSS) static bool nxp_c45_get_hwtxts(struct nxp_c45_phy *priv, 343514def5dSRadu Pirea (NXP OSS) struct nxp_c45_hwts *hwts) 344514def5dSRadu Pirea (NXP OSS) { 345514def5dSRadu Pirea (NXP OSS) bool valid; 346514def5dSRadu Pirea (NXP OSS) u16 reg; 347514def5dSRadu Pirea (NXP OSS) 348514def5dSRadu Pirea (NXP OSS) mutex_lock(&priv->ptp_lock); 349514def5dSRadu Pirea (NXP OSS) phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_CTRL, 350514def5dSRadu Pirea (NXP OSS) RING_DONE); 351514def5dSRadu Pirea (NXP OSS) reg = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_DATA_0); 352514def5dSRadu Pirea (NXP OSS) valid = !!(reg & RING_DATA_0_TS_VALID); 353514def5dSRadu Pirea (NXP OSS) if (!valid) 354514def5dSRadu Pirea (NXP OSS) goto nxp_c45_get_hwtxts_out; 355514def5dSRadu Pirea (NXP OSS) 356514def5dSRadu Pirea (NXP OSS) hwts->domain_number = reg; 357514def5dSRadu Pirea (NXP OSS) hwts->msg_type = (reg & RING_DATA_0_MSG_TYPE) >> 8; 358514def5dSRadu Pirea (NXP OSS) hwts->sec = (reg & RING_DATA_0_SEC_4_2) >> 10; 359514def5dSRadu Pirea (NXP OSS) hwts->sequence_id = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, 360514def5dSRadu Pirea (NXP OSS) VEND1_EGR_RING_DATA_1_SEQ_ID); 361514def5dSRadu Pirea (NXP OSS) hwts->nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, 362514def5dSRadu Pirea (NXP OSS) VEND1_EGR_RING_DATA_2_NSEC_15_0); 363514def5dSRadu Pirea (NXP OSS) reg = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_DATA_3); 364514def5dSRadu Pirea (NXP OSS) hwts->nsec |= (reg & RING_DATA_3_NSEC_29_16) << 16; 365514def5dSRadu Pirea (NXP OSS) hwts->sec |= (reg & RING_DATA_3_SEC_1_0) >> 14; 366514def5dSRadu Pirea (NXP OSS) 367514def5dSRadu Pirea (NXP OSS) nxp_c45_get_hwtxts_out: 368514def5dSRadu Pirea (NXP OSS) mutex_unlock(&priv->ptp_lock); 369514def5dSRadu Pirea (NXP OSS) return valid; 370514def5dSRadu Pirea (NXP OSS) } 371514def5dSRadu Pirea (NXP OSS) 372514def5dSRadu Pirea (NXP OSS) static void nxp_c45_process_txts(struct nxp_c45_phy *priv, 373514def5dSRadu Pirea (NXP OSS) struct nxp_c45_hwts *txts) 374514def5dSRadu Pirea (NXP OSS) { 375514def5dSRadu Pirea (NXP OSS) struct sk_buff *skb, *tmp, *skb_match = NULL; 376514def5dSRadu Pirea (NXP OSS) struct skb_shared_hwtstamps shhwtstamps; 377514def5dSRadu Pirea (NXP OSS) struct timespec64 ts; 378514def5dSRadu Pirea (NXP OSS) unsigned long flags; 379514def5dSRadu Pirea (NXP OSS) bool ts_match; 380514def5dSRadu Pirea (NXP OSS) s64 ts_ns; 381514def5dSRadu Pirea (NXP OSS) 382514def5dSRadu Pirea (NXP OSS) spin_lock_irqsave(&priv->tx_queue.lock, flags); 383514def5dSRadu Pirea (NXP OSS) skb_queue_walk_safe(&priv->tx_queue, skb, tmp) { 384514def5dSRadu Pirea (NXP OSS) ts_match = nxp_c45_match_ts(NXP_C45_SKB_CB(skb)->header, txts, 385514def5dSRadu Pirea (NXP OSS) NXP_C45_SKB_CB(skb)->type); 386514def5dSRadu Pirea (NXP OSS) if (!ts_match) 387514def5dSRadu Pirea (NXP OSS) continue; 388514def5dSRadu Pirea (NXP OSS) skb_match = skb; 389514def5dSRadu Pirea (NXP OSS) __skb_unlink(skb, &priv->tx_queue); 390514def5dSRadu Pirea (NXP OSS) break; 391514def5dSRadu Pirea (NXP OSS) } 392514def5dSRadu Pirea (NXP OSS) spin_unlock_irqrestore(&priv->tx_queue.lock, flags); 393514def5dSRadu Pirea (NXP OSS) 394514def5dSRadu Pirea (NXP OSS) if (skb_match) { 395514def5dSRadu Pirea (NXP OSS) nxp_c45_ptp_gettimex64(&priv->caps, &ts, NULL); 396514def5dSRadu Pirea (NXP OSS) nxp_c45_reconstruct_ts(&ts, txts); 397514def5dSRadu Pirea (NXP OSS) memset(&shhwtstamps, 0, sizeof(shhwtstamps)); 398514def5dSRadu Pirea (NXP OSS) ts_ns = timespec64_to_ns(&ts); 399514def5dSRadu Pirea (NXP OSS) shhwtstamps.hwtstamp = ns_to_ktime(ts_ns); 400514def5dSRadu Pirea (NXP OSS) skb_complete_tx_timestamp(skb_match, &shhwtstamps); 401514def5dSRadu Pirea (NXP OSS) } else { 402514def5dSRadu Pirea (NXP OSS) phydev_warn(priv->phydev, 403514def5dSRadu Pirea (NXP OSS) "the tx timestamp doesn't match with any skb\n"); 404514def5dSRadu Pirea (NXP OSS) } 405514def5dSRadu Pirea (NXP OSS) } 406514def5dSRadu Pirea (NXP OSS) 407514def5dSRadu Pirea (NXP OSS) static long nxp_c45_do_aux_work(struct ptp_clock_info *ptp) 408514def5dSRadu Pirea (NXP OSS) { 409514def5dSRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps); 410514def5dSRadu Pirea (NXP OSS) bool poll_txts = nxp_c45_poll_txts(priv->phydev); 411514def5dSRadu Pirea (NXP OSS) struct skb_shared_hwtstamps *shhwtstamps_rx; 412514def5dSRadu Pirea (NXP OSS) struct nxp_c45_hwts hwts; 413514def5dSRadu Pirea (NXP OSS) bool reschedule = false; 414514def5dSRadu Pirea (NXP OSS) struct timespec64 ts; 415514def5dSRadu Pirea (NXP OSS) struct sk_buff *skb; 416514def5dSRadu Pirea (NXP OSS) bool txts_valid; 417514def5dSRadu Pirea (NXP OSS) u32 ts_raw; 418514def5dSRadu Pirea (NXP OSS) 419514def5dSRadu Pirea (NXP OSS) while (!skb_queue_empty_lockless(&priv->tx_queue) && poll_txts) { 420514def5dSRadu Pirea (NXP OSS) txts_valid = nxp_c45_get_hwtxts(priv, &hwts); 421514def5dSRadu Pirea (NXP OSS) if (unlikely(!txts_valid)) { 422514def5dSRadu Pirea (NXP OSS) /* Still more skbs in the queue */ 423514def5dSRadu Pirea (NXP OSS) reschedule = true; 424514def5dSRadu Pirea (NXP OSS) break; 425514def5dSRadu Pirea (NXP OSS) } 426514def5dSRadu Pirea (NXP OSS) 427514def5dSRadu Pirea (NXP OSS) nxp_c45_process_txts(priv, &hwts); 428514def5dSRadu Pirea (NXP OSS) } 429514def5dSRadu Pirea (NXP OSS) 430514def5dSRadu Pirea (NXP OSS) while ((skb = skb_dequeue(&priv->rx_queue)) != NULL) { 431109258edSVladimir Oltean nxp_c45_ptp_gettimex64(&priv->caps, &ts, NULL); 432514def5dSRadu Pirea (NXP OSS) ts_raw = __be32_to_cpu(NXP_C45_SKB_CB(skb)->header->reserved2); 433514def5dSRadu Pirea (NXP OSS) hwts.sec = ts_raw >> 30; 434514def5dSRadu Pirea (NXP OSS) hwts.nsec = ts_raw & GENMASK(29, 0); 435514def5dSRadu Pirea (NXP OSS) nxp_c45_reconstruct_ts(&ts, &hwts); 436514def5dSRadu Pirea (NXP OSS) shhwtstamps_rx = skb_hwtstamps(skb); 437514def5dSRadu Pirea (NXP OSS) shhwtstamps_rx->hwtstamp = ns_to_ktime(timespec64_to_ns(&ts)); 438514def5dSRadu Pirea (NXP OSS) NXP_C45_SKB_CB(skb)->header->reserved2 = 0; 439514def5dSRadu Pirea (NXP OSS) netif_rx_ni(skb); 440514def5dSRadu Pirea (NXP OSS) } 441514def5dSRadu Pirea (NXP OSS) 442514def5dSRadu Pirea (NXP OSS) return reschedule ? 1 : -1; 443514def5dSRadu Pirea (NXP OSS) } 444514def5dSRadu Pirea (NXP OSS) 445514def5dSRadu Pirea (NXP OSS) static int nxp_c45_init_ptp_clock(struct nxp_c45_phy *priv) 446514def5dSRadu Pirea (NXP OSS) { 447514def5dSRadu Pirea (NXP OSS) priv->caps = (struct ptp_clock_info) { 448514def5dSRadu Pirea (NXP OSS) .owner = THIS_MODULE, 449514def5dSRadu Pirea (NXP OSS) .name = "NXP C45 PHC", 450514def5dSRadu Pirea (NXP OSS) .max_adj = 16666666, 451514def5dSRadu Pirea (NXP OSS) .adjfine = nxp_c45_ptp_adjfine, 452514def5dSRadu Pirea (NXP OSS) .adjtime = nxp_c45_ptp_adjtime, 453514def5dSRadu Pirea (NXP OSS) .gettimex64 = nxp_c45_ptp_gettimex64, 454514def5dSRadu Pirea (NXP OSS) .settime64 = nxp_c45_ptp_settime64, 455514def5dSRadu Pirea (NXP OSS) .do_aux_work = nxp_c45_do_aux_work, 456514def5dSRadu Pirea (NXP OSS) }; 457514def5dSRadu Pirea (NXP OSS) 458514def5dSRadu Pirea (NXP OSS) priv->ptp_clock = ptp_clock_register(&priv->caps, 459514def5dSRadu Pirea (NXP OSS) &priv->phydev->mdio.dev); 460514def5dSRadu Pirea (NXP OSS) 461514def5dSRadu Pirea (NXP OSS) if (IS_ERR(priv->ptp_clock)) 462514def5dSRadu Pirea (NXP OSS) return PTR_ERR(priv->ptp_clock); 463514def5dSRadu Pirea (NXP OSS) 464514def5dSRadu Pirea (NXP OSS) if (!priv->ptp_clock) 465514def5dSRadu Pirea (NXP OSS) return -ENOMEM; 466514def5dSRadu Pirea (NXP OSS) 467514def5dSRadu Pirea (NXP OSS) return 0; 468514def5dSRadu Pirea (NXP OSS) } 469514def5dSRadu Pirea (NXP OSS) 470514def5dSRadu Pirea (NXP OSS) static void nxp_c45_txtstamp(struct mii_timestamper *mii_ts, 471514def5dSRadu Pirea (NXP OSS) struct sk_buff *skb, int type) 472514def5dSRadu Pirea (NXP OSS) { 473514def5dSRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy, 474514def5dSRadu Pirea (NXP OSS) mii_ts); 475514def5dSRadu Pirea (NXP OSS) 476514def5dSRadu Pirea (NXP OSS) switch (priv->hwts_tx) { 477514def5dSRadu Pirea (NXP OSS) case HWTSTAMP_TX_ON: 478514def5dSRadu Pirea (NXP OSS) NXP_C45_SKB_CB(skb)->type = type; 479514def5dSRadu Pirea (NXP OSS) NXP_C45_SKB_CB(skb)->header = ptp_parse_header(skb, type); 480514def5dSRadu Pirea (NXP OSS) skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 481514def5dSRadu Pirea (NXP OSS) skb_queue_tail(&priv->tx_queue, skb); 482514def5dSRadu Pirea (NXP OSS) if (nxp_c45_poll_txts(priv->phydev)) 483514def5dSRadu Pirea (NXP OSS) ptp_schedule_worker(priv->ptp_clock, 0); 484514def5dSRadu Pirea (NXP OSS) break; 485514def5dSRadu Pirea (NXP OSS) case HWTSTAMP_TX_OFF: 486514def5dSRadu Pirea (NXP OSS) default: 487514def5dSRadu Pirea (NXP OSS) kfree_skb(skb); 488514def5dSRadu Pirea (NXP OSS) break; 489514def5dSRadu Pirea (NXP OSS) } 490514def5dSRadu Pirea (NXP OSS) } 491514def5dSRadu Pirea (NXP OSS) 492514def5dSRadu Pirea (NXP OSS) static bool nxp_c45_rxtstamp(struct mii_timestamper *mii_ts, 493514def5dSRadu Pirea (NXP OSS) struct sk_buff *skb, int type) 494514def5dSRadu Pirea (NXP OSS) { 495514def5dSRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy, 496514def5dSRadu Pirea (NXP OSS) mii_ts); 497514def5dSRadu Pirea (NXP OSS) struct ptp_header *header = ptp_parse_header(skb, type); 498514def5dSRadu Pirea (NXP OSS) 499514def5dSRadu Pirea (NXP OSS) if (!header) 500514def5dSRadu Pirea (NXP OSS) return false; 501514def5dSRadu Pirea (NXP OSS) 502514def5dSRadu Pirea (NXP OSS) if (!priv->hwts_rx) 503514def5dSRadu Pirea (NXP OSS) return false; 504514def5dSRadu Pirea (NXP OSS) 505514def5dSRadu Pirea (NXP OSS) NXP_C45_SKB_CB(skb)->header = header; 506514def5dSRadu Pirea (NXP OSS) skb_queue_tail(&priv->rx_queue, skb); 507514def5dSRadu Pirea (NXP OSS) ptp_schedule_worker(priv->ptp_clock, 0); 508514def5dSRadu Pirea (NXP OSS) 509514def5dSRadu Pirea (NXP OSS) return true; 510514def5dSRadu Pirea (NXP OSS) } 511514def5dSRadu Pirea (NXP OSS) 512514def5dSRadu Pirea (NXP OSS) static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts, 513514def5dSRadu Pirea (NXP OSS) struct ifreq *ifreq) 514514def5dSRadu Pirea (NXP OSS) { 515514def5dSRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy, 516514def5dSRadu Pirea (NXP OSS) mii_ts); 517514def5dSRadu Pirea (NXP OSS) struct phy_device *phydev = priv->phydev; 518514def5dSRadu Pirea (NXP OSS) struct hwtstamp_config cfg; 519514def5dSRadu Pirea (NXP OSS) 520514def5dSRadu Pirea (NXP OSS) if (copy_from_user(&cfg, ifreq->ifr_data, sizeof(cfg))) 521514def5dSRadu Pirea (NXP OSS) return -EFAULT; 522514def5dSRadu Pirea (NXP OSS) 523514def5dSRadu Pirea (NXP OSS) if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ON) 524514def5dSRadu Pirea (NXP OSS) return -ERANGE; 525514def5dSRadu Pirea (NXP OSS) 526514def5dSRadu Pirea (NXP OSS) priv->hwts_tx = cfg.tx_type; 527514def5dSRadu Pirea (NXP OSS) 528514def5dSRadu Pirea (NXP OSS) switch (cfg.rx_filter) { 529514def5dSRadu Pirea (NXP OSS) case HWTSTAMP_FILTER_NONE: 530514def5dSRadu Pirea (NXP OSS) priv->hwts_rx = 0; 531514def5dSRadu Pirea (NXP OSS) break; 532514def5dSRadu Pirea (NXP OSS) case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 533514def5dSRadu Pirea (NXP OSS) case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 534514def5dSRadu Pirea (NXP OSS) case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 535514def5dSRadu Pirea (NXP OSS) priv->hwts_rx = 1; 536514def5dSRadu Pirea (NXP OSS) cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; 537514def5dSRadu Pirea (NXP OSS) break; 538514def5dSRadu Pirea (NXP OSS) default: 539514def5dSRadu Pirea (NXP OSS) return -ERANGE; 540514def5dSRadu Pirea (NXP OSS) } 541514def5dSRadu Pirea (NXP OSS) 542514def5dSRadu Pirea (NXP OSS) if (priv->hwts_rx || priv->hwts_tx) { 543514def5dSRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_EVENT_MSG_FILT, 544514def5dSRadu Pirea (NXP OSS) EVENT_MSG_FILT_ALL); 545514def5dSRadu Pirea (NXP OSS) phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 546514def5dSRadu Pirea (NXP OSS) VEND1_PORT_PTP_CONTROL, 547514def5dSRadu Pirea (NXP OSS) PORT_PTP_CONTROL_BYPASS); 548514def5dSRadu Pirea (NXP OSS) } else { 549514def5dSRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_EVENT_MSG_FILT, 550514def5dSRadu Pirea (NXP OSS) EVENT_MSG_FILT_NONE); 551514def5dSRadu Pirea (NXP OSS) phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_PTP_CONTROL, 552514def5dSRadu Pirea (NXP OSS) PORT_PTP_CONTROL_BYPASS); 553514def5dSRadu Pirea (NXP OSS) } 554514def5dSRadu Pirea (NXP OSS) 555514def5dSRadu Pirea (NXP OSS) if (nxp_c45_poll_txts(priv->phydev)) 556514def5dSRadu Pirea (NXP OSS) goto nxp_c45_no_ptp_irq; 557514def5dSRadu Pirea (NXP OSS) 558514def5dSRadu Pirea (NXP OSS) if (priv->hwts_tx) 559514def5dSRadu Pirea (NXP OSS) phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, 560514def5dSRadu Pirea (NXP OSS) VEND1_PTP_IRQ_EN, PTP_IRQ_EGR_TS); 561514def5dSRadu Pirea (NXP OSS) else 562514def5dSRadu Pirea (NXP OSS) phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 563514def5dSRadu Pirea (NXP OSS) VEND1_PTP_IRQ_EN, PTP_IRQ_EGR_TS); 564514def5dSRadu Pirea (NXP OSS) 565514def5dSRadu Pirea (NXP OSS) nxp_c45_no_ptp_irq: 566514def5dSRadu Pirea (NXP OSS) return copy_to_user(ifreq->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; 567514def5dSRadu Pirea (NXP OSS) } 568514def5dSRadu Pirea (NXP OSS) 569514def5dSRadu Pirea (NXP OSS) static int nxp_c45_ts_info(struct mii_timestamper *mii_ts, 570514def5dSRadu Pirea (NXP OSS) struct ethtool_ts_info *ts_info) 571514def5dSRadu Pirea (NXP OSS) { 572514def5dSRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy, 573514def5dSRadu Pirea (NXP OSS) mii_ts); 574514def5dSRadu Pirea (NXP OSS) 575514def5dSRadu Pirea (NXP OSS) ts_info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | 576514def5dSRadu Pirea (NXP OSS) SOF_TIMESTAMPING_RX_HARDWARE | 577514def5dSRadu Pirea (NXP OSS) SOF_TIMESTAMPING_RAW_HARDWARE; 578514def5dSRadu Pirea (NXP OSS) ts_info->phc_index = ptp_clock_index(priv->ptp_clock); 579514def5dSRadu Pirea (NXP OSS) ts_info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); 580514def5dSRadu Pirea (NXP OSS) ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 581514def5dSRadu Pirea (NXP OSS) (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | 582514def5dSRadu Pirea (NXP OSS) (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | 583514def5dSRadu Pirea (NXP OSS) (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT); 584514def5dSRadu Pirea (NXP OSS) 585514def5dSRadu Pirea (NXP OSS) return 0; 586514def5dSRadu Pirea (NXP OSS) } 587514def5dSRadu Pirea (NXP OSS) 588b050f2f1SRadu Pirea (NXP OSS) static const struct nxp_c45_phy_stats nxp_c45_hw_stats[] = { 589b050f2f1SRadu Pirea (NXP OSS) { "phy_symbol_error_cnt", MDIO_MMD_VEND1, 590b050f2f1SRadu Pirea (NXP OSS) VEND1_SYMBOL_ERROR_COUNTER, 0, GENMASK(15, 0) }, 591b050f2f1SRadu Pirea (NXP OSS) { "phy_link_status_drop_cnt", MDIO_MMD_VEND1, 592b050f2f1SRadu Pirea (NXP OSS) VEND1_LINK_DROP_COUNTER, 8, GENMASK(13, 8) }, 593b050f2f1SRadu Pirea (NXP OSS) { "phy_link_availability_drop_cnt", MDIO_MMD_VEND1, 594b050f2f1SRadu Pirea (NXP OSS) VEND1_LINK_DROP_COUNTER, 0, GENMASK(5, 0) }, 595b050f2f1SRadu Pirea (NXP OSS) { "phy_link_loss_cnt", MDIO_MMD_VEND1, 596b050f2f1SRadu Pirea (NXP OSS) VEND1_LINK_LOSSES_AND_FAILURES, 10, GENMASK(15, 10) }, 597b050f2f1SRadu Pirea (NXP OSS) { "phy_link_failure_cnt", MDIO_MMD_VEND1, 598b050f2f1SRadu Pirea (NXP OSS) VEND1_LINK_LOSSES_AND_FAILURES, 0, GENMASK(9, 0) }, 599b050f2f1SRadu Pirea (NXP OSS) { "r_good_frame_cnt", MDIO_MMD_VEND1, 600b050f2f1SRadu Pirea (NXP OSS) VEND1_R_GOOD_FRAME_CNT, 0, GENMASK(15, 0) }, 601b050f2f1SRadu Pirea (NXP OSS) { "r_bad_frame_cnt", MDIO_MMD_VEND1, 602b050f2f1SRadu Pirea (NXP OSS) VEND1_R_BAD_FRAME_CNT, 0, GENMASK(15, 0) }, 603b050f2f1SRadu Pirea (NXP OSS) { "r_rxer_frame_cnt", MDIO_MMD_VEND1, 604b050f2f1SRadu Pirea (NXP OSS) VEND1_R_RXER_FRAME_CNT, 0, GENMASK(15, 0) }, 605b050f2f1SRadu Pirea (NXP OSS) { "rx_preamble_count", MDIO_MMD_VEND1, 606b050f2f1SRadu Pirea (NXP OSS) VEND1_RX_PREAMBLE_COUNT, 0, GENMASK(5, 0) }, 607b050f2f1SRadu Pirea (NXP OSS) { "tx_preamble_count", MDIO_MMD_VEND1, 608b050f2f1SRadu Pirea (NXP OSS) VEND1_TX_PREAMBLE_COUNT, 0, GENMASK(5, 0) }, 609b050f2f1SRadu Pirea (NXP OSS) { "rx_ipg_length", MDIO_MMD_VEND1, 610b050f2f1SRadu Pirea (NXP OSS) VEND1_RX_IPG_LENGTH, 0, GENMASK(8, 0) }, 611b050f2f1SRadu Pirea (NXP OSS) { "tx_ipg_length", MDIO_MMD_VEND1, 612b050f2f1SRadu Pirea (NXP OSS) VEND1_TX_IPG_LENGTH, 0, GENMASK(8, 0) }, 613b050f2f1SRadu Pirea (NXP OSS) }; 614b050f2f1SRadu Pirea (NXP OSS) 615b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_get_sset_count(struct phy_device *phydev) 616b050f2f1SRadu Pirea (NXP OSS) { 617b050f2f1SRadu Pirea (NXP OSS) return ARRAY_SIZE(nxp_c45_hw_stats); 618b050f2f1SRadu Pirea (NXP OSS) } 619b050f2f1SRadu Pirea (NXP OSS) 620b050f2f1SRadu Pirea (NXP OSS) static void nxp_c45_get_strings(struct phy_device *phydev, u8 *data) 621b050f2f1SRadu Pirea (NXP OSS) { 622b050f2f1SRadu Pirea (NXP OSS) size_t i; 623b050f2f1SRadu Pirea (NXP OSS) 624b050f2f1SRadu Pirea (NXP OSS) for (i = 0; i < ARRAY_SIZE(nxp_c45_hw_stats); i++) { 625b050f2f1SRadu Pirea (NXP OSS) strncpy(data + i * ETH_GSTRING_LEN, 626b050f2f1SRadu Pirea (NXP OSS) nxp_c45_hw_stats[i].name, ETH_GSTRING_LEN); 627b050f2f1SRadu Pirea (NXP OSS) } 628b050f2f1SRadu Pirea (NXP OSS) } 629b050f2f1SRadu Pirea (NXP OSS) 630b050f2f1SRadu Pirea (NXP OSS) static void nxp_c45_get_stats(struct phy_device *phydev, 631b050f2f1SRadu Pirea (NXP OSS) struct ethtool_stats *stats, u64 *data) 632b050f2f1SRadu Pirea (NXP OSS) { 633b050f2f1SRadu Pirea (NXP OSS) size_t i; 634b050f2f1SRadu Pirea (NXP OSS) int ret; 635b050f2f1SRadu Pirea (NXP OSS) 636b050f2f1SRadu Pirea (NXP OSS) for (i = 0; i < ARRAY_SIZE(nxp_c45_hw_stats); i++) { 637b050f2f1SRadu Pirea (NXP OSS) ret = phy_read_mmd(phydev, nxp_c45_hw_stats[i].mmd, 638b050f2f1SRadu Pirea (NXP OSS) nxp_c45_hw_stats[i].reg); 639b050f2f1SRadu Pirea (NXP OSS) if (ret < 0) { 640b050f2f1SRadu Pirea (NXP OSS) data[i] = U64_MAX; 641b050f2f1SRadu Pirea (NXP OSS) } else { 642b050f2f1SRadu Pirea (NXP OSS) data[i] = ret & nxp_c45_hw_stats[i].mask; 643b050f2f1SRadu Pirea (NXP OSS) data[i] >>= nxp_c45_hw_stats[i].off; 644b050f2f1SRadu Pirea (NXP OSS) } 645b050f2f1SRadu Pirea (NXP OSS) } 646b050f2f1SRadu Pirea (NXP OSS) } 647b050f2f1SRadu Pirea (NXP OSS) 648b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_config_enable(struct phy_device *phydev) 649b050f2f1SRadu Pirea (NXP OSS) { 650b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_CONTROL, 651b050f2f1SRadu Pirea (NXP OSS) DEVICE_CONTROL_CONFIG_GLOBAL_EN | 652b050f2f1SRadu Pirea (NXP OSS) DEVICE_CONTROL_CONFIG_ALL_EN); 653b050f2f1SRadu Pirea (NXP OSS) usleep_range(400, 450); 654b050f2f1SRadu Pirea (NXP OSS) 655b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_CONTROL, 656b050f2f1SRadu Pirea (NXP OSS) PORT_CONTROL_EN); 657b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONTROL, 658b050f2f1SRadu Pirea (NXP OSS) PHY_CONFIG_EN); 659b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_INFRA_CONTROL, 660b050f2f1SRadu Pirea (NXP OSS) PORT_INFRA_CONTROL_EN); 661b050f2f1SRadu Pirea (NXP OSS) 662b050f2f1SRadu Pirea (NXP OSS) return 0; 663b050f2f1SRadu Pirea (NXP OSS) } 664b050f2f1SRadu Pirea (NXP OSS) 665b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_start_op(struct phy_device *phydev) 666b050f2f1SRadu Pirea (NXP OSS) { 667b050f2f1SRadu Pirea (NXP OSS) return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONTROL, 668b050f2f1SRadu Pirea (NXP OSS) PHY_START_OP); 669b050f2f1SRadu Pirea (NXP OSS) } 670b050f2f1SRadu Pirea (NXP OSS) 671b2f0ca00SRadu Pirea (NXP OSS) static int nxp_c45_config_intr(struct phy_device *phydev) 672b2f0ca00SRadu Pirea (NXP OSS) { 673b2f0ca00SRadu Pirea (NXP OSS) if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 674b2f0ca00SRadu Pirea (NXP OSS) return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, 675b2f0ca00SRadu Pirea (NXP OSS) VEND1_PHY_IRQ_EN, PHY_IRQ_LINK_EVENT); 676b2f0ca00SRadu Pirea (NXP OSS) else 677b2f0ca00SRadu Pirea (NXP OSS) return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 678b2f0ca00SRadu Pirea (NXP OSS) VEND1_PHY_IRQ_EN, PHY_IRQ_LINK_EVENT); 679b2f0ca00SRadu Pirea (NXP OSS) } 680b2f0ca00SRadu Pirea (NXP OSS) 681b2f0ca00SRadu Pirea (NXP OSS) static irqreturn_t nxp_c45_handle_interrupt(struct phy_device *phydev) 682b2f0ca00SRadu Pirea (NXP OSS) { 683514def5dSRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = phydev->priv; 684b2f0ca00SRadu Pirea (NXP OSS) irqreturn_t ret = IRQ_NONE; 685514def5dSRadu Pirea (NXP OSS) struct nxp_c45_hwts hwts; 686b2f0ca00SRadu Pirea (NXP OSS) int irq; 687b2f0ca00SRadu Pirea (NXP OSS) 688b2f0ca00SRadu Pirea (NXP OSS) irq = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_IRQ_STATUS); 689b2f0ca00SRadu Pirea (NXP OSS) if (irq & PHY_IRQ_LINK_EVENT) { 690b2f0ca00SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_IRQ_ACK, 691b2f0ca00SRadu Pirea (NXP OSS) PHY_IRQ_LINK_EVENT); 692b2f0ca00SRadu Pirea (NXP OSS) phy_trigger_machine(phydev); 693b2f0ca00SRadu Pirea (NXP OSS) ret = IRQ_HANDLED; 694b2f0ca00SRadu Pirea (NXP OSS) } 695b2f0ca00SRadu Pirea (NXP OSS) 696514def5dSRadu Pirea (NXP OSS) /* There is no need for ACK. 697514def5dSRadu Pirea (NXP OSS) * The irq signal will be asserted until the EGR TS FIFO will be 698514def5dSRadu Pirea (NXP OSS) * emptied. 699514def5dSRadu Pirea (NXP OSS) */ 700514def5dSRadu Pirea (NXP OSS) irq = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_IRQ_STATUS); 701514def5dSRadu Pirea (NXP OSS) if (irq & PTP_IRQ_EGR_TS) { 702514def5dSRadu Pirea (NXP OSS) while (nxp_c45_get_hwtxts(priv, &hwts)) 703514def5dSRadu Pirea (NXP OSS) nxp_c45_process_txts(priv, &hwts); 704514def5dSRadu Pirea (NXP OSS) 705514def5dSRadu Pirea (NXP OSS) ret = IRQ_HANDLED; 706514def5dSRadu Pirea (NXP OSS) } 707514def5dSRadu Pirea (NXP OSS) 708b2f0ca00SRadu Pirea (NXP OSS) return ret; 709b2f0ca00SRadu Pirea (NXP OSS) } 710b2f0ca00SRadu Pirea (NXP OSS) 711b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_soft_reset(struct phy_device *phydev) 712b050f2f1SRadu Pirea (NXP OSS) { 713b050f2f1SRadu Pirea (NXP OSS) int ret; 714b050f2f1SRadu Pirea (NXP OSS) 715b050f2f1SRadu Pirea (NXP OSS) ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_CONTROL, 716b050f2f1SRadu Pirea (NXP OSS) DEVICE_CONTROL_RESET); 717b050f2f1SRadu Pirea (NXP OSS) if (ret) 718b050f2f1SRadu Pirea (NXP OSS) return ret; 719b050f2f1SRadu Pirea (NXP OSS) 720b050f2f1SRadu Pirea (NXP OSS) return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, 721b050f2f1SRadu Pirea (NXP OSS) VEND1_DEVICE_CONTROL, ret, 722b050f2f1SRadu Pirea (NXP OSS) !(ret & DEVICE_CONTROL_RESET), 20000, 723b050f2f1SRadu Pirea (NXP OSS) 240000, false); 724b050f2f1SRadu Pirea (NXP OSS) } 725b050f2f1SRadu Pirea (NXP OSS) 726b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_cable_test_start(struct phy_device *phydev) 727b050f2f1SRadu Pirea (NXP OSS) { 728b050f2f1SRadu Pirea (NXP OSS) return phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_CABLE_TEST, 729b050f2f1SRadu Pirea (NXP OSS) CABLE_TEST_ENABLE | CABLE_TEST_START); 730b050f2f1SRadu Pirea (NXP OSS) } 731b050f2f1SRadu Pirea (NXP OSS) 732b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_cable_test_get_status(struct phy_device *phydev, 733b050f2f1SRadu Pirea (NXP OSS) bool *finished) 734b050f2f1SRadu Pirea (NXP OSS) { 735b050f2f1SRadu Pirea (NXP OSS) int ret; 736b050f2f1SRadu Pirea (NXP OSS) u8 cable_test_result; 737b050f2f1SRadu Pirea (NXP OSS) 738b050f2f1SRadu Pirea (NXP OSS) ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_CABLE_TEST); 739b050f2f1SRadu Pirea (NXP OSS) if (!(ret & CABLE_TEST_VALID)) { 740b050f2f1SRadu Pirea (NXP OSS) *finished = false; 741b050f2f1SRadu Pirea (NXP OSS) return 0; 742b050f2f1SRadu Pirea (NXP OSS) } 743b050f2f1SRadu Pirea (NXP OSS) 744b050f2f1SRadu Pirea (NXP OSS) *finished = true; 745b050f2f1SRadu Pirea (NXP OSS) cable_test_result = ret & GENMASK(2, 0); 746b050f2f1SRadu Pirea (NXP OSS) 747b050f2f1SRadu Pirea (NXP OSS) switch (cable_test_result) { 748b050f2f1SRadu Pirea (NXP OSS) case CABLE_TEST_OK: 749b050f2f1SRadu Pirea (NXP OSS) ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, 750b050f2f1SRadu Pirea (NXP OSS) ETHTOOL_A_CABLE_RESULT_CODE_OK); 751b050f2f1SRadu Pirea (NXP OSS) break; 752b050f2f1SRadu Pirea (NXP OSS) case CABLE_TEST_SHORTED: 753b050f2f1SRadu Pirea (NXP OSS) ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, 754b050f2f1SRadu Pirea (NXP OSS) ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT); 755b050f2f1SRadu Pirea (NXP OSS) break; 756b050f2f1SRadu Pirea (NXP OSS) case CABLE_TEST_OPEN: 757b050f2f1SRadu Pirea (NXP OSS) ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, 758b050f2f1SRadu Pirea (NXP OSS) ETHTOOL_A_CABLE_RESULT_CODE_OPEN); 759b050f2f1SRadu Pirea (NXP OSS) break; 760b050f2f1SRadu Pirea (NXP OSS) default: 761b050f2f1SRadu Pirea (NXP OSS) ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, 762b050f2f1SRadu Pirea (NXP OSS) ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC); 763b050f2f1SRadu Pirea (NXP OSS) } 764b050f2f1SRadu Pirea (NXP OSS) 765b050f2f1SRadu Pirea (NXP OSS) phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_CABLE_TEST, 766b050f2f1SRadu Pirea (NXP OSS) CABLE_TEST_ENABLE); 767b050f2f1SRadu Pirea (NXP OSS) 768b050f2f1SRadu Pirea (NXP OSS) return nxp_c45_start_op(phydev); 769b050f2f1SRadu Pirea (NXP OSS) } 770b050f2f1SRadu Pirea (NXP OSS) 771b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_setup_master_slave(struct phy_device *phydev) 772b050f2f1SRadu Pirea (NXP OSS) { 773b050f2f1SRadu Pirea (NXP OSS) switch (phydev->master_slave_set) { 774b050f2f1SRadu Pirea (NXP OSS) case MASTER_SLAVE_CFG_MASTER_FORCE: 775b050f2f1SRadu Pirea (NXP OSS) case MASTER_SLAVE_CFG_MASTER_PREFERRED: 776b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_B100T1_PMAPMD_CTL, 777b050f2f1SRadu Pirea (NXP OSS) MASTER_MODE); 778b050f2f1SRadu Pirea (NXP OSS) break; 779b050f2f1SRadu Pirea (NXP OSS) case MASTER_SLAVE_CFG_SLAVE_PREFERRED: 780b050f2f1SRadu Pirea (NXP OSS) case MASTER_SLAVE_CFG_SLAVE_FORCE: 781b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_B100T1_PMAPMD_CTL, 782b050f2f1SRadu Pirea (NXP OSS) SLAVE_MODE); 783b050f2f1SRadu Pirea (NXP OSS) break; 784b050f2f1SRadu Pirea (NXP OSS) case MASTER_SLAVE_CFG_UNKNOWN: 785b050f2f1SRadu Pirea (NXP OSS) case MASTER_SLAVE_CFG_UNSUPPORTED: 786b050f2f1SRadu Pirea (NXP OSS) return 0; 787b050f2f1SRadu Pirea (NXP OSS) default: 788b050f2f1SRadu Pirea (NXP OSS) phydev_warn(phydev, "Unsupported Master/Slave mode\n"); 789b050f2f1SRadu Pirea (NXP OSS) return -EOPNOTSUPP; 790b050f2f1SRadu Pirea (NXP OSS) } 791b050f2f1SRadu Pirea (NXP OSS) 792b050f2f1SRadu Pirea (NXP OSS) return 0; 793b050f2f1SRadu Pirea (NXP OSS) } 794b050f2f1SRadu Pirea (NXP OSS) 795b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_read_master_slave(struct phy_device *phydev) 796b050f2f1SRadu Pirea (NXP OSS) { 797b050f2f1SRadu Pirea (NXP OSS) int reg; 798b050f2f1SRadu Pirea (NXP OSS) 799b050f2f1SRadu Pirea (NXP OSS) phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN; 800b050f2f1SRadu Pirea (NXP OSS) phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; 801b050f2f1SRadu Pirea (NXP OSS) 802b050f2f1SRadu Pirea (NXP OSS) reg = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_B100T1_PMAPMD_CTL); 803b050f2f1SRadu Pirea (NXP OSS) if (reg < 0) 804b050f2f1SRadu Pirea (NXP OSS) return reg; 805b050f2f1SRadu Pirea (NXP OSS) 806b050f2f1SRadu Pirea (NXP OSS) if (reg & B100T1_PMAPMD_MASTER) { 807b050f2f1SRadu Pirea (NXP OSS) phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE; 808b050f2f1SRadu Pirea (NXP OSS) phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; 809b050f2f1SRadu Pirea (NXP OSS) } else { 810b050f2f1SRadu Pirea (NXP OSS) phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE; 811b050f2f1SRadu Pirea (NXP OSS) phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; 812b050f2f1SRadu Pirea (NXP OSS) } 813b050f2f1SRadu Pirea (NXP OSS) 814b050f2f1SRadu Pirea (NXP OSS) return 0; 815b050f2f1SRadu Pirea (NXP OSS) } 816b050f2f1SRadu Pirea (NXP OSS) 817b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_config_aneg(struct phy_device *phydev) 818b050f2f1SRadu Pirea (NXP OSS) { 819b050f2f1SRadu Pirea (NXP OSS) return nxp_c45_setup_master_slave(phydev); 820b050f2f1SRadu Pirea (NXP OSS) } 821b050f2f1SRadu Pirea (NXP OSS) 822b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_read_status(struct phy_device *phydev) 823b050f2f1SRadu Pirea (NXP OSS) { 824b050f2f1SRadu Pirea (NXP OSS) int ret; 825b050f2f1SRadu Pirea (NXP OSS) 826b050f2f1SRadu Pirea (NXP OSS) ret = genphy_c45_read_status(phydev); 827b050f2f1SRadu Pirea (NXP OSS) if (ret) 828b050f2f1SRadu Pirea (NXP OSS) return ret; 829b050f2f1SRadu Pirea (NXP OSS) 830b050f2f1SRadu Pirea (NXP OSS) ret = nxp_c45_read_master_slave(phydev); 831b050f2f1SRadu Pirea (NXP OSS) if (ret) 832b050f2f1SRadu Pirea (NXP OSS) return ret; 833b050f2f1SRadu Pirea (NXP OSS) 834b050f2f1SRadu Pirea (NXP OSS) return 0; 835b050f2f1SRadu Pirea (NXP OSS) } 836b050f2f1SRadu Pirea (NXP OSS) 837b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_get_sqi(struct phy_device *phydev) 838b050f2f1SRadu Pirea (NXP OSS) { 839b050f2f1SRadu Pirea (NXP OSS) int reg; 840b050f2f1SRadu Pirea (NXP OSS) 841b050f2f1SRadu Pirea (NXP OSS) reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_SIGNAL_QUALITY); 842b050f2f1SRadu Pirea (NXP OSS) if (!(reg & SQI_VALID)) 843b050f2f1SRadu Pirea (NXP OSS) return -EINVAL; 844b050f2f1SRadu Pirea (NXP OSS) 845b050f2f1SRadu Pirea (NXP OSS) reg &= SQI_MASK; 846b050f2f1SRadu Pirea (NXP OSS) 847b050f2f1SRadu Pirea (NXP OSS) return reg; 848b050f2f1SRadu Pirea (NXP OSS) } 849b050f2f1SRadu Pirea (NXP OSS) 850b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_get_sqi_max(struct phy_device *phydev) 851b050f2f1SRadu Pirea (NXP OSS) { 852b050f2f1SRadu Pirea (NXP OSS) return MAX_SQI; 853b050f2f1SRadu Pirea (NXP OSS) } 854b050f2f1SRadu Pirea (NXP OSS) 855b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_check_delay(struct phy_device *phydev, u32 delay) 856b050f2f1SRadu Pirea (NXP OSS) { 857b050f2f1SRadu Pirea (NXP OSS) if (delay < MIN_ID_PS) { 858b050f2f1SRadu Pirea (NXP OSS) phydev_err(phydev, "delay value smaller than %u\n", MIN_ID_PS); 859b050f2f1SRadu Pirea (NXP OSS) return -EINVAL; 860b050f2f1SRadu Pirea (NXP OSS) } 861b050f2f1SRadu Pirea (NXP OSS) 862b050f2f1SRadu Pirea (NXP OSS) if (delay > MAX_ID_PS) { 863b050f2f1SRadu Pirea (NXP OSS) phydev_err(phydev, "delay value higher than %u\n", MAX_ID_PS); 864b050f2f1SRadu Pirea (NXP OSS) return -EINVAL; 865b050f2f1SRadu Pirea (NXP OSS) } 866b050f2f1SRadu Pirea (NXP OSS) 867b050f2f1SRadu Pirea (NXP OSS) return 0; 868b050f2f1SRadu Pirea (NXP OSS) } 869b050f2f1SRadu Pirea (NXP OSS) 870b050f2f1SRadu Pirea (NXP OSS) static u64 nxp_c45_get_phase_shift(u64 phase_offset_raw) 871b050f2f1SRadu Pirea (NXP OSS) { 872b050f2f1SRadu Pirea (NXP OSS) /* The delay in degree phase is 73.8 + phase_offset_raw * 0.9. 873b050f2f1SRadu Pirea (NXP OSS) * To avoid floating point operations we'll multiply by 10 874b050f2f1SRadu Pirea (NXP OSS) * and get 1 decimal point precision. 875b050f2f1SRadu Pirea (NXP OSS) */ 876b050f2f1SRadu Pirea (NXP OSS) phase_offset_raw *= 10; 8776b3a6310SRadu Pirea (NXP OSS) phase_offset_raw -= 738; 878b050f2f1SRadu Pirea (NXP OSS) return div_u64(phase_offset_raw, 9); 879b050f2f1SRadu Pirea (NXP OSS) } 880b050f2f1SRadu Pirea (NXP OSS) 881b050f2f1SRadu Pirea (NXP OSS) static void nxp_c45_disable_delays(struct phy_device *phydev) 882b050f2f1SRadu Pirea (NXP OSS) { 883b050f2f1SRadu Pirea (NXP OSS) phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TXID, ID_ENABLE); 884b050f2f1SRadu Pirea (NXP OSS) phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RXID, ID_ENABLE); 885b050f2f1SRadu Pirea (NXP OSS) } 886b050f2f1SRadu Pirea (NXP OSS) 887b050f2f1SRadu Pirea (NXP OSS) static void nxp_c45_set_delays(struct phy_device *phydev) 888b050f2f1SRadu Pirea (NXP OSS) { 889b050f2f1SRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = phydev->priv; 890b050f2f1SRadu Pirea (NXP OSS) u64 tx_delay = priv->tx_delay; 891b050f2f1SRadu Pirea (NXP OSS) u64 rx_delay = priv->rx_delay; 892b050f2f1SRadu Pirea (NXP OSS) u64 degree; 893b050f2f1SRadu Pirea (NXP OSS) 894b050f2f1SRadu Pirea (NXP OSS) if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 895b050f2f1SRadu Pirea (NXP OSS) phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 896b050f2f1SRadu Pirea (NXP OSS) degree = div_u64(tx_delay, PS_PER_DEGREE); 897b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_TXID, 898b050f2f1SRadu Pirea (NXP OSS) ID_ENABLE | nxp_c45_get_phase_shift(degree)); 899b050f2f1SRadu Pirea (NXP OSS) } else { 900b050f2f1SRadu Pirea (NXP OSS) phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TXID, 901b050f2f1SRadu Pirea (NXP OSS) ID_ENABLE); 902b050f2f1SRadu Pirea (NXP OSS) } 903b050f2f1SRadu Pirea (NXP OSS) 904b050f2f1SRadu Pirea (NXP OSS) if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 905b050f2f1SRadu Pirea (NXP OSS) phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 906b050f2f1SRadu Pirea (NXP OSS) degree = div_u64(rx_delay, PS_PER_DEGREE); 907b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RXID, 908b050f2f1SRadu Pirea (NXP OSS) ID_ENABLE | nxp_c45_get_phase_shift(degree)); 909b050f2f1SRadu Pirea (NXP OSS) } else { 910b050f2f1SRadu Pirea (NXP OSS) phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RXID, 911b050f2f1SRadu Pirea (NXP OSS) ID_ENABLE); 912b050f2f1SRadu Pirea (NXP OSS) } 913b050f2f1SRadu Pirea (NXP OSS) } 914b050f2f1SRadu Pirea (NXP OSS) 915b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_get_delays(struct phy_device *phydev) 916b050f2f1SRadu Pirea (NXP OSS) { 917b050f2f1SRadu Pirea (NXP OSS) struct nxp_c45_phy *priv = phydev->priv; 918b050f2f1SRadu Pirea (NXP OSS) int ret; 919b050f2f1SRadu Pirea (NXP OSS) 920b050f2f1SRadu Pirea (NXP OSS) if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 921b050f2f1SRadu Pirea (NXP OSS) phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 922b050f2f1SRadu Pirea (NXP OSS) ret = device_property_read_u32(&phydev->mdio.dev, 923b050f2f1SRadu Pirea (NXP OSS) "tx-internal-delay-ps", 924b050f2f1SRadu Pirea (NXP OSS) &priv->tx_delay); 925b050f2f1SRadu Pirea (NXP OSS) if (ret) 926b050f2f1SRadu Pirea (NXP OSS) priv->tx_delay = DEFAULT_ID_PS; 927b050f2f1SRadu Pirea (NXP OSS) 928b050f2f1SRadu Pirea (NXP OSS) ret = nxp_c45_check_delay(phydev, priv->tx_delay); 929b050f2f1SRadu Pirea (NXP OSS) if (ret) { 930b050f2f1SRadu Pirea (NXP OSS) phydev_err(phydev, 931b050f2f1SRadu Pirea (NXP OSS) "tx-internal-delay-ps invalid value\n"); 932b050f2f1SRadu Pirea (NXP OSS) return ret; 933b050f2f1SRadu Pirea (NXP OSS) } 934b050f2f1SRadu Pirea (NXP OSS) } 935b050f2f1SRadu Pirea (NXP OSS) 936b050f2f1SRadu Pirea (NXP OSS) if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 937b050f2f1SRadu Pirea (NXP OSS) phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 938b050f2f1SRadu Pirea (NXP OSS) ret = device_property_read_u32(&phydev->mdio.dev, 939b050f2f1SRadu Pirea (NXP OSS) "rx-internal-delay-ps", 940b050f2f1SRadu Pirea (NXP OSS) &priv->rx_delay); 941b050f2f1SRadu Pirea (NXP OSS) if (ret) 942b050f2f1SRadu Pirea (NXP OSS) priv->rx_delay = DEFAULT_ID_PS; 943b050f2f1SRadu Pirea (NXP OSS) 944b050f2f1SRadu Pirea (NXP OSS) ret = nxp_c45_check_delay(phydev, priv->rx_delay); 945b050f2f1SRadu Pirea (NXP OSS) if (ret) { 946b050f2f1SRadu Pirea (NXP OSS) phydev_err(phydev, 947b050f2f1SRadu Pirea (NXP OSS) "rx-internal-delay-ps invalid value\n"); 948b050f2f1SRadu Pirea (NXP OSS) return ret; 949b050f2f1SRadu Pirea (NXP OSS) } 950b050f2f1SRadu Pirea (NXP OSS) } 951b050f2f1SRadu Pirea (NXP OSS) 952b050f2f1SRadu Pirea (NXP OSS) return 0; 953b050f2f1SRadu Pirea (NXP OSS) } 954b050f2f1SRadu Pirea (NXP OSS) 955b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_set_phy_mode(struct phy_device *phydev) 956b050f2f1SRadu Pirea (NXP OSS) { 957b050f2f1SRadu Pirea (NXP OSS) int ret; 958b050f2f1SRadu Pirea (NXP OSS) 959b050f2f1SRadu Pirea (NXP OSS) ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_ABILITIES); 960b050f2f1SRadu Pirea (NXP OSS) phydev_dbg(phydev, "Clause 45 managed PHY abilities 0x%x\n", ret); 961b050f2f1SRadu Pirea (NXP OSS) 962b050f2f1SRadu Pirea (NXP OSS) switch (phydev->interface) { 963b050f2f1SRadu Pirea (NXP OSS) case PHY_INTERFACE_MODE_RGMII: 964b050f2f1SRadu Pirea (NXP OSS) if (!(ret & RGMII_ABILITY)) { 965b050f2f1SRadu Pirea (NXP OSS) phydev_err(phydev, "rgmii mode not supported\n"); 966b050f2f1SRadu Pirea (NXP OSS) return -EINVAL; 967b050f2f1SRadu Pirea (NXP OSS) } 968b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG, 969b050f2f1SRadu Pirea (NXP OSS) MII_BASIC_CONFIG_RGMII); 970b050f2f1SRadu Pirea (NXP OSS) nxp_c45_disable_delays(phydev); 971b050f2f1SRadu Pirea (NXP OSS) break; 972b050f2f1SRadu Pirea (NXP OSS) case PHY_INTERFACE_MODE_RGMII_ID: 973b050f2f1SRadu Pirea (NXP OSS) case PHY_INTERFACE_MODE_RGMII_TXID: 974b050f2f1SRadu Pirea (NXP OSS) case PHY_INTERFACE_MODE_RGMII_RXID: 975b050f2f1SRadu Pirea (NXP OSS) if (!(ret & RGMII_ID_ABILITY)) { 976b050f2f1SRadu Pirea (NXP OSS) phydev_err(phydev, "rgmii-id, rgmii-txid, rgmii-rxid modes are not supported\n"); 977b050f2f1SRadu Pirea (NXP OSS) return -EINVAL; 978b050f2f1SRadu Pirea (NXP OSS) } 979b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG, 980b050f2f1SRadu Pirea (NXP OSS) MII_BASIC_CONFIG_RGMII); 981b050f2f1SRadu Pirea (NXP OSS) ret = nxp_c45_get_delays(phydev); 982b050f2f1SRadu Pirea (NXP OSS) if (ret) 983b050f2f1SRadu Pirea (NXP OSS) return ret; 984b050f2f1SRadu Pirea (NXP OSS) 985b050f2f1SRadu Pirea (NXP OSS) nxp_c45_set_delays(phydev); 986b050f2f1SRadu Pirea (NXP OSS) break; 987b050f2f1SRadu Pirea (NXP OSS) case PHY_INTERFACE_MODE_MII: 988b050f2f1SRadu Pirea (NXP OSS) if (!(ret & MII_ABILITY)) { 989b050f2f1SRadu Pirea (NXP OSS) phydev_err(phydev, "mii mode not supported\n"); 990b050f2f1SRadu Pirea (NXP OSS) return -EINVAL; 991b050f2f1SRadu Pirea (NXP OSS) } 992b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG, 993b050f2f1SRadu Pirea (NXP OSS) MII_BASIC_CONFIG_MII); 994b050f2f1SRadu Pirea (NXP OSS) break; 995b050f2f1SRadu Pirea (NXP OSS) case PHY_INTERFACE_MODE_REVMII: 996b050f2f1SRadu Pirea (NXP OSS) if (!(ret & REVMII_ABILITY)) { 997b050f2f1SRadu Pirea (NXP OSS) phydev_err(phydev, "rev-mii mode not supported\n"); 998b050f2f1SRadu Pirea (NXP OSS) return -EINVAL; 999b050f2f1SRadu Pirea (NXP OSS) } 1000b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG, 1001b050f2f1SRadu Pirea (NXP OSS) MII_BASIC_CONFIG_MII | MII_BASIC_CONFIG_REV); 1002b050f2f1SRadu Pirea (NXP OSS) break; 1003b050f2f1SRadu Pirea (NXP OSS) case PHY_INTERFACE_MODE_RMII: 1004b050f2f1SRadu Pirea (NXP OSS) if (!(ret & RMII_ABILITY)) { 1005b050f2f1SRadu Pirea (NXP OSS) phydev_err(phydev, "rmii mode not supported\n"); 1006b050f2f1SRadu Pirea (NXP OSS) return -EINVAL; 1007b050f2f1SRadu Pirea (NXP OSS) } 1008b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG, 1009b050f2f1SRadu Pirea (NXP OSS) MII_BASIC_CONFIG_RMII); 1010b050f2f1SRadu Pirea (NXP OSS) break; 1011b050f2f1SRadu Pirea (NXP OSS) case PHY_INTERFACE_MODE_SGMII: 1012b050f2f1SRadu Pirea (NXP OSS) if (!(ret & SGMII_ABILITY)) { 1013b050f2f1SRadu Pirea (NXP OSS) phydev_err(phydev, "sgmii mode not supported\n"); 1014b050f2f1SRadu Pirea (NXP OSS) return -EINVAL; 1015b050f2f1SRadu Pirea (NXP OSS) } 1016b050f2f1SRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG, 1017b050f2f1SRadu Pirea (NXP OSS) MII_BASIC_CONFIG_SGMII); 1018b050f2f1SRadu Pirea (NXP OSS) break; 1019b050f2f1SRadu Pirea (NXP OSS) case PHY_INTERFACE_MODE_INTERNAL: 1020b050f2f1SRadu Pirea (NXP OSS) break; 1021b050f2f1SRadu Pirea (NXP OSS) default: 1022b050f2f1SRadu Pirea (NXP OSS) return -EINVAL; 1023b050f2f1SRadu Pirea (NXP OSS) } 1024b050f2f1SRadu Pirea (NXP OSS) 1025b050f2f1SRadu Pirea (NXP OSS) return 0; 1026b050f2f1SRadu Pirea (NXP OSS) } 1027b050f2f1SRadu Pirea (NXP OSS) 1028b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_config_init(struct phy_device *phydev) 1029b050f2f1SRadu Pirea (NXP OSS) { 1030b050f2f1SRadu Pirea (NXP OSS) int ret; 1031b050f2f1SRadu Pirea (NXP OSS) 1032b050f2f1SRadu Pirea (NXP OSS) ret = nxp_c45_config_enable(phydev); 1033b050f2f1SRadu Pirea (NXP OSS) if (ret) { 1034b050f2f1SRadu Pirea (NXP OSS) phydev_err(phydev, "Failed to enable config\n"); 1035b050f2f1SRadu Pirea (NXP OSS) return ret; 1036b050f2f1SRadu Pirea (NXP OSS) } 1037b050f2f1SRadu Pirea (NXP OSS) 1038*0b5f0f29SVladimir Oltean /* Bug workaround for SJA1110 rev B: enable write access 1039*0b5f0f29SVladimir Oltean * to MDIO_MMD_PMAPMD 1040*0b5f0f29SVladimir Oltean */ 1041*0b5f0f29SVladimir Oltean phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 1); 1042*0b5f0f29SVladimir Oltean phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 2); 1043*0b5f0f29SVladimir Oltean 1044b050f2f1SRadu Pirea (NXP OSS) phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONFIG, 1045b050f2f1SRadu Pirea (NXP OSS) PHY_CONFIG_AUTO); 1046b050f2f1SRadu Pirea (NXP OSS) 1047b050f2f1SRadu Pirea (NXP OSS) phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_LINK_DROP_COUNTER, 1048b050f2f1SRadu Pirea (NXP OSS) COUNTER_EN); 1049b050f2f1SRadu Pirea (NXP OSS) phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_PREAMBLE_COUNT, 1050b050f2f1SRadu Pirea (NXP OSS) COUNTER_EN); 1051b050f2f1SRadu Pirea (NXP OSS) phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TX_PREAMBLE_COUNT, 1052b050f2f1SRadu Pirea (NXP OSS) COUNTER_EN); 1053b050f2f1SRadu Pirea (NXP OSS) phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_IPG_LENGTH, 1054b050f2f1SRadu Pirea (NXP OSS) COUNTER_EN); 1055b050f2f1SRadu Pirea (NXP OSS) phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TX_IPG_LENGTH, 1056b050f2f1SRadu Pirea (NXP OSS) COUNTER_EN); 1057b050f2f1SRadu Pirea (NXP OSS) 1058b050f2f1SRadu Pirea (NXP OSS) ret = nxp_c45_set_phy_mode(phydev); 1059b050f2f1SRadu Pirea (NXP OSS) if (ret) 1060b050f2f1SRadu Pirea (NXP OSS) return ret; 1061b050f2f1SRadu Pirea (NXP OSS) 1062b050f2f1SRadu Pirea (NXP OSS) phydev->autoneg = AUTONEG_DISABLE; 1063b050f2f1SRadu Pirea (NXP OSS) 1064514def5dSRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK_PERIOD, 1065514def5dSRadu Pirea (NXP OSS) PTP_CLK_PERIOD_100BT1); 1066514def5dSRadu Pirea (NXP OSS) phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_HW_LTC_LOCK_CTRL, 1067514def5dSRadu Pirea (NXP OSS) HW_LTC_LOCK_EN); 1068514def5dSRadu Pirea (NXP OSS) phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_TS_INSRT_CTRL, 1069514def5dSRadu Pirea (NXP OSS) RX_TS_INSRT_MODE2); 1070514def5dSRadu Pirea (NXP OSS) phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_FUNC_ENABLES, 1071514def5dSRadu Pirea (NXP OSS) PTP_ENABLE); 1072514def5dSRadu Pirea (NXP OSS) 1073b050f2f1SRadu Pirea (NXP OSS) return nxp_c45_start_op(phydev); 1074b050f2f1SRadu Pirea (NXP OSS) } 1075b050f2f1SRadu Pirea (NXP OSS) 1076b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_probe(struct phy_device *phydev) 1077b050f2f1SRadu Pirea (NXP OSS) { 1078b050f2f1SRadu Pirea (NXP OSS) struct nxp_c45_phy *priv; 1079514def5dSRadu Pirea (NXP OSS) int ptp_ability; 1080514def5dSRadu Pirea (NXP OSS) int ret = 0; 1081b050f2f1SRadu Pirea (NXP OSS) 1082b050f2f1SRadu Pirea (NXP OSS) priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 1083b050f2f1SRadu Pirea (NXP OSS) if (!priv) 1084b050f2f1SRadu Pirea (NXP OSS) return -ENOMEM; 1085b050f2f1SRadu Pirea (NXP OSS) 1086514def5dSRadu Pirea (NXP OSS) skb_queue_head_init(&priv->tx_queue); 1087514def5dSRadu Pirea (NXP OSS) skb_queue_head_init(&priv->rx_queue); 1088514def5dSRadu Pirea (NXP OSS) 1089514def5dSRadu Pirea (NXP OSS) priv->phydev = phydev; 1090514def5dSRadu Pirea (NXP OSS) 1091b050f2f1SRadu Pirea (NXP OSS) phydev->priv = priv; 1092b050f2f1SRadu Pirea (NXP OSS) 1093514def5dSRadu Pirea (NXP OSS) mutex_init(&priv->ptp_lock); 1094514def5dSRadu Pirea (NXP OSS) 1095514def5dSRadu Pirea (NXP OSS) ptp_ability = phy_read_mmd(phydev, MDIO_MMD_VEND1, 1096514def5dSRadu Pirea (NXP OSS) VEND1_PORT_ABILITIES); 1097514def5dSRadu Pirea (NXP OSS) ptp_ability = !!(ptp_ability & PTP_ABILITY); 1098514def5dSRadu Pirea (NXP OSS) if (!ptp_ability) { 1099565c6d8cSVladimir Oltean phydev_dbg(phydev, "the phy does not support PTP"); 1100514def5dSRadu Pirea (NXP OSS) goto no_ptp_support; 1101514def5dSRadu Pirea (NXP OSS) } 1102514def5dSRadu Pirea (NXP OSS) 1103514def5dSRadu Pirea (NXP OSS) if (IS_ENABLED(CONFIG_PTP_1588_CLOCK) && 1104514def5dSRadu Pirea (NXP OSS) IS_ENABLED(CONFIG_NETWORK_PHY_TIMESTAMPING)) { 1105514def5dSRadu Pirea (NXP OSS) priv->mii_ts.rxtstamp = nxp_c45_rxtstamp; 1106514def5dSRadu Pirea (NXP OSS) priv->mii_ts.txtstamp = nxp_c45_txtstamp; 1107514def5dSRadu Pirea (NXP OSS) priv->mii_ts.hwtstamp = nxp_c45_hwtstamp; 1108514def5dSRadu Pirea (NXP OSS) priv->mii_ts.ts_info = nxp_c45_ts_info; 1109514def5dSRadu Pirea (NXP OSS) phydev->mii_ts = &priv->mii_ts; 1110514def5dSRadu Pirea (NXP OSS) ret = nxp_c45_init_ptp_clock(priv); 1111514def5dSRadu Pirea (NXP OSS) } else { 1112514def5dSRadu Pirea (NXP OSS) phydev_dbg(phydev, "PTP support not enabled even if the phy supports it"); 1113514def5dSRadu Pirea (NXP OSS) } 1114514def5dSRadu Pirea (NXP OSS) 1115514def5dSRadu Pirea (NXP OSS) no_ptp_support: 1116514def5dSRadu Pirea (NXP OSS) 1117514def5dSRadu Pirea (NXP OSS) return ret; 1118b050f2f1SRadu Pirea (NXP OSS) } 1119b050f2f1SRadu Pirea (NXP OSS) 1120b050f2f1SRadu Pirea (NXP OSS) static struct phy_driver nxp_c45_driver[] = { 1121b050f2f1SRadu Pirea (NXP OSS) { 1122b050f2f1SRadu Pirea (NXP OSS) PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103), 1123b050f2f1SRadu Pirea (NXP OSS) .name = "NXP C45 TJA1103", 1124b050f2f1SRadu Pirea (NXP OSS) .features = PHY_BASIC_T1_FEATURES, 1125b050f2f1SRadu Pirea (NXP OSS) .probe = nxp_c45_probe, 1126b050f2f1SRadu Pirea (NXP OSS) .soft_reset = nxp_c45_soft_reset, 1127b050f2f1SRadu Pirea (NXP OSS) .config_aneg = nxp_c45_config_aneg, 1128b050f2f1SRadu Pirea (NXP OSS) .config_init = nxp_c45_config_init, 1129b2f0ca00SRadu Pirea (NXP OSS) .config_intr = nxp_c45_config_intr, 1130b2f0ca00SRadu Pirea (NXP OSS) .handle_interrupt = nxp_c45_handle_interrupt, 1131b050f2f1SRadu Pirea (NXP OSS) .read_status = nxp_c45_read_status, 1132b050f2f1SRadu Pirea (NXP OSS) .suspend = genphy_c45_pma_suspend, 1133b050f2f1SRadu Pirea (NXP OSS) .resume = genphy_c45_pma_resume, 1134b050f2f1SRadu Pirea (NXP OSS) .get_sset_count = nxp_c45_get_sset_count, 1135b050f2f1SRadu Pirea (NXP OSS) .get_strings = nxp_c45_get_strings, 1136b050f2f1SRadu Pirea (NXP OSS) .get_stats = nxp_c45_get_stats, 1137b050f2f1SRadu Pirea (NXP OSS) .cable_test_start = nxp_c45_cable_test_start, 1138b050f2f1SRadu Pirea (NXP OSS) .cable_test_get_status = nxp_c45_cable_test_get_status, 1139b050f2f1SRadu Pirea (NXP OSS) .set_loopback = genphy_c45_loopback, 1140b050f2f1SRadu Pirea (NXP OSS) .get_sqi = nxp_c45_get_sqi, 1141b050f2f1SRadu Pirea (NXP OSS) .get_sqi_max = nxp_c45_get_sqi_max, 1142b050f2f1SRadu Pirea (NXP OSS) }, 1143b050f2f1SRadu Pirea (NXP OSS) }; 1144b050f2f1SRadu Pirea (NXP OSS) 1145b050f2f1SRadu Pirea (NXP OSS) module_phy_driver(nxp_c45_driver); 1146b050f2f1SRadu Pirea (NXP OSS) 1147b050f2f1SRadu Pirea (NXP OSS) static struct mdio_device_id __maybe_unused nxp_c45_tbl[] = { 1148b050f2f1SRadu Pirea (NXP OSS) { PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103) }, 1149b050f2f1SRadu Pirea (NXP OSS) { /*sentinel*/ }, 1150b050f2f1SRadu Pirea (NXP OSS) }; 1151b050f2f1SRadu Pirea (NXP OSS) 1152b050f2f1SRadu Pirea (NXP OSS) MODULE_DEVICE_TABLE(mdio, nxp_c45_tbl); 1153b050f2f1SRadu Pirea (NXP OSS) 1154b050f2f1SRadu Pirea (NXP OSS) MODULE_AUTHOR("Radu Pirea <radu-nicolae.pirea@oss.nxp.com>"); 1155b050f2f1SRadu Pirea (NXP OSS) MODULE_DESCRIPTION("NXP C45 PHY driver"); 1156b050f2f1SRadu Pirea (NXP OSS) MODULE_LICENSE("GPL v2"); 1157