xref: /openbmc/linux/drivers/net/phy/nxp-c45-tja11xx.c (revision b2f0ca00e6b34bd57c9298a869ea133699e8ec39)
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>
16b050f2f1SRadu Pirea (NXP OSS) 
17b050f2f1SRadu Pirea (NXP OSS) #define PHY_ID_TJA_1103			0x001BB010
18b050f2f1SRadu Pirea (NXP OSS) 
19b050f2f1SRadu Pirea (NXP OSS) #define PMAPMD_B100T1_PMAPMD_CTL	0x0834
20b050f2f1SRadu Pirea (NXP OSS) #define B100T1_PMAPMD_CONFIG_EN		BIT(15)
21b050f2f1SRadu Pirea (NXP OSS) #define B100T1_PMAPMD_MASTER		BIT(14)
22b050f2f1SRadu Pirea (NXP OSS) #define MASTER_MODE			(B100T1_PMAPMD_CONFIG_EN | \
23b050f2f1SRadu Pirea (NXP OSS) 					 B100T1_PMAPMD_MASTER)
24b050f2f1SRadu Pirea (NXP OSS) #define SLAVE_MODE			(B100T1_PMAPMD_CONFIG_EN)
25b050f2f1SRadu Pirea (NXP OSS) 
26b050f2f1SRadu Pirea (NXP OSS) #define VEND1_DEVICE_CONTROL		0x0040
27b050f2f1SRadu Pirea (NXP OSS) #define DEVICE_CONTROL_RESET		BIT(15)
28b050f2f1SRadu Pirea (NXP OSS) #define DEVICE_CONTROL_CONFIG_GLOBAL_EN	BIT(14)
29b050f2f1SRadu Pirea (NXP OSS) #define DEVICE_CONTROL_CONFIG_ALL_EN	BIT(13)
30b050f2f1SRadu Pirea (NXP OSS) 
31*b2f0ca00SRadu Pirea (NXP OSS) #define VEND1_PHY_IRQ_ACK		0x80A0
32*b2f0ca00SRadu Pirea (NXP OSS) #define VEND1_PHY_IRQ_EN		0x80A1
33*b2f0ca00SRadu Pirea (NXP OSS) #define VEND1_PHY_IRQ_STATUS		0x80A2
34*b2f0ca00SRadu Pirea (NXP OSS) #define PHY_IRQ_LINK_EVENT		BIT(1)
35*b2f0ca00SRadu Pirea (NXP OSS) 
36b050f2f1SRadu Pirea (NXP OSS) #define VEND1_PHY_CONTROL		0x8100
37b050f2f1SRadu Pirea (NXP OSS) #define PHY_CONFIG_EN			BIT(14)
38b050f2f1SRadu Pirea (NXP OSS) #define PHY_START_OP			BIT(0)
39b050f2f1SRadu Pirea (NXP OSS) 
40b050f2f1SRadu Pirea (NXP OSS) #define VEND1_PHY_CONFIG		0x8108
41b050f2f1SRadu Pirea (NXP OSS) #define PHY_CONFIG_AUTO			BIT(0)
42b050f2f1SRadu Pirea (NXP OSS) 
43b050f2f1SRadu Pirea (NXP OSS) #define VEND1_SIGNAL_QUALITY		0x8320
44b050f2f1SRadu Pirea (NXP OSS) #define SQI_VALID			BIT(14)
45b050f2f1SRadu Pirea (NXP OSS) #define SQI_MASK			GENMASK(2, 0)
46b050f2f1SRadu Pirea (NXP OSS) #define MAX_SQI				SQI_MASK
47b050f2f1SRadu Pirea (NXP OSS) 
48b050f2f1SRadu Pirea (NXP OSS) #define VEND1_CABLE_TEST		0x8330
49b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_ENABLE		BIT(15)
50b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_START		BIT(14)
51b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_VALID		BIT(13)
52b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_OK			0x00
53b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_SHORTED		0x01
54b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_OPEN			0x02
55b050f2f1SRadu Pirea (NXP OSS) #define CABLE_TEST_UNKNOWN		0x07
56b050f2f1SRadu Pirea (NXP OSS) 
57b050f2f1SRadu Pirea (NXP OSS) #define VEND1_PORT_CONTROL		0x8040
58b050f2f1SRadu Pirea (NXP OSS) #define PORT_CONTROL_EN			BIT(14)
59b050f2f1SRadu Pirea (NXP OSS) 
60b050f2f1SRadu Pirea (NXP OSS) #define VEND1_PORT_INFRA_CONTROL	0xAC00
61b050f2f1SRadu Pirea (NXP OSS) #define PORT_INFRA_CONTROL_EN		BIT(14)
62b050f2f1SRadu Pirea (NXP OSS) 
63b050f2f1SRadu Pirea (NXP OSS) #define VEND1_RXID			0xAFCC
64b050f2f1SRadu Pirea (NXP OSS) #define VEND1_TXID			0xAFCD
65b050f2f1SRadu Pirea (NXP OSS) #define ID_ENABLE			BIT(15)
66b050f2f1SRadu Pirea (NXP OSS) 
67b050f2f1SRadu Pirea (NXP OSS) #define VEND1_ABILITIES			0xAFC4
68b050f2f1SRadu Pirea (NXP OSS) #define RGMII_ID_ABILITY		BIT(15)
69b050f2f1SRadu Pirea (NXP OSS) #define RGMII_ABILITY			BIT(14)
70b050f2f1SRadu Pirea (NXP OSS) #define RMII_ABILITY			BIT(10)
71b050f2f1SRadu Pirea (NXP OSS) #define REVMII_ABILITY			BIT(9)
72b050f2f1SRadu Pirea (NXP OSS) #define MII_ABILITY			BIT(8)
73b050f2f1SRadu Pirea (NXP OSS) #define SGMII_ABILITY			BIT(0)
74b050f2f1SRadu Pirea (NXP OSS) 
75b050f2f1SRadu Pirea (NXP OSS) #define VEND1_MII_BASIC_CONFIG		0xAFC6
76b050f2f1SRadu Pirea (NXP OSS) #define MII_BASIC_CONFIG_REV		BIT(8)
77b050f2f1SRadu Pirea (NXP OSS) #define MII_BASIC_CONFIG_SGMII		0x9
78b050f2f1SRadu Pirea (NXP OSS) #define MII_BASIC_CONFIG_RGMII		0x7
79b050f2f1SRadu Pirea (NXP OSS) #define MII_BASIC_CONFIG_RMII		0x5
80b050f2f1SRadu Pirea (NXP OSS) #define MII_BASIC_CONFIG_MII		0x4
81b050f2f1SRadu Pirea (NXP OSS) 
82b050f2f1SRadu Pirea (NXP OSS) #define VEND1_SYMBOL_ERROR_COUNTER	0x8350
83b050f2f1SRadu Pirea (NXP OSS) #define VEND1_LINK_DROP_COUNTER		0x8352
84b050f2f1SRadu Pirea (NXP OSS) #define VEND1_LINK_LOSSES_AND_FAILURES	0x8353
85b050f2f1SRadu Pirea (NXP OSS) #define VEND1_R_GOOD_FRAME_CNT		0xA950
86b050f2f1SRadu Pirea (NXP OSS) #define VEND1_R_BAD_FRAME_CNT		0xA952
87b050f2f1SRadu Pirea (NXP OSS) #define VEND1_R_RXER_FRAME_CNT		0xA954
88b050f2f1SRadu Pirea (NXP OSS) #define VEND1_RX_PREAMBLE_COUNT		0xAFCE
89b050f2f1SRadu Pirea (NXP OSS) #define VEND1_TX_PREAMBLE_COUNT		0xAFCF
90b050f2f1SRadu Pirea (NXP OSS) #define VEND1_RX_IPG_LENGTH		0xAFD0
91b050f2f1SRadu Pirea (NXP OSS) #define VEND1_TX_IPG_LENGTH		0xAFD1
92b050f2f1SRadu Pirea (NXP OSS) #define COUNTER_EN			BIT(15)
93b050f2f1SRadu Pirea (NXP OSS) 
94b050f2f1SRadu Pirea (NXP OSS) #define RGMII_PERIOD_PS			8000U
95b050f2f1SRadu Pirea (NXP OSS) #define PS_PER_DEGREE			div_u64(RGMII_PERIOD_PS, 360)
96b050f2f1SRadu Pirea (NXP OSS) #define MIN_ID_PS			1644U
97b050f2f1SRadu Pirea (NXP OSS) #define MAX_ID_PS			2260U
98b050f2f1SRadu Pirea (NXP OSS) #define DEFAULT_ID_PS			2000U
99b050f2f1SRadu Pirea (NXP OSS) 
100b050f2f1SRadu Pirea (NXP OSS) struct nxp_c45_phy {
101b050f2f1SRadu Pirea (NXP OSS) 	u32 tx_delay;
102b050f2f1SRadu Pirea (NXP OSS) 	u32 rx_delay;
103b050f2f1SRadu Pirea (NXP OSS) };
104b050f2f1SRadu Pirea (NXP OSS) 
105b050f2f1SRadu Pirea (NXP OSS) struct nxp_c45_phy_stats {
106b050f2f1SRadu Pirea (NXP OSS) 	const char	*name;
107b050f2f1SRadu Pirea (NXP OSS) 	u8		mmd;
108b050f2f1SRadu Pirea (NXP OSS) 	u16		reg;
109b050f2f1SRadu Pirea (NXP OSS) 	u8		off;
110b050f2f1SRadu Pirea (NXP OSS) 	u16		mask;
111b050f2f1SRadu Pirea (NXP OSS) };
112b050f2f1SRadu Pirea (NXP OSS) 
113b050f2f1SRadu Pirea (NXP OSS) static const struct nxp_c45_phy_stats nxp_c45_hw_stats[] = {
114b050f2f1SRadu Pirea (NXP OSS) 	{ "phy_symbol_error_cnt", MDIO_MMD_VEND1,
115b050f2f1SRadu Pirea (NXP OSS) 		VEND1_SYMBOL_ERROR_COUNTER, 0, GENMASK(15, 0) },
116b050f2f1SRadu Pirea (NXP OSS) 	{ "phy_link_status_drop_cnt", MDIO_MMD_VEND1,
117b050f2f1SRadu Pirea (NXP OSS) 		VEND1_LINK_DROP_COUNTER, 8, GENMASK(13, 8) },
118b050f2f1SRadu Pirea (NXP OSS) 	{ "phy_link_availability_drop_cnt", MDIO_MMD_VEND1,
119b050f2f1SRadu Pirea (NXP OSS) 		VEND1_LINK_DROP_COUNTER, 0, GENMASK(5, 0) },
120b050f2f1SRadu Pirea (NXP OSS) 	{ "phy_link_loss_cnt", MDIO_MMD_VEND1,
121b050f2f1SRadu Pirea (NXP OSS) 		VEND1_LINK_LOSSES_AND_FAILURES, 10, GENMASK(15, 10) },
122b050f2f1SRadu Pirea (NXP OSS) 	{ "phy_link_failure_cnt", MDIO_MMD_VEND1,
123b050f2f1SRadu Pirea (NXP OSS) 		VEND1_LINK_LOSSES_AND_FAILURES, 0, GENMASK(9, 0) },
124b050f2f1SRadu Pirea (NXP OSS) 	{ "r_good_frame_cnt", MDIO_MMD_VEND1,
125b050f2f1SRadu Pirea (NXP OSS) 		VEND1_R_GOOD_FRAME_CNT, 0, GENMASK(15, 0) },
126b050f2f1SRadu Pirea (NXP OSS) 	{ "r_bad_frame_cnt", MDIO_MMD_VEND1,
127b050f2f1SRadu Pirea (NXP OSS) 		VEND1_R_BAD_FRAME_CNT, 0, GENMASK(15, 0) },
128b050f2f1SRadu Pirea (NXP OSS) 	{ "r_rxer_frame_cnt", MDIO_MMD_VEND1,
129b050f2f1SRadu Pirea (NXP OSS) 		VEND1_R_RXER_FRAME_CNT, 0, GENMASK(15, 0) },
130b050f2f1SRadu Pirea (NXP OSS) 	{ "rx_preamble_count", MDIO_MMD_VEND1,
131b050f2f1SRadu Pirea (NXP OSS) 		VEND1_RX_PREAMBLE_COUNT, 0, GENMASK(5, 0) },
132b050f2f1SRadu Pirea (NXP OSS) 	{ "tx_preamble_count", MDIO_MMD_VEND1,
133b050f2f1SRadu Pirea (NXP OSS) 		VEND1_TX_PREAMBLE_COUNT, 0, GENMASK(5, 0) },
134b050f2f1SRadu Pirea (NXP OSS) 	{ "rx_ipg_length", MDIO_MMD_VEND1,
135b050f2f1SRadu Pirea (NXP OSS) 		VEND1_RX_IPG_LENGTH, 0, GENMASK(8, 0) },
136b050f2f1SRadu Pirea (NXP OSS) 	{ "tx_ipg_length", MDIO_MMD_VEND1,
137b050f2f1SRadu Pirea (NXP OSS) 		VEND1_TX_IPG_LENGTH, 0, GENMASK(8, 0) },
138b050f2f1SRadu Pirea (NXP OSS) };
139b050f2f1SRadu Pirea (NXP OSS) 
140b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_get_sset_count(struct phy_device *phydev)
141b050f2f1SRadu Pirea (NXP OSS) {
142b050f2f1SRadu Pirea (NXP OSS) 	return ARRAY_SIZE(nxp_c45_hw_stats);
143b050f2f1SRadu Pirea (NXP OSS) }
144b050f2f1SRadu Pirea (NXP OSS) 
145b050f2f1SRadu Pirea (NXP OSS) static void nxp_c45_get_strings(struct phy_device *phydev, u8 *data)
146b050f2f1SRadu Pirea (NXP OSS) {
147b050f2f1SRadu Pirea (NXP OSS) 	size_t i;
148b050f2f1SRadu Pirea (NXP OSS) 
149b050f2f1SRadu Pirea (NXP OSS) 	for (i = 0; i < ARRAY_SIZE(nxp_c45_hw_stats); i++) {
150b050f2f1SRadu Pirea (NXP OSS) 		strncpy(data + i * ETH_GSTRING_LEN,
151b050f2f1SRadu Pirea (NXP OSS) 			nxp_c45_hw_stats[i].name, ETH_GSTRING_LEN);
152b050f2f1SRadu Pirea (NXP OSS) 	}
153b050f2f1SRadu Pirea (NXP OSS) }
154b050f2f1SRadu Pirea (NXP OSS) 
155b050f2f1SRadu Pirea (NXP OSS) static void nxp_c45_get_stats(struct phy_device *phydev,
156b050f2f1SRadu Pirea (NXP OSS) 			      struct ethtool_stats *stats, u64 *data)
157b050f2f1SRadu Pirea (NXP OSS) {
158b050f2f1SRadu Pirea (NXP OSS) 	size_t i;
159b050f2f1SRadu Pirea (NXP OSS) 	int ret;
160b050f2f1SRadu Pirea (NXP OSS) 
161b050f2f1SRadu Pirea (NXP OSS) 	for (i = 0; i < ARRAY_SIZE(nxp_c45_hw_stats); i++) {
162b050f2f1SRadu Pirea (NXP OSS) 		ret = phy_read_mmd(phydev, nxp_c45_hw_stats[i].mmd,
163b050f2f1SRadu Pirea (NXP OSS) 				   nxp_c45_hw_stats[i].reg);
164b050f2f1SRadu Pirea (NXP OSS) 		if (ret < 0) {
165b050f2f1SRadu Pirea (NXP OSS) 			data[i] = U64_MAX;
166b050f2f1SRadu Pirea (NXP OSS) 		} else {
167b050f2f1SRadu Pirea (NXP OSS) 			data[i] = ret & nxp_c45_hw_stats[i].mask;
168b050f2f1SRadu Pirea (NXP OSS) 			data[i] >>= nxp_c45_hw_stats[i].off;
169b050f2f1SRadu Pirea (NXP OSS) 		}
170b050f2f1SRadu Pirea (NXP OSS) 	}
171b050f2f1SRadu Pirea (NXP OSS) }
172b050f2f1SRadu Pirea (NXP OSS) 
173b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_config_enable(struct phy_device *phydev)
174b050f2f1SRadu Pirea (NXP OSS) {
175b050f2f1SRadu Pirea (NXP OSS) 	phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_CONTROL,
176b050f2f1SRadu Pirea (NXP OSS) 		      DEVICE_CONTROL_CONFIG_GLOBAL_EN |
177b050f2f1SRadu Pirea (NXP OSS) 		      DEVICE_CONTROL_CONFIG_ALL_EN);
178b050f2f1SRadu Pirea (NXP OSS) 	usleep_range(400, 450);
179b050f2f1SRadu Pirea (NXP OSS) 
180b050f2f1SRadu Pirea (NXP OSS) 	phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_CONTROL,
181b050f2f1SRadu Pirea (NXP OSS) 		      PORT_CONTROL_EN);
182b050f2f1SRadu Pirea (NXP OSS) 	phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONTROL,
183b050f2f1SRadu Pirea (NXP OSS) 		      PHY_CONFIG_EN);
184b050f2f1SRadu Pirea (NXP OSS) 	phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_INFRA_CONTROL,
185b050f2f1SRadu Pirea (NXP OSS) 		      PORT_INFRA_CONTROL_EN);
186b050f2f1SRadu Pirea (NXP OSS) 
187b050f2f1SRadu Pirea (NXP OSS) 	return 0;
188b050f2f1SRadu Pirea (NXP OSS) }
189b050f2f1SRadu Pirea (NXP OSS) 
190b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_start_op(struct phy_device *phydev)
191b050f2f1SRadu Pirea (NXP OSS) {
192b050f2f1SRadu Pirea (NXP OSS) 	return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONTROL,
193b050f2f1SRadu Pirea (NXP OSS) 				PHY_START_OP);
194b050f2f1SRadu Pirea (NXP OSS) }
195b050f2f1SRadu Pirea (NXP OSS) 
196*b2f0ca00SRadu Pirea (NXP OSS) static int nxp_c45_config_intr(struct phy_device *phydev)
197*b2f0ca00SRadu Pirea (NXP OSS) {
198*b2f0ca00SRadu Pirea (NXP OSS) 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
199*b2f0ca00SRadu Pirea (NXP OSS) 		return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
200*b2f0ca00SRadu Pirea (NXP OSS) 					VEND1_PHY_IRQ_EN, PHY_IRQ_LINK_EVENT);
201*b2f0ca00SRadu Pirea (NXP OSS) 	else
202*b2f0ca00SRadu Pirea (NXP OSS) 		return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
203*b2f0ca00SRadu Pirea (NXP OSS) 					  VEND1_PHY_IRQ_EN, PHY_IRQ_LINK_EVENT);
204*b2f0ca00SRadu Pirea (NXP OSS) }
205*b2f0ca00SRadu Pirea (NXP OSS) 
206*b2f0ca00SRadu Pirea (NXP OSS) static irqreturn_t nxp_c45_handle_interrupt(struct phy_device *phydev)
207*b2f0ca00SRadu Pirea (NXP OSS) {
208*b2f0ca00SRadu Pirea (NXP OSS) 	irqreturn_t ret = IRQ_NONE;
209*b2f0ca00SRadu Pirea (NXP OSS) 	int irq;
210*b2f0ca00SRadu Pirea (NXP OSS) 
211*b2f0ca00SRadu Pirea (NXP OSS) 	irq = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_IRQ_STATUS);
212*b2f0ca00SRadu Pirea (NXP OSS) 	if (irq & PHY_IRQ_LINK_EVENT) {
213*b2f0ca00SRadu Pirea (NXP OSS) 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_IRQ_ACK,
214*b2f0ca00SRadu Pirea (NXP OSS) 			      PHY_IRQ_LINK_EVENT);
215*b2f0ca00SRadu Pirea (NXP OSS) 		phy_trigger_machine(phydev);
216*b2f0ca00SRadu Pirea (NXP OSS) 		ret = IRQ_HANDLED;
217*b2f0ca00SRadu Pirea (NXP OSS) 	}
218*b2f0ca00SRadu Pirea (NXP OSS) 
219*b2f0ca00SRadu Pirea (NXP OSS) 	return ret;
220*b2f0ca00SRadu Pirea (NXP OSS) }
221*b2f0ca00SRadu Pirea (NXP OSS) 
222b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_soft_reset(struct phy_device *phydev)
223b050f2f1SRadu Pirea (NXP OSS) {
224b050f2f1SRadu Pirea (NXP OSS) 	int ret;
225b050f2f1SRadu Pirea (NXP OSS) 
226b050f2f1SRadu Pirea (NXP OSS) 	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_CONTROL,
227b050f2f1SRadu Pirea (NXP OSS) 			    DEVICE_CONTROL_RESET);
228b050f2f1SRadu Pirea (NXP OSS) 	if (ret)
229b050f2f1SRadu Pirea (NXP OSS) 		return ret;
230b050f2f1SRadu Pirea (NXP OSS) 
231b050f2f1SRadu Pirea (NXP OSS) 	return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
232b050f2f1SRadu Pirea (NXP OSS) 					 VEND1_DEVICE_CONTROL, ret,
233b050f2f1SRadu Pirea (NXP OSS) 					 !(ret & DEVICE_CONTROL_RESET), 20000,
234b050f2f1SRadu Pirea (NXP OSS) 					 240000, false);
235b050f2f1SRadu Pirea (NXP OSS) }
236b050f2f1SRadu Pirea (NXP OSS) 
237b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_cable_test_start(struct phy_device *phydev)
238b050f2f1SRadu Pirea (NXP OSS) {
239b050f2f1SRadu Pirea (NXP OSS) 	return phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_CABLE_TEST,
240b050f2f1SRadu Pirea (NXP OSS) 			     CABLE_TEST_ENABLE | CABLE_TEST_START);
241b050f2f1SRadu Pirea (NXP OSS) }
242b050f2f1SRadu Pirea (NXP OSS) 
243b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_cable_test_get_status(struct phy_device *phydev,
244b050f2f1SRadu Pirea (NXP OSS) 					 bool *finished)
245b050f2f1SRadu Pirea (NXP OSS) {
246b050f2f1SRadu Pirea (NXP OSS) 	int ret;
247b050f2f1SRadu Pirea (NXP OSS) 	u8 cable_test_result;
248b050f2f1SRadu Pirea (NXP OSS) 
249b050f2f1SRadu Pirea (NXP OSS) 	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_CABLE_TEST);
250b050f2f1SRadu Pirea (NXP OSS) 	if (!(ret & CABLE_TEST_VALID)) {
251b050f2f1SRadu Pirea (NXP OSS) 		*finished = false;
252b050f2f1SRadu Pirea (NXP OSS) 		return 0;
253b050f2f1SRadu Pirea (NXP OSS) 	}
254b050f2f1SRadu Pirea (NXP OSS) 
255b050f2f1SRadu Pirea (NXP OSS) 	*finished = true;
256b050f2f1SRadu Pirea (NXP OSS) 	cable_test_result = ret & GENMASK(2, 0);
257b050f2f1SRadu Pirea (NXP OSS) 
258b050f2f1SRadu Pirea (NXP OSS) 	switch (cable_test_result) {
259b050f2f1SRadu Pirea (NXP OSS) 	case CABLE_TEST_OK:
260b050f2f1SRadu Pirea (NXP OSS) 		ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
261b050f2f1SRadu Pirea (NXP OSS) 					ETHTOOL_A_CABLE_RESULT_CODE_OK);
262b050f2f1SRadu Pirea (NXP OSS) 		break;
263b050f2f1SRadu Pirea (NXP OSS) 	case CABLE_TEST_SHORTED:
264b050f2f1SRadu Pirea (NXP OSS) 		ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
265b050f2f1SRadu Pirea (NXP OSS) 					ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT);
266b050f2f1SRadu Pirea (NXP OSS) 		break;
267b050f2f1SRadu Pirea (NXP OSS) 	case CABLE_TEST_OPEN:
268b050f2f1SRadu Pirea (NXP OSS) 		ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
269b050f2f1SRadu Pirea (NXP OSS) 					ETHTOOL_A_CABLE_RESULT_CODE_OPEN);
270b050f2f1SRadu Pirea (NXP OSS) 		break;
271b050f2f1SRadu Pirea (NXP OSS) 	default:
272b050f2f1SRadu Pirea (NXP OSS) 		ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
273b050f2f1SRadu Pirea (NXP OSS) 					ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC);
274b050f2f1SRadu Pirea (NXP OSS) 	}
275b050f2f1SRadu Pirea (NXP OSS) 
276b050f2f1SRadu Pirea (NXP OSS) 	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_CABLE_TEST,
277b050f2f1SRadu Pirea (NXP OSS) 			   CABLE_TEST_ENABLE);
278b050f2f1SRadu Pirea (NXP OSS) 
279b050f2f1SRadu Pirea (NXP OSS) 	return nxp_c45_start_op(phydev);
280b050f2f1SRadu Pirea (NXP OSS) }
281b050f2f1SRadu Pirea (NXP OSS) 
282b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_setup_master_slave(struct phy_device *phydev)
283b050f2f1SRadu Pirea (NXP OSS) {
284b050f2f1SRadu Pirea (NXP OSS) 	switch (phydev->master_slave_set) {
285b050f2f1SRadu Pirea (NXP OSS) 	case MASTER_SLAVE_CFG_MASTER_FORCE:
286b050f2f1SRadu Pirea (NXP OSS) 	case MASTER_SLAVE_CFG_MASTER_PREFERRED:
287b050f2f1SRadu Pirea (NXP OSS) 		phy_write_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_B100T1_PMAPMD_CTL,
288b050f2f1SRadu Pirea (NXP OSS) 			      MASTER_MODE);
289b050f2f1SRadu Pirea (NXP OSS) 		break;
290b050f2f1SRadu Pirea (NXP OSS) 	case MASTER_SLAVE_CFG_SLAVE_PREFERRED:
291b050f2f1SRadu Pirea (NXP OSS) 	case MASTER_SLAVE_CFG_SLAVE_FORCE:
292b050f2f1SRadu Pirea (NXP OSS) 		phy_write_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_B100T1_PMAPMD_CTL,
293b050f2f1SRadu Pirea (NXP OSS) 			      SLAVE_MODE);
294b050f2f1SRadu Pirea (NXP OSS) 		break;
295b050f2f1SRadu Pirea (NXP OSS) 	case MASTER_SLAVE_CFG_UNKNOWN:
296b050f2f1SRadu Pirea (NXP OSS) 	case MASTER_SLAVE_CFG_UNSUPPORTED:
297b050f2f1SRadu Pirea (NXP OSS) 		return 0;
298b050f2f1SRadu Pirea (NXP OSS) 	default:
299b050f2f1SRadu Pirea (NXP OSS) 		phydev_warn(phydev, "Unsupported Master/Slave mode\n");
300b050f2f1SRadu Pirea (NXP OSS) 		return -EOPNOTSUPP;
301b050f2f1SRadu Pirea (NXP OSS) 	}
302b050f2f1SRadu Pirea (NXP OSS) 
303b050f2f1SRadu Pirea (NXP OSS) 	return 0;
304b050f2f1SRadu Pirea (NXP OSS) }
305b050f2f1SRadu Pirea (NXP OSS) 
306b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_read_master_slave(struct phy_device *phydev)
307b050f2f1SRadu Pirea (NXP OSS) {
308b050f2f1SRadu Pirea (NXP OSS) 	int reg;
309b050f2f1SRadu Pirea (NXP OSS) 
310b050f2f1SRadu Pirea (NXP OSS) 	phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
311b050f2f1SRadu Pirea (NXP OSS) 	phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
312b050f2f1SRadu Pirea (NXP OSS) 
313b050f2f1SRadu Pirea (NXP OSS) 	reg = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_B100T1_PMAPMD_CTL);
314b050f2f1SRadu Pirea (NXP OSS) 	if (reg < 0)
315b050f2f1SRadu Pirea (NXP OSS) 		return reg;
316b050f2f1SRadu Pirea (NXP OSS) 
317b050f2f1SRadu Pirea (NXP OSS) 	if (reg & B100T1_PMAPMD_MASTER) {
318b050f2f1SRadu Pirea (NXP OSS) 		phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE;
319b050f2f1SRadu Pirea (NXP OSS) 		phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
320b050f2f1SRadu Pirea (NXP OSS) 	} else {
321b050f2f1SRadu Pirea (NXP OSS) 		phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE;
322b050f2f1SRadu Pirea (NXP OSS) 		phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
323b050f2f1SRadu Pirea (NXP OSS) 	}
324b050f2f1SRadu Pirea (NXP OSS) 
325b050f2f1SRadu Pirea (NXP OSS) 	return 0;
326b050f2f1SRadu Pirea (NXP OSS) }
327b050f2f1SRadu Pirea (NXP OSS) 
328b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_config_aneg(struct phy_device *phydev)
329b050f2f1SRadu Pirea (NXP OSS) {
330b050f2f1SRadu Pirea (NXP OSS) 	return nxp_c45_setup_master_slave(phydev);
331b050f2f1SRadu Pirea (NXP OSS) }
332b050f2f1SRadu Pirea (NXP OSS) 
333b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_read_status(struct phy_device *phydev)
334b050f2f1SRadu Pirea (NXP OSS) {
335b050f2f1SRadu Pirea (NXP OSS) 	int ret;
336b050f2f1SRadu Pirea (NXP OSS) 
337b050f2f1SRadu Pirea (NXP OSS) 	ret = genphy_c45_read_status(phydev);
338b050f2f1SRadu Pirea (NXP OSS) 	if (ret)
339b050f2f1SRadu Pirea (NXP OSS) 		return ret;
340b050f2f1SRadu Pirea (NXP OSS) 
341b050f2f1SRadu Pirea (NXP OSS) 	ret = nxp_c45_read_master_slave(phydev);
342b050f2f1SRadu Pirea (NXP OSS) 	if (ret)
343b050f2f1SRadu Pirea (NXP OSS) 		return ret;
344b050f2f1SRadu Pirea (NXP OSS) 
345b050f2f1SRadu Pirea (NXP OSS) 	return 0;
346b050f2f1SRadu Pirea (NXP OSS) }
347b050f2f1SRadu Pirea (NXP OSS) 
348b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_get_sqi(struct phy_device *phydev)
349b050f2f1SRadu Pirea (NXP OSS) {
350b050f2f1SRadu Pirea (NXP OSS) 	int reg;
351b050f2f1SRadu Pirea (NXP OSS) 
352b050f2f1SRadu Pirea (NXP OSS) 	reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_SIGNAL_QUALITY);
353b050f2f1SRadu Pirea (NXP OSS) 	if (!(reg & SQI_VALID))
354b050f2f1SRadu Pirea (NXP OSS) 		return -EINVAL;
355b050f2f1SRadu Pirea (NXP OSS) 
356b050f2f1SRadu Pirea (NXP OSS) 	reg &= SQI_MASK;
357b050f2f1SRadu Pirea (NXP OSS) 
358b050f2f1SRadu Pirea (NXP OSS) 	return reg;
359b050f2f1SRadu Pirea (NXP OSS) }
360b050f2f1SRadu Pirea (NXP OSS) 
361b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_get_sqi_max(struct phy_device *phydev)
362b050f2f1SRadu Pirea (NXP OSS) {
363b050f2f1SRadu Pirea (NXP OSS) 	return MAX_SQI;
364b050f2f1SRadu Pirea (NXP OSS) }
365b050f2f1SRadu Pirea (NXP OSS) 
366b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_check_delay(struct phy_device *phydev, u32 delay)
367b050f2f1SRadu Pirea (NXP OSS) {
368b050f2f1SRadu Pirea (NXP OSS) 	if (delay < MIN_ID_PS) {
369b050f2f1SRadu Pirea (NXP OSS) 		phydev_err(phydev, "delay value smaller than %u\n", MIN_ID_PS);
370b050f2f1SRadu Pirea (NXP OSS) 		return -EINVAL;
371b050f2f1SRadu Pirea (NXP OSS) 	}
372b050f2f1SRadu Pirea (NXP OSS) 
373b050f2f1SRadu Pirea (NXP OSS) 	if (delay > MAX_ID_PS) {
374b050f2f1SRadu Pirea (NXP OSS) 		phydev_err(phydev, "delay value higher than %u\n", MAX_ID_PS);
375b050f2f1SRadu Pirea (NXP OSS) 		return -EINVAL;
376b050f2f1SRadu Pirea (NXP OSS) 	}
377b050f2f1SRadu Pirea (NXP OSS) 
378b050f2f1SRadu Pirea (NXP OSS) 	return 0;
379b050f2f1SRadu Pirea (NXP OSS) }
380b050f2f1SRadu Pirea (NXP OSS) 
381b050f2f1SRadu Pirea (NXP OSS) static u64 nxp_c45_get_phase_shift(u64 phase_offset_raw)
382b050f2f1SRadu Pirea (NXP OSS) {
383b050f2f1SRadu Pirea (NXP OSS) 	/* The delay in degree phase is 73.8 + phase_offset_raw * 0.9.
384b050f2f1SRadu Pirea (NXP OSS) 	 * To avoid floating point operations we'll multiply by 10
385b050f2f1SRadu Pirea (NXP OSS) 	 * and get 1 decimal point precision.
386b050f2f1SRadu Pirea (NXP OSS) 	 */
387b050f2f1SRadu Pirea (NXP OSS) 	phase_offset_raw *= 10;
3886b3a6310SRadu Pirea (NXP OSS) 	phase_offset_raw -= 738;
389b050f2f1SRadu Pirea (NXP OSS) 	return div_u64(phase_offset_raw, 9);
390b050f2f1SRadu Pirea (NXP OSS) }
391b050f2f1SRadu Pirea (NXP OSS) 
392b050f2f1SRadu Pirea (NXP OSS) static void nxp_c45_disable_delays(struct phy_device *phydev)
393b050f2f1SRadu Pirea (NXP OSS) {
394b050f2f1SRadu Pirea (NXP OSS) 	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TXID, ID_ENABLE);
395b050f2f1SRadu Pirea (NXP OSS) 	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RXID, ID_ENABLE);
396b050f2f1SRadu Pirea (NXP OSS) }
397b050f2f1SRadu Pirea (NXP OSS) 
398b050f2f1SRadu Pirea (NXP OSS) static void nxp_c45_set_delays(struct phy_device *phydev)
399b050f2f1SRadu Pirea (NXP OSS) {
400b050f2f1SRadu Pirea (NXP OSS) 	struct nxp_c45_phy *priv = phydev->priv;
401b050f2f1SRadu Pirea (NXP OSS) 	u64 tx_delay = priv->tx_delay;
402b050f2f1SRadu Pirea (NXP OSS) 	u64 rx_delay = priv->rx_delay;
403b050f2f1SRadu Pirea (NXP OSS) 	u64 degree;
404b050f2f1SRadu Pirea (NXP OSS) 
405b050f2f1SRadu Pirea (NXP OSS) 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
406b050f2f1SRadu Pirea (NXP OSS) 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
407b050f2f1SRadu Pirea (NXP OSS) 		degree = div_u64(tx_delay, PS_PER_DEGREE);
408b050f2f1SRadu Pirea (NXP OSS) 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_TXID,
409b050f2f1SRadu Pirea (NXP OSS) 			      ID_ENABLE | nxp_c45_get_phase_shift(degree));
410b050f2f1SRadu Pirea (NXP OSS) 	} else {
411b050f2f1SRadu Pirea (NXP OSS) 		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TXID,
412b050f2f1SRadu Pirea (NXP OSS) 				   ID_ENABLE);
413b050f2f1SRadu Pirea (NXP OSS) 	}
414b050f2f1SRadu Pirea (NXP OSS) 
415b050f2f1SRadu Pirea (NXP OSS) 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
416b050f2f1SRadu Pirea (NXP OSS) 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
417b050f2f1SRadu Pirea (NXP OSS) 		degree = div_u64(rx_delay, PS_PER_DEGREE);
418b050f2f1SRadu Pirea (NXP OSS) 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RXID,
419b050f2f1SRadu Pirea (NXP OSS) 			      ID_ENABLE | nxp_c45_get_phase_shift(degree));
420b050f2f1SRadu Pirea (NXP OSS) 	} else {
421b050f2f1SRadu Pirea (NXP OSS) 		phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RXID,
422b050f2f1SRadu Pirea (NXP OSS) 				   ID_ENABLE);
423b050f2f1SRadu Pirea (NXP OSS) 	}
424b050f2f1SRadu Pirea (NXP OSS) }
425b050f2f1SRadu Pirea (NXP OSS) 
426b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_get_delays(struct phy_device *phydev)
427b050f2f1SRadu Pirea (NXP OSS) {
428b050f2f1SRadu Pirea (NXP OSS) 	struct nxp_c45_phy *priv = phydev->priv;
429b050f2f1SRadu Pirea (NXP OSS) 	int ret;
430b050f2f1SRadu Pirea (NXP OSS) 
431b050f2f1SRadu Pirea (NXP OSS) 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
432b050f2f1SRadu Pirea (NXP OSS) 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
433b050f2f1SRadu Pirea (NXP OSS) 		ret = device_property_read_u32(&phydev->mdio.dev,
434b050f2f1SRadu Pirea (NXP OSS) 					       "tx-internal-delay-ps",
435b050f2f1SRadu Pirea (NXP OSS) 					       &priv->tx_delay);
436b050f2f1SRadu Pirea (NXP OSS) 		if (ret)
437b050f2f1SRadu Pirea (NXP OSS) 			priv->tx_delay = DEFAULT_ID_PS;
438b050f2f1SRadu Pirea (NXP OSS) 
439b050f2f1SRadu Pirea (NXP OSS) 		ret = nxp_c45_check_delay(phydev, priv->tx_delay);
440b050f2f1SRadu Pirea (NXP OSS) 		if (ret) {
441b050f2f1SRadu Pirea (NXP OSS) 			phydev_err(phydev,
442b050f2f1SRadu Pirea (NXP OSS) 				   "tx-internal-delay-ps invalid value\n");
443b050f2f1SRadu Pirea (NXP OSS) 			return ret;
444b050f2f1SRadu Pirea (NXP OSS) 		}
445b050f2f1SRadu Pirea (NXP OSS) 	}
446b050f2f1SRadu Pirea (NXP OSS) 
447b050f2f1SRadu Pirea (NXP OSS) 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
448b050f2f1SRadu Pirea (NXP OSS) 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
449b050f2f1SRadu Pirea (NXP OSS) 		ret = device_property_read_u32(&phydev->mdio.dev,
450b050f2f1SRadu Pirea (NXP OSS) 					       "rx-internal-delay-ps",
451b050f2f1SRadu Pirea (NXP OSS) 					       &priv->rx_delay);
452b050f2f1SRadu Pirea (NXP OSS) 		if (ret)
453b050f2f1SRadu Pirea (NXP OSS) 			priv->rx_delay = DEFAULT_ID_PS;
454b050f2f1SRadu Pirea (NXP OSS) 
455b050f2f1SRadu Pirea (NXP OSS) 		ret = nxp_c45_check_delay(phydev, priv->rx_delay);
456b050f2f1SRadu Pirea (NXP OSS) 		if (ret) {
457b050f2f1SRadu Pirea (NXP OSS) 			phydev_err(phydev,
458b050f2f1SRadu Pirea (NXP OSS) 				   "rx-internal-delay-ps invalid value\n");
459b050f2f1SRadu Pirea (NXP OSS) 			return ret;
460b050f2f1SRadu Pirea (NXP OSS) 		}
461b050f2f1SRadu Pirea (NXP OSS) 	}
462b050f2f1SRadu Pirea (NXP OSS) 
463b050f2f1SRadu Pirea (NXP OSS) 	return 0;
464b050f2f1SRadu Pirea (NXP OSS) }
465b050f2f1SRadu Pirea (NXP OSS) 
466b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_set_phy_mode(struct phy_device *phydev)
467b050f2f1SRadu Pirea (NXP OSS) {
468b050f2f1SRadu Pirea (NXP OSS) 	int ret;
469b050f2f1SRadu Pirea (NXP OSS) 
470b050f2f1SRadu Pirea (NXP OSS) 	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_ABILITIES);
471b050f2f1SRadu Pirea (NXP OSS) 	phydev_dbg(phydev, "Clause 45 managed PHY abilities 0x%x\n", ret);
472b050f2f1SRadu Pirea (NXP OSS) 
473b050f2f1SRadu Pirea (NXP OSS) 	switch (phydev->interface) {
474b050f2f1SRadu Pirea (NXP OSS) 	case PHY_INTERFACE_MODE_RGMII:
475b050f2f1SRadu Pirea (NXP OSS) 		if (!(ret & RGMII_ABILITY)) {
476b050f2f1SRadu Pirea (NXP OSS) 			phydev_err(phydev, "rgmii mode not supported\n");
477b050f2f1SRadu Pirea (NXP OSS) 			return -EINVAL;
478b050f2f1SRadu Pirea (NXP OSS) 		}
479b050f2f1SRadu Pirea (NXP OSS) 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG,
480b050f2f1SRadu Pirea (NXP OSS) 			      MII_BASIC_CONFIG_RGMII);
481b050f2f1SRadu Pirea (NXP OSS) 		nxp_c45_disable_delays(phydev);
482b050f2f1SRadu Pirea (NXP OSS) 		break;
483b050f2f1SRadu Pirea (NXP OSS) 	case PHY_INTERFACE_MODE_RGMII_ID:
484b050f2f1SRadu Pirea (NXP OSS) 	case PHY_INTERFACE_MODE_RGMII_TXID:
485b050f2f1SRadu Pirea (NXP OSS) 	case PHY_INTERFACE_MODE_RGMII_RXID:
486b050f2f1SRadu Pirea (NXP OSS) 		if (!(ret & RGMII_ID_ABILITY)) {
487b050f2f1SRadu Pirea (NXP OSS) 			phydev_err(phydev, "rgmii-id, rgmii-txid, rgmii-rxid modes are not supported\n");
488b050f2f1SRadu Pirea (NXP OSS) 			return -EINVAL;
489b050f2f1SRadu Pirea (NXP OSS) 		}
490b050f2f1SRadu Pirea (NXP OSS) 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG,
491b050f2f1SRadu Pirea (NXP OSS) 			      MII_BASIC_CONFIG_RGMII);
492b050f2f1SRadu Pirea (NXP OSS) 		ret = nxp_c45_get_delays(phydev);
493b050f2f1SRadu Pirea (NXP OSS) 		if (ret)
494b050f2f1SRadu Pirea (NXP OSS) 			return ret;
495b050f2f1SRadu Pirea (NXP OSS) 
496b050f2f1SRadu Pirea (NXP OSS) 		nxp_c45_set_delays(phydev);
497b050f2f1SRadu Pirea (NXP OSS) 		break;
498b050f2f1SRadu Pirea (NXP OSS) 	case PHY_INTERFACE_MODE_MII:
499b050f2f1SRadu Pirea (NXP OSS) 		if (!(ret & MII_ABILITY)) {
500b050f2f1SRadu Pirea (NXP OSS) 			phydev_err(phydev, "mii mode not supported\n");
501b050f2f1SRadu Pirea (NXP OSS) 			return -EINVAL;
502b050f2f1SRadu Pirea (NXP OSS) 		}
503b050f2f1SRadu Pirea (NXP OSS) 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG,
504b050f2f1SRadu Pirea (NXP OSS) 			      MII_BASIC_CONFIG_MII);
505b050f2f1SRadu Pirea (NXP OSS) 		break;
506b050f2f1SRadu Pirea (NXP OSS) 	case PHY_INTERFACE_MODE_REVMII:
507b050f2f1SRadu Pirea (NXP OSS) 		if (!(ret & REVMII_ABILITY)) {
508b050f2f1SRadu Pirea (NXP OSS) 			phydev_err(phydev, "rev-mii mode not supported\n");
509b050f2f1SRadu Pirea (NXP OSS) 			return -EINVAL;
510b050f2f1SRadu Pirea (NXP OSS) 		}
511b050f2f1SRadu Pirea (NXP OSS) 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG,
512b050f2f1SRadu Pirea (NXP OSS) 			      MII_BASIC_CONFIG_MII | MII_BASIC_CONFIG_REV);
513b050f2f1SRadu Pirea (NXP OSS) 		break;
514b050f2f1SRadu Pirea (NXP OSS) 	case PHY_INTERFACE_MODE_RMII:
515b050f2f1SRadu Pirea (NXP OSS) 		if (!(ret & RMII_ABILITY)) {
516b050f2f1SRadu Pirea (NXP OSS) 			phydev_err(phydev, "rmii mode not supported\n");
517b050f2f1SRadu Pirea (NXP OSS) 			return -EINVAL;
518b050f2f1SRadu Pirea (NXP OSS) 		}
519b050f2f1SRadu Pirea (NXP OSS) 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG,
520b050f2f1SRadu Pirea (NXP OSS) 			      MII_BASIC_CONFIG_RMII);
521b050f2f1SRadu Pirea (NXP OSS) 		break;
522b050f2f1SRadu Pirea (NXP OSS) 	case PHY_INTERFACE_MODE_SGMII:
523b050f2f1SRadu Pirea (NXP OSS) 		if (!(ret & SGMII_ABILITY)) {
524b050f2f1SRadu Pirea (NXP OSS) 			phydev_err(phydev, "sgmii mode not supported\n");
525b050f2f1SRadu Pirea (NXP OSS) 			return -EINVAL;
526b050f2f1SRadu Pirea (NXP OSS) 		}
527b050f2f1SRadu Pirea (NXP OSS) 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG,
528b050f2f1SRadu Pirea (NXP OSS) 			      MII_BASIC_CONFIG_SGMII);
529b050f2f1SRadu Pirea (NXP OSS) 		break;
530b050f2f1SRadu Pirea (NXP OSS) 	case PHY_INTERFACE_MODE_INTERNAL:
531b050f2f1SRadu Pirea (NXP OSS) 		break;
532b050f2f1SRadu Pirea (NXP OSS) 	default:
533b050f2f1SRadu Pirea (NXP OSS) 		return -EINVAL;
534b050f2f1SRadu Pirea (NXP OSS) 	}
535b050f2f1SRadu Pirea (NXP OSS) 
536b050f2f1SRadu Pirea (NXP OSS) 	return 0;
537b050f2f1SRadu Pirea (NXP OSS) }
538b050f2f1SRadu Pirea (NXP OSS) 
539b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_config_init(struct phy_device *phydev)
540b050f2f1SRadu Pirea (NXP OSS) {
541b050f2f1SRadu Pirea (NXP OSS) 	int ret;
542b050f2f1SRadu Pirea (NXP OSS) 
543b050f2f1SRadu Pirea (NXP OSS) 	ret = nxp_c45_config_enable(phydev);
544b050f2f1SRadu Pirea (NXP OSS) 	if (ret) {
545b050f2f1SRadu Pirea (NXP OSS) 		phydev_err(phydev, "Failed to enable config\n");
546b050f2f1SRadu Pirea (NXP OSS) 		return ret;
547b050f2f1SRadu Pirea (NXP OSS) 	}
548b050f2f1SRadu Pirea (NXP OSS) 
549b050f2f1SRadu Pirea (NXP OSS) 	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONFIG,
550b050f2f1SRadu Pirea (NXP OSS) 			 PHY_CONFIG_AUTO);
551b050f2f1SRadu Pirea (NXP OSS) 
552b050f2f1SRadu Pirea (NXP OSS) 	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_LINK_DROP_COUNTER,
553b050f2f1SRadu Pirea (NXP OSS) 			 COUNTER_EN);
554b050f2f1SRadu Pirea (NXP OSS) 	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_PREAMBLE_COUNT,
555b050f2f1SRadu Pirea (NXP OSS) 			 COUNTER_EN);
556b050f2f1SRadu Pirea (NXP OSS) 	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TX_PREAMBLE_COUNT,
557b050f2f1SRadu Pirea (NXP OSS) 			 COUNTER_EN);
558b050f2f1SRadu Pirea (NXP OSS) 	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_IPG_LENGTH,
559b050f2f1SRadu Pirea (NXP OSS) 			 COUNTER_EN);
560b050f2f1SRadu Pirea (NXP OSS) 	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TX_IPG_LENGTH,
561b050f2f1SRadu Pirea (NXP OSS) 			 COUNTER_EN);
562b050f2f1SRadu Pirea (NXP OSS) 
563b050f2f1SRadu Pirea (NXP OSS) 	ret = nxp_c45_set_phy_mode(phydev);
564b050f2f1SRadu Pirea (NXP OSS) 	if (ret)
565b050f2f1SRadu Pirea (NXP OSS) 		return ret;
566b050f2f1SRadu Pirea (NXP OSS) 
567b050f2f1SRadu Pirea (NXP OSS) 	phydev->autoneg = AUTONEG_DISABLE;
568b050f2f1SRadu Pirea (NXP OSS) 
569b050f2f1SRadu Pirea (NXP OSS) 	return nxp_c45_start_op(phydev);
570b050f2f1SRadu Pirea (NXP OSS) }
571b050f2f1SRadu Pirea (NXP OSS) 
572b050f2f1SRadu Pirea (NXP OSS) static int nxp_c45_probe(struct phy_device *phydev)
573b050f2f1SRadu Pirea (NXP OSS) {
574b050f2f1SRadu Pirea (NXP OSS) 	struct nxp_c45_phy *priv;
575b050f2f1SRadu Pirea (NXP OSS) 
576b050f2f1SRadu Pirea (NXP OSS) 	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
577b050f2f1SRadu Pirea (NXP OSS) 	if (!priv)
578b050f2f1SRadu Pirea (NXP OSS) 		return -ENOMEM;
579b050f2f1SRadu Pirea (NXP OSS) 
580b050f2f1SRadu Pirea (NXP OSS) 	phydev->priv = priv;
581b050f2f1SRadu Pirea (NXP OSS) 
582b050f2f1SRadu Pirea (NXP OSS) 	return 0;
583b050f2f1SRadu Pirea (NXP OSS) }
584b050f2f1SRadu Pirea (NXP OSS) 
585b050f2f1SRadu Pirea (NXP OSS) static struct phy_driver nxp_c45_driver[] = {
586b050f2f1SRadu Pirea (NXP OSS) 	{
587b050f2f1SRadu Pirea (NXP OSS) 		PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103),
588b050f2f1SRadu Pirea (NXP OSS) 		.name			= "NXP C45 TJA1103",
589b050f2f1SRadu Pirea (NXP OSS) 		.features		= PHY_BASIC_T1_FEATURES,
590b050f2f1SRadu Pirea (NXP OSS) 		.probe			= nxp_c45_probe,
591b050f2f1SRadu Pirea (NXP OSS) 		.soft_reset		= nxp_c45_soft_reset,
592b050f2f1SRadu Pirea (NXP OSS) 		.config_aneg		= nxp_c45_config_aneg,
593b050f2f1SRadu Pirea (NXP OSS) 		.config_init		= nxp_c45_config_init,
594*b2f0ca00SRadu Pirea (NXP OSS) 		.config_intr		= nxp_c45_config_intr,
595*b2f0ca00SRadu Pirea (NXP OSS) 		.handle_interrupt	= nxp_c45_handle_interrupt,
596b050f2f1SRadu Pirea (NXP OSS) 		.read_status		= nxp_c45_read_status,
597b050f2f1SRadu Pirea (NXP OSS) 		.suspend		= genphy_c45_pma_suspend,
598b050f2f1SRadu Pirea (NXP OSS) 		.resume			= genphy_c45_pma_resume,
599b050f2f1SRadu Pirea (NXP OSS) 		.get_sset_count		= nxp_c45_get_sset_count,
600b050f2f1SRadu Pirea (NXP OSS) 		.get_strings		= nxp_c45_get_strings,
601b050f2f1SRadu Pirea (NXP OSS) 		.get_stats		= nxp_c45_get_stats,
602b050f2f1SRadu Pirea (NXP OSS) 		.cable_test_start	= nxp_c45_cable_test_start,
603b050f2f1SRadu Pirea (NXP OSS) 		.cable_test_get_status	= nxp_c45_cable_test_get_status,
604b050f2f1SRadu Pirea (NXP OSS) 		.set_loopback		= genphy_c45_loopback,
605b050f2f1SRadu Pirea (NXP OSS) 		.get_sqi		= nxp_c45_get_sqi,
606b050f2f1SRadu Pirea (NXP OSS) 		.get_sqi_max		= nxp_c45_get_sqi_max,
607b050f2f1SRadu Pirea (NXP OSS) 	},
608b050f2f1SRadu Pirea (NXP OSS) };
609b050f2f1SRadu Pirea (NXP OSS) 
610b050f2f1SRadu Pirea (NXP OSS) module_phy_driver(nxp_c45_driver);
611b050f2f1SRadu Pirea (NXP OSS) 
612b050f2f1SRadu Pirea (NXP OSS) static struct mdio_device_id __maybe_unused nxp_c45_tbl[] = {
613b050f2f1SRadu Pirea (NXP OSS) 	{ PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103) },
614b050f2f1SRadu Pirea (NXP OSS) 	{ /*sentinel*/ },
615b050f2f1SRadu Pirea (NXP OSS) };
616b050f2f1SRadu Pirea (NXP OSS) 
617b050f2f1SRadu Pirea (NXP OSS) MODULE_DEVICE_TABLE(mdio, nxp_c45_tbl);
618b050f2f1SRadu Pirea (NXP OSS) 
619b050f2f1SRadu Pirea (NXP OSS) MODULE_AUTHOR("Radu Pirea <radu-nicolae.pirea@oss.nxp.com>");
620b050f2f1SRadu Pirea (NXP OSS) MODULE_DESCRIPTION("NXP C45 PHY driver");
621b050f2f1SRadu Pirea (NXP OSS) MODULE_LICENSE("GPL v2");
622