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, ®val, 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