1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * NXP C45 PHY driver
4  *
5  * Copyright 2021 NXP
6  * Author: Radu Pirea <radu-nicolae.pirea@oss.nxp.com>
7  */
8 #include <common.h>
9 #include <dm.h>
10 #include <dm/devres.h>
11 #include <linux/delay.h>
12 #include <linux/math64.h>
13 #include <linux/mdio.h>
14 #include <phy.h>
15 
16 #define PHY_ID_TJA_1103			0x001BB010
17 
18 #define VEND1_DEVICE_CONTROL		0x0040
19 #define DEVICE_CONTROL_RESET		BIT(15)
20 #define DEVICE_CONTROL_CONFIG_GLOBAL_EN	BIT(14)
21 #define DEVICE_CONTROL_CONFIG_ALL_EN	BIT(13)
22 
23 #define VEND1_PORT_CONTROL		0x8040
24 #define PORT_CONTROL_EN			BIT(14)
25 
26 #define VEND1_PHY_CONTROL		0x8100
27 #define PHY_CONFIG_EN			BIT(14)
28 #define PHY_START_OP			BIT(0)
29 
30 #define VEND1_PHY_CONFIG		0x8108
31 #define PHY_CONFIG_AUTO			BIT(0)
32 
33 #define VEND1_PORT_INFRA_CONTROL	0xAC00
34 #define PORT_INFRA_CONTROL_EN		BIT(14)
35 
36 #define VEND1_RXID			0xAFCC
37 #define VEND1_TXID			0xAFCD
38 #define ID_ENABLE			BIT(15)
39 
40 #define VEND1_ABILITIES			0xAFC4
41 #define RGMII_ID_ABILITY		BIT(15)
42 #define RGMII_ABILITY			BIT(14)
43 #define RMII_ABILITY			BIT(10)
44 #define REVMII_ABILITY			BIT(9)
45 #define MII_ABILITY			BIT(8)
46 #define SGMII_ABILITY			BIT(0)
47 
48 #define VEND1_MII_BASIC_CONFIG		0xAFC6
49 #define MII_BASIC_CONFIG_REV		BIT(8)
50 #define MII_BASIC_CONFIG_SGMII		0x9
51 #define MII_BASIC_CONFIG_RGMII		0x7
52 #define MII_BASIC_CONFIG_RMII		0x5
53 #define MII_BASIC_CONFIG_MII		0x4
54 
55 #define RGMII_PERIOD_PS			8000U
56 #define PS_PER_DEGREE			div_u64(RGMII_PERIOD_PS, 360)
57 #define MIN_ID_PS			1644U
58 #define MAX_ID_PS			2260U
59 #define DEFAULT_ID_PS			2000U
60 
61 #define RESET_DELAY_MS			25
62 #define CONF_EN_DELAY_US		450
63 
64 struct nxp_c45_phy {
65 	u32 tx_delay;
66 	u32 rx_delay;
67 };
68 
nxp_c45_soft_reset(struct phy_device * phydev)69 static int nxp_c45_soft_reset(struct phy_device *phydev)
70 {
71 	int tries = 10, ret;
72 
73 	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_CONTROL,
74 			    DEVICE_CONTROL_RESET);
75 	if (ret)
76 		return ret;
77 
78 	do {
79 		ret = phy_read_mmd(phydev, MDIO_MMD_VEND1,
80 				   VEND1_DEVICE_CONTROL);
81 		if (!(ret & DEVICE_CONTROL_RESET))
82 			return 0;
83 		mdelay(RESET_DELAY_MS);
84 	} while (tries--);
85 
86 	return -EIO;
87 }
88 
nxp_c45_start_op(struct phy_device * phydev)89 static int nxp_c45_start_op(struct phy_device *phydev)
90 {
91 	return phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONTROL,
92 			     PHY_START_OP);
93 }
94 
nxp_c45_config_enable(struct phy_device * phydev)95 static int nxp_c45_config_enable(struct phy_device *phydev)
96 {
97 	phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_CONTROL,
98 		      DEVICE_CONTROL_CONFIG_GLOBAL_EN |
99 		      DEVICE_CONTROL_CONFIG_ALL_EN);
100 	udelay(CONF_EN_DELAY_US);
101 
102 	phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_CONTROL,
103 		      PORT_CONTROL_EN);
104 	phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONTROL,
105 		      PHY_CONFIG_EN);
106 	phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_INFRA_CONTROL,
107 		      PORT_INFRA_CONTROL_EN);
108 
109 	return 0;
110 }
111 
nxp_c45_get_phase_shift(u64 phase_offset_raw)112 static u64 nxp_c45_get_phase_shift(u64 phase_offset_raw)
113 {
114 	/* The delay in degree phase is 73.8 + phase_offset_raw * 0.9.
115 	 * To avoid floating point operations we'll multiply by 10
116 	 * and get 1 decimal point precision.
117 	 */
118 	phase_offset_raw *= 10;
119 	phase_offset_raw -= 738;
120 	return div_u64(phase_offset_raw, 9);
121 }
122 
nxp_c45_disable_delays(struct phy_device * phydev)123 static void nxp_c45_disable_delays(struct phy_device *phydev)
124 {
125 	phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_TXID, 0);
126 	phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RXID, 0);
127 }
128 
nxp_c45_check_delay(struct phy_device * phydev,u32 delay)129 static int nxp_c45_check_delay(struct phy_device *phydev, u32 delay)
130 {
131 	if (delay < MIN_ID_PS) {
132 		pr_err("%s: delay value smaller than %u\n",
133 		       phydev->drv->name, MIN_ID_PS);
134 		return -EINVAL;
135 	}
136 
137 	if (delay > MAX_ID_PS) {
138 		pr_err("%s: delay value higher than %u\n",
139 		       phydev->drv->name, MAX_ID_PS);
140 		return -EINVAL;
141 	}
142 
143 	return 0;
144 }
145 
nxp_c45_get_delays(struct phy_device * phydev)146 static int nxp_c45_get_delays(struct phy_device *phydev)
147 {
148 	struct nxp_c45_phy *priv = phydev->priv;
149 	int ret;
150 
151 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
152 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
153 		ret = dev_read_u32(phydev->dev, "tx-internal-delay-ps",
154 				   &priv->tx_delay);
155 		if (ret)
156 			priv->tx_delay = DEFAULT_ID_PS;
157 
158 		ret = nxp_c45_check_delay(phydev, priv->tx_delay);
159 		if (ret) {
160 			pr_err("%s: tx-internal-delay-ps invalid value\n",
161 			       phydev->drv->name);
162 			return ret;
163 		}
164 	}
165 
166 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
167 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
168 		ret = dev_read_u32(phydev->dev, "rx-internal-delay-ps",
169 				   &priv->rx_delay);
170 		if (ret)
171 			priv->rx_delay = DEFAULT_ID_PS;
172 
173 		ret = nxp_c45_check_delay(phydev, priv->rx_delay);
174 		if (ret) {
175 			pr_err("%s: rx-internal-delay-ps invalid value\n",
176 			       phydev->drv->name);
177 			return ret;
178 		}
179 	}
180 
181 	return 0;
182 }
183 
nxp_c45_set_delays(struct phy_device * phydev)184 static void nxp_c45_set_delays(struct phy_device *phydev)
185 {
186 	struct nxp_c45_phy *priv = phydev->priv;
187 	u64 tx_delay = priv->tx_delay;
188 	u64 rx_delay = priv->rx_delay;
189 	u64 degree;
190 
191 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
192 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
193 		degree = div_u64(tx_delay, PS_PER_DEGREE);
194 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_TXID,
195 			      ID_ENABLE | nxp_c45_get_phase_shift(degree));
196 	} else {
197 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_TXID, 0);
198 	}
199 
200 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
201 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
202 		degree = div_u64(rx_delay, PS_PER_DEGREE);
203 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RXID,
204 			      ID_ENABLE | nxp_c45_get_phase_shift(degree));
205 	} else {
206 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RXID, 0);
207 	}
208 }
209 
nxp_c45_set_phy_mode(struct phy_device * phydev)210 static int nxp_c45_set_phy_mode(struct phy_device *phydev)
211 {
212 	int ret;
213 
214 	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_ABILITIES);
215 	pr_debug("%s: Clause 45 managed PHY abilities 0x%x\n",
216 		 phydev->drv->name, ret);
217 
218 	switch (phydev->interface) {
219 	case PHY_INTERFACE_MODE_RGMII:
220 		if (!(ret & RGMII_ABILITY)) {
221 			pr_err("%s: rgmii mode not supported\n",
222 			       phydev->drv->name);
223 			return -EINVAL;
224 		}
225 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG,
226 			      MII_BASIC_CONFIG_RGMII);
227 		nxp_c45_disable_delays(phydev);
228 		break;
229 	case PHY_INTERFACE_MODE_RGMII_ID:
230 	case PHY_INTERFACE_MODE_RGMII_TXID:
231 	case PHY_INTERFACE_MODE_RGMII_RXID:
232 		if (!(ret & RGMII_ID_ABILITY)) {
233 			pr_err("%s: rgmii-id, rgmii-txid, rgmii-rxid modes are not supported\n",
234 			       phydev->drv->name);
235 			return -EINVAL;
236 		}
237 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG,
238 			      MII_BASIC_CONFIG_RGMII);
239 		ret = nxp_c45_get_delays(phydev);
240 		if (ret)
241 			return ret;
242 
243 		nxp_c45_set_delays(phydev);
244 		break;
245 	case PHY_INTERFACE_MODE_MII:
246 		if (!(ret & MII_ABILITY)) {
247 			pr_err("%s: mii mode not supported\n",
248 			       phydev->drv->name);
249 			return -EINVAL;
250 		}
251 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG,
252 			      MII_BASIC_CONFIG_MII);
253 		break;
254 	case PHY_INTERFACE_MODE_RMII:
255 		if (!(ret & RMII_ABILITY)) {
256 			pr_err("%s: rmii mode not supported\n",
257 			       phydev->drv->name);
258 			return -EINVAL;
259 		}
260 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG,
261 			      MII_BASIC_CONFIG_RMII);
262 		break;
263 	case PHY_INTERFACE_MODE_SGMII:
264 		if (!(ret & SGMII_ABILITY)) {
265 			pr_err("%s: sgmii mode not supported\n",
266 			       phydev->drv->name);
267 			return -EINVAL;
268 		}
269 		phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG,
270 			      MII_BASIC_CONFIG_SGMII);
271 		break;
272 	case PHY_INTERFACE_MODE_INTERNAL:
273 		break;
274 	default:
275 		return -EINVAL;
276 	}
277 
278 	return 0;
279 }
280 
nxp_c45_config(struct phy_device * phydev)281 static int nxp_c45_config(struct phy_device *phydev)
282 {
283 	int ret;
284 
285 	ret = nxp_c45_soft_reset(phydev);
286 	if (ret)
287 		return ret;
288 
289 	ret = nxp_c45_config_enable(phydev);
290 	if (ret) {
291 		pr_err("%s: Failed to enable config\n", phydev->drv->name);
292 		return ret;
293 	}
294 
295 	phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONFIG,
296 		      PHY_CONFIG_AUTO);
297 
298 	ret = nxp_c45_set_phy_mode(phydev);
299 	if (ret) {
300 		pr_err("%s: Failed to set phy mode\n", phydev->drv->name);
301 		return ret;
302 	}
303 
304 	phydev->autoneg = AUTONEG_DISABLE;
305 
306 	return nxp_c45_start_op(phydev);
307 }
308 
nxp_c45_startup(struct phy_device * phydev)309 static int nxp_c45_startup(struct phy_device *phydev)
310 {
311 	u32 reg;
312 
313 	reg = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT1);
314 	phydev->link = !!(reg & MDIO_STAT1_LSTATUS);
315 	phydev->speed = SPEED_100;
316 	phydev->duplex = DUPLEX_FULL;
317 	return 0;
318 }
319 
nxp_c45_probe(struct phy_device * phydev)320 static int nxp_c45_probe(struct phy_device *phydev)
321 {
322 	struct nxp_c45_phy *priv;
323 
324 	priv = devm_kzalloc(phydev->priv, sizeof(*priv), GFP_KERNEL);
325 	if (!priv)
326 		return -ENOMEM;
327 
328 	phydev->priv = priv;
329 
330 	return 0;
331 }
332 
333 static struct phy_driver nxp_tja11xx = {
334 	.name = "NXP C45 TJA1103",
335 	.uid  = PHY_ID_TJA_1103,
336 	.mask = 0xfffff0,
337 	.features = PHY_100BT1_FEATURES,
338 	.probe = &nxp_c45_probe,
339 	.config = &nxp_c45_config,
340 	.startup = &nxp_c45_startup,
341 	.shutdown = &genphy_shutdown,
342 };
343 
phy_nxp_tja11xx_init(void)344 int phy_nxp_tja11xx_init(void)
345 {
346 	phy_register(&nxp_tja11xx);
347 	return 0;
348 }
349