1 #ifndef PHY_CYCLONEV_SRC
2 #define PHY_CYCLONEV_SRC
3 /*
4  * SPDX-License-Identifier: Apache-2.0
5  * Copyright (C) 2022, Intel Corporation
6  * Description:
7  * Driver for the PHY KSZ9021RL/RN Datasheet:(https://ww1.microchip.com/
8  * downloads/en/DeviceDoc/KSZ9021RL-RN-Data-Sheet-DS00003050A.pdf)
9  * specifically designed for Cyclone V SoC DevKit use only.
10  */
11 
12 /* PHY */
13 /* According to default Cyclone V DevKit Bootstrap Encoding Scheme */
14 #include "eth_cyclonev_priv.h"
15 
16 #include <stdio.h>
17 
18 #include <zephyr/kernel.h>
19 
20 #include <sys/types.h>
21 
22 #define PHY_ADDR (4)
23 
24 /*  PHY_Read_write_Timeouts   */
25 #define PHY_READ_TO  ((uint32_t)0x0004FFFF)
26 #define PHY_WRITE_TO ((uint32_t)0x0004FFFF)
27 
28 /* Speed and Duplex mask values  */
29 #define PHY_SPEED_100  (0x0020)
30 #define PHY_SPEED_1000 (0x0040)
31 
32 #define PHY_CLK_AND_CONTROL_PAD_SKEW_VALUE 0xa0d0
33 #define PHY_RX_DATA_PAD_SKEW_VALUE	   0x0000
34 
35 /* Write/read to/from extended registers */
36 #define MII_KSZPHY_EXTREG	0x0b
37 #define KSZPHY_EXTREG_WRITE	0x8000
38 #define MII_KSZPHY_EXTREG_WRITE 0x0c
39 #define MII_KSZPHY_EXTREG_READ	0x0d
40 
41 /* PHY Regs */
42 
43 /* Basic Control Register */
44 #define PHY_BCR			    (0)
45 #define PHY_RESET		    BIT(15) /* Do a PHY reset */
46 #define PHY_AUTONEGOTIATION	    BIT(12)
47 #define PHY_RESTART_AUTONEGOTIATION BIT(9)
48 
49 /* Basic Status Register */
50 #define PHY_BSR		      BIT(0)
51 #define PHY_AUTOCAP	      BIT(3) /* Auto-negotiation capability */
52 #define PHY_LINKED_STATUS     BIT(2)
53 #define PHY_AUTONEGO_COMPLETE BIT(5)
54 
55 /* Auto-Negotiation Advertisement */
56 #define PHY_AUTON	   (4)
57 #define PHYANA_10BASET	   BIT(5)
58 #define PHYANA_10BASETFD   BIT(6)
59 #define PHYANA_100BASETX   BIT(7)
60 #define PHYANA_100BASETXFD BIT(8)
61 #define PHYSYMETRIC_PAUSE  BIT(10)
62 #define PHYASYMETRIC_PAUSE BIT(11)
63 
64 /* 1000Base-T Control */
65 #define PHY_1GCTL (9)
66 #define PHYADVERTISE_1000HALF BIT(8)
67 #define PHYADVERTISE_1000FULL BIT(9)
68 #define PHYINDICATE_PORTTYPE  BIT(10)
69 #define PHYCONFIG_MASTER      BIT(11)
70 #define PHYENABLE_MANUALCONFIG BIT(12)
71 
72 /* PHY Control Register */
73 #define PHY_CR		      (31)
74 #define PHY_DUPLEX_STATUS     BIT(3)
75 
76 /* Extended registers */
77 #define MII_KSZPHY_CLK_CONTROL_PAD_SKEW 0x104
78 #define MII_KSZPHY_RX_DATA_PAD_SKEW	0x105
79 #define MII_KSZPHY_TX_DATA_PAD_SKEW	0x106
80 
81 
82 int alt_eth_phy_write_register(uint16_t emac_instance, uint16_t phy_reg,
83 		uint16_t phy_value, struct eth_cyclonev_priv *p);
84 int alt_eth_phy_read_register(uint16_t emac_instance, uint16_t phy_reg,
85 		uint16_t *rdval, struct eth_cyclonev_priv *p);
86 int alt_eth_phy_write_register_extended(uint16_t emac_instance, uint16_t phy_reg,
87 		uint16_t phy_value, struct eth_cyclonev_priv *p);
88 int alt_eth_phy_read_register_extended(uint16_t emac_instance, uint16_t phy_reg,
89 		uint16_t *rdval, struct eth_cyclonev_priv *p);
90 int alt_eth_phy_config(uint16_t instance, struct eth_cyclonev_priv *p);
91 int alt_eth_phy_reset(uint16_t instance, struct eth_cyclonev_priv *p);
92 int alt_eth_phy_get_duplex_and_speed(uint16_t *phy_duplex_status, uint16_t *phy_speed,
93 				     uint16_t instance, struct eth_cyclonev_priv *p);
94 
alt_eth_phy_write_register(uint16_t emac_instance,uint16_t phy_reg,uint16_t phy_value,struct eth_cyclonev_priv * p)95 int alt_eth_phy_write_register(uint16_t emac_instance, uint16_t phy_reg,
96 		uint16_t phy_value, struct eth_cyclonev_priv *p)
97 {
98 	uint16_t tmpreg = 0;
99 	volatile uint32_t timeout = 0;
100 	uint16_t phy_addr;
101 
102 	if (emac_instance > 1) {
103 		return -1;
104 	}
105 
106 	phy_addr = PHY_ADDR;
107 
108 	/* Prepare the MII address register value */
109 	tmpreg = 0;
110 	/* Set the PHY device address */
111 	tmpreg |= EMAC_GMAC_GMII_ADDR_PA_SET(phy_addr);
112 	/* Set the PHY register address */
113 	tmpreg |= EMAC_GMAC_GMII_ADDR_GR_SET(phy_reg);
114 	/* Set the write mode */
115 	tmpreg |= EMAC_GMAC_GMII_ADDR_GW_SET_MSK;
116 	/* Set the clock divider */
117 	tmpreg |= EMAC_GMAC_GMII_ADDR_CR_SET(EMAC_GMAC_GMII_ADDR_CR_E_DIV102);
118 	/* Set the MII Busy bit */
119 	tmpreg |= EMAC_GMAC_GMII_ADDR_GB_SET(EMAC_GMAC_GMII_ADDR_GB_SET_MSK);
120 
121 	/* Give the value to the MII data register */
122 	sys_write32(phy_value & 0xffff, EMAC_GMAC_GMII_DATA_ADDR(p->base_addr));
123 	/* Write the result value into the MII Address register */
124 	sys_write32(tmpreg & 0xffff, EMAC_GMAC_GMII_ADDR_ADDR(p->base_addr));
125 
126 
127 	/* Check the Busy flag */
128 	do {
129 		timeout++;
130 		tmpreg = sys_read32(EMAC_GMAC_GMII_ADDR_ADDR(p->base_addr));
131 	} while ((tmpreg & EMAC_GMAC_GMII_ADDR_GB_SET_MSK) && (timeout < PHY_WRITE_TO));
132 
133 	/* Return ERROR in case of timeout */
134 	if (timeout == PHY_WRITE_TO) {
135 		return -1;
136 	}
137 
138 	/* Return SUCCESS */
139 	return 0;
140 }
141 
alt_eth_phy_read_register(uint16_t emac_instance,uint16_t phy_reg,uint16_t * rdval,struct eth_cyclonev_priv * p)142 int alt_eth_phy_read_register(uint16_t emac_instance, uint16_t phy_reg, uint16_t *rdval,
143 		struct eth_cyclonev_priv *p)
144 {
145 	uint16_t tmpreg = 0;
146 	volatile uint32_t timeout = 0;
147 	uint16_t phy_addr;
148 
149 	if (emac_instance > 1) {
150 		return -1;
151 	}
152 
153 	phy_addr = PHY_ADDR;
154 
155 	/* Prepare the MII address register value */
156 	tmpreg = 0;
157 	/* Set the PHY device address */
158 	tmpreg |= EMAC_GMAC_GMII_ADDR_PA_SET(phy_addr);
159 	/* Set the PHY register address */
160 	tmpreg |= EMAC_GMAC_GMII_ADDR_GR_SET(phy_reg);
161 	/* Set the read mode */
162 	tmpreg &= EMAC_GMAC_GMII_ADDR_GW_CLR_MSK;
163 	/* Set the clock divider */
164 	tmpreg |= EMAC_GMAC_GMII_ADDR_CR_SET(EMAC_GMAC_GMII_ADDR_CR_E_DIV102);
165 	/* Set the MII Busy bit */
166 	tmpreg |= EMAC_GMAC_GMII_ADDR_GB_SET(EMAC_GMAC_GMII_ADDR_GB_SET_MSK);
167 
168 	/* Write the result value into the MII Address register */
169 	sys_write32(tmpreg & 0xffff, EMAC_GMAC_GMII_ADDR_ADDR(p->base_addr));
170 
171 	/* Check the Busy flag */
172 	do {
173 		timeout++;
174 		tmpreg = sys_read32(EMAC_GMAC_GMII_ADDR_ADDR(p->base_addr));
175 	} while ((tmpreg & EMAC_GMAC_GMII_ADDR_GB_SET_MSK) && (timeout < PHY_READ_TO));
176 
177 	/* Return ERROR in case of timeout */
178 	if (timeout == PHY_READ_TO) {
179 		return -1;
180 	}
181 
182 	/* Return data register value */
183 	*rdval = sys_read32(EMAC_GMAC_GMII_DATA_ADDR(p->base_addr));
184 
185 	return 0;
186 }
187 
alt_eth_phy_write_register_extended(uint16_t emac_instance,uint16_t phy_reg,uint16_t phy_value,struct eth_cyclonev_priv * p)188 int alt_eth_phy_write_register_extended(uint16_t emac_instance, uint16_t phy_reg,
189 					uint16_t phy_value, struct eth_cyclonev_priv *p)
190 {
191 	int rc;
192 
193 	rc = alt_eth_phy_write_register(emac_instance, MII_KSZPHY_EXTREG,
194 					KSZPHY_EXTREG_WRITE | phy_reg, p);
195 
196 	if (rc == -1) {
197 		return rc;
198 	}
199 
200 	rc = alt_eth_phy_write_register(emac_instance, MII_KSZPHY_EXTREG_WRITE, phy_value, p);
201 	return rc;
202 }
203 
alt_eth_phy_read_register_extended(uint16_t emac_instance,uint16_t phy_reg,uint16_t * rdval,struct eth_cyclonev_priv * p)204 int alt_eth_phy_read_register_extended(uint16_t emac_instance, uint16_t phy_reg, uint16_t *rdval,
205 		struct eth_cyclonev_priv *p)
206 {
207 	int rc;
208 
209 	rc = alt_eth_phy_write_register(emac_instance, MII_KSZPHY_EXTREG, phy_reg, p);
210 
211 	if (rc == -1) {
212 		return rc;
213 	}
214 	k_sleep(K_MSEC(1));
215 
216 	rc = alt_eth_phy_read_register(emac_instance, MII_KSZPHY_EXTREG_READ, rdval, p);
217 
218 	return rc;
219 }
220 
alt_eth_phy_config(uint16_t instance,struct eth_cyclonev_priv * p)221 int alt_eth_phy_config(uint16_t instance, struct eth_cyclonev_priv *p)
222 {
223 
224 	int rc;
225 	uint16_t rdval;
226 	uint32_t timeout;
227 	/*--------------------   Configure the PHY skew values  ----------------*/
228 
229 	rc = alt_eth_phy_write_register_extended(instance, MII_KSZPHY_CLK_CONTROL_PAD_SKEW,
230 						 PHY_CLK_AND_CONTROL_PAD_SKEW_VALUE, p);
231 	if (rc == -1) {
232 		return rc;
233 	}
234 
235 	rc = alt_eth_phy_write_register_extended(instance, MII_KSZPHY_RX_DATA_PAD_SKEW,
236 						 PHY_RX_DATA_PAD_SKEW_VALUE, p);
237 	if (rc == -1) {
238 		return rc;
239 	}
240 
241 	/* Implement Auto-negotiation Process */
242 
243 	/* Check PHY Status if auto-negotiation is supported */
244 	rc = alt_eth_phy_read_register(instance, PHY_BSR, &rdval, p);
245 	if (((rdval & PHY_AUTOCAP) == 0) || (rc == -1)) {
246 		return -1;
247 	}
248 
249 	/* Set Advertise capabilities for 10Base-T/
250 	 *10Base-T full-duplex/100Base-T/100Base-T full-duplex
251 	 */
252 	rc = alt_eth_phy_read_register(instance, PHY_AUTON, &rdval, p);
253 	if (rc == -1) {
254 		return rc;
255 	}
256 
257 	rdval |= (PHYANA_10BASET | PHYANA_10BASETFD | PHYANA_100BASETX | PHYANA_100BASETXFD |
258 		  PHYSYMETRIC_PAUSE);
259 	rc = alt_eth_phy_write_register(instance, PHY_AUTON, rdval, p);
260 	if (rc == -1) {
261 		return rc;
262 	}
263 
264 	/* Set Advertise capabilities for 1000 Base-T/1000 Base-T full-duplex */
265 
266 	rc = alt_eth_phy_write_register(instance, PHY_1GCTL,
267 			PHYADVERTISE_1000FULL | PHYADVERTISE_1000HALF |
268 			PHYINDICATE_PORTTYPE |  PHYCONFIG_MASTER | PHYENABLE_MANUALCONFIG
269 					, p);
270 	if (rc == -1) {
271 		return rc;
272 	}
273 
274 	/* Wait for linked status... */
275 	timeout = 0;
276 	do {
277 		timeout++;
278 		rc = alt_eth_phy_read_register(instance, PHY_BSR, &rdval, p);
279 	} while (!(rdval & PHY_LINKED_STATUS) && (timeout < PHY_READ_TO) && (rc == 0));
280 
281 	/* Return ERROR in case of timeout */
282 	if ((timeout == PHY_READ_TO) || (rc == -1)) {
283 		LOG_ERR("Error Link Down\n");
284 		return -1;
285 	}
286 	LOG_INF("Link is up!");
287 
288 	/* Configure the PHY for AutoNegotiate */
289 	rc = alt_eth_phy_read_register(instance, PHY_BCR, &rdval, p);
290 	if (rc == -1) {
291 		return rc;
292 	}
293 
294 	rdval |= PHY_AUTONEGOTIATION;
295 	rdval |= PHY_RESTART_AUTONEGOTIATION;
296 	rc = alt_eth_phy_write_register(instance, PHY_BCR, rdval, p);
297 	if (rc == -1) {
298 		return rc;
299 	}
300 
301 	/* Wait until the auto-negotiation is completed */
302 	timeout = 0;
303 	do {
304 		timeout++;
305 		rc = alt_eth_phy_read_register(instance, PHY_BSR, &rdval, p);
306 	} while (!(rdval & PHY_AUTONEGO_COMPLETE) && (timeout < PHY_READ_TO) && (rc == 0));
307 
308 	/* Return ERROR in case of timeout */
309 	if ((timeout == PHY_READ_TO) || (rc == -1)) {
310 		alt_eth_phy_read_register(instance, PHY_BSR, &rdval, p);
311 		LOG_ERR("Auto Negotiation: Status reg = 0x%x\n", rdval);
312 		return -1;
313 	}
314 	LOG_INF("Auto Negotiation Complete!");
315 
316 	return rc;
317 };
318 
alt_eth_phy_reset(uint16_t instance,struct eth_cyclonev_priv * p)319 int alt_eth_phy_reset(uint16_t instance, struct eth_cyclonev_priv *p)
320 {
321 	int i;
322 	int rc;
323 	uint16_t rdval;
324 
325 	/* Put the PHY in reset mode */
326 	if ((alt_eth_phy_write_register(instance, PHY_BCR, PHY_RESET, p)) != 0) {
327 		/* Return ERROR in case of write timeout */
328 		return -1;
329 	}
330 
331 	/* Wait for the reset to clear */
332 	for (i = 0; i < 10; i++) {
333 		k_sleep(K_MSEC(10));
334 		rc = alt_eth_phy_read_register(instance, PHY_BCR, &rdval, p);
335 		if (((rdval & PHY_RESET) == 0) || (rc == -1)) {
336 			break;
337 		}
338 	}
339 
340 	if (i == 10) {
341 		return -1;
342 	}
343 	/* Delay to assure PHY reset */
344 	k_sleep(K_MSEC(10));
345 
346 	return rc;
347 };
348 
alt_eth_phy_get_duplex_and_speed(uint16_t * phy_duplex_status,uint16_t * phy_speed,uint16_t instance,struct eth_cyclonev_priv * p)349 int alt_eth_phy_get_duplex_and_speed(uint16_t *phy_duplex_status, uint16_t *phy_speed,
350 				     uint16_t instance, struct eth_cyclonev_priv *p)
351 {
352 
353 	LOG_DBG("PHY: func_alt_eth_phy_get_duplex_and_speed\n");
354 	uint16_t regval = 0;
355 	int rc;
356 
357 	rc = alt_eth_phy_read_register(instance, PHY_CR, &regval, p);
358 
359 	if (regval & PHY_DUPLEX_STATUS) {
360 		*phy_duplex_status = 1;
361 	} else {
362 		*phy_duplex_status = 0;
363 	}
364 
365 	if (regval & PHY_SPEED_100) {
366 		*phy_speed = 100;
367 	} else {
368 		if (regval & PHY_SPEED_1000) {
369 			*phy_speed = 1000;
370 		} else {
371 			*phy_speed = 10;
372 		}
373 	}
374 
375 	return rc;
376 }
377 
378 #endif
379