1 /*******************************************************************************
2 * Copyright 2020 Microchip Corporation.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Microsemi VSC8541 PHY interface driver implementation to support the FU540
7 * Aloe board.
8 *
9 */
10 #include "mpfs_hal/mss_hal.h"
11 #include "hal/hal.h"
12
13 #include "drivers/mss_ethernet_mac/mss_ethernet_registers.h"
14 #include "drivers/mss_ethernet_mac/mss_ethernet_mac_regs.h"
15 #include "drivers/mss_ethernet_mac/mss_ethernet_mac_sw_cfg.h"
16 #include "drivers/mss_ethernet_mac/mss_ethernet_mac.h"
17 #include "drivers/mss_ethernet_mac/phy.h"
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
23 #if MSS_MAC_USE_PHY_VSC8541
24
25 /**************************************************************************/
26 /* Preprocessor Macros */
27 /**************************************************************************/
28
29 #define BMSR_AUTO_NEGOTIATION_COMPLETE (0x0020U)
30
31 /**************************************************************************//**
32 *
33 */
34
35 typedef struct
36 {
37 __IO uint32_t INPUT_VAL; /* 0x0000 */
38 __IO uint32_t INPUT_EN; /* 0x0004 */
39 __IO uint32_t OUTPUT_VAL; /* 0x0008 */
40 __IO uint32_t OUTPUT_EN; /* 0x000C */
41 __IO uint32_t PUE; /* 0x0010 */
42 __IO uint32_t DS; /* 0x0014 */
43 __IO uint32_t RISE_IE; /* 0x0018 */
44 __IO uint32_t RISE_IP; /* 0x001C */
45 __IO uint32_t FALL_IE; /* 0x0020 */
46 __IO uint32_t FALL_IP; /* 0x0024 */
47 __IO uint32_t HIGH_IE; /* 0x0028 */
48 __IO uint32_t HIGH_IP; /* 0x002C */
49 __IO uint32_t LOW_IE; /* 0x0030 */
50 __IO uint32_t LOW_IP; /* 0x0034 */
51 __IO uint32_t reserved0; /* 0x0038 */
52 __IO uint32_t reserved1; /* 0x003C */
53 __IO uint32_t OUT_XOR; /* 0x0040 */
54 } AloeGPIO_TypeDef;
55
56
MSS_MAC_VSC8541_phy_init(const void * v_this_mac,uint8_t phy_addr)57 void MSS_MAC_VSC8541_phy_init(/* mss_mac_instance_t */ const void *v_this_mac, uint8_t phy_addr)
58 {
59 #if defined(TARGET_ALOE)
60 volatile uint32_t loop;
61 AloeGPIO_TypeDef *g_aloe_gpio = (AloeGPIO_TypeDef *)0x10060000UL;
62
63 (void)v_this_mac;
64 (void)phy_addr;
65 /*
66 * Init includes toggling the reset line which is connected to GPIO 0 pin 12.
67 * This is the only pin I can see on the 16 GPIO which is currently set as an.
68 * output. We will hard code the setup here to avoid having to have a GPIO
69 * driver as well...
70 *
71 * The Aloe board is strapped for unmanaged mode and needs two pulses of the
72 * reset line to configure the device properly.
73 *
74 * The RX_CLK, TX_CLK and RXD7 pins are strapped high and the remainder low.
75 * This selects GMII mode with auto 10/100/1000 and 125MHz clkout.
76 */
77 g_aloe_gpio->OUTPUT_EN |= 0x00001000UL; /* Configure pin 12 as an output */
78 g_aloe_gpio->OUTPUT_VAL &= 0x0000EFFFUL; /* Clear pin 12 to reset PHY */
79 for(loop = 0U; loop != 1000U; loop++) /* Short delay, I'm not sure how much is needed... */
80 {
81 ;
82 }
83 g_aloe_gpio->OUTPUT_VAL |= 0x00001000UL; /* Take PHY^ out of reset */
84 for(loop = 0U; loop != 1000U; loop++) /* Short delay, I'm not sure how much is needed... */
85 {
86 ;
87 }
88 g_aloe_gpio->OUTPUT_VAL &= 0x0000EFFFUL; /* Second reset pulse */
89 for(loop = 0U; loop != 1000U; loop++) /* Short delay, I'm not sure how much is needed... */
90 {
91 ;
92 }
93 g_aloe_gpio->OUTPUT_VAL |= 0x00001000UL; /* Out of reset once more */
94
95 /* Need at least 15mS delay before accessing PHY after reset... */
96 for(loop = 0U; loop != 10000000U; loop++) /* Long delay, I'm not sure how much is needed... */
97 {
98 ;
99 }
100 #else
101 volatile uint16_t temp_reg;
102 const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac;
103 mss_mac_instance_t *phy_mac;
104
105 /* Assume this is done by app for the moment */
106 #if 0
107 /* Do hardware reset if possible/necessary */
108
109 /* Phy is actually attached to another MAC... */
110 if((struct mss_mac_instance *)0UL != this_mac->phy_controller)
111 {
112 phy_mac = (mss_mac_instance_t *)this_mac->phy_controller;
113 }
114 else
115 {
116 phy_mac = (mss_mac_instance_t *)this_mac;
117 }
118
119 if(0 == phy_mac->phy_hard_reset_done)
120 {
121 /* Active low reset pulse */
122 MSS_MAC_phy_reset(phy_mac, MSS_MAC_SOFT_RESET, false);
123 MSS_MAC_phy_reset(phy_mac, MSS_MAC_SOFT_RESET, true);
124
125 #if defined(TARGET_G5_SOC)
126 /*
127 * Multiple MACs may be involved and we need to ensure all relevant MACs
128 * have the phy_hard_reset_done flag set
129 */
130
131 if(phy_mac != this_mac) /* Simple case, set flag for all 4 MACs */
132 {
133 g_mac0.phy_hard_reset_done = true;
134 g_emac0.phy_hard_reset_done = true;
135 g_mac1.phy_hard_reset_done = true;
136 g_emac1.phy_hard_reset_done = true;
137 }
138 else if((&g_mac0 == phy_mac) || (&g_emac0 == phy_mac))
139 {
140 g_mac0.phy_hard_reset_done = true;
141 g_emac0.phy_hard_reset_done = true;
142 }
143 else
144 {
145 g_mac1.phy_hard_reset_done = true;
146 g_emac1.phy_hard_reset_done = true;
147 }
148 #else
149 phy_mac->phy_hard_reset_done = true;
150 #endif
151 }
152 #endif
153
154 /* Select standard registers page */
155 MSS_MAC_write_phy_reg(this_mac, phy_addr, 31, 0x0000U);
156
157 /* Select GMII mode */
158 MSS_MAC_write_phy_reg(this_mac, phy_addr, 23, (uint16_t)(0x0000));
159
160 /* Software Reset */
161 temp_reg = MSS_MAC_read_phy_reg(this_mac, phy_addr, 0);
162 temp_reg |= 0x8000U;
163 MSS_MAC_write_phy_reg(this_mac, phy_addr, 0, temp_reg);
164
165 /* Wait for soft reset to complete */
166 do
167 {
168 temp_reg = MSS_MAC_read_phy_reg(this_mac, phy_addr, 0);
169 } while(0 != (temp_reg & 0x8000U));
170
171 /* Full duplex, autonegotiation and 1000Mbps as starting point */
172 MSS_MAC_write_phy_reg(this_mac, phy_addr, MII_BMCR, (uint16_t)(BMCR_ANENABLE | BMCR_FULLDPLX | BMCR_SPEED1000));
173
174 /* Full duplex modes */
175 MSS_MAC_write_phy_reg(this_mac, phy_addr, MII_ADVERTISE, (uint16_t)(ADVERTISE_FULL));
176
177 /* Full duplex mode */
178 MSS_MAC_write_phy_reg(this_mac, phy_addr, MII_CTRL1000, (uint16_t)(ADVERTISE_1000FULL));
179
180
181 /* Select page 2 */
182 MSS_MAC_write_phy_reg(this_mac, phy_addr, 31, 0x0002U);
183
184 /* Adjust MAC interface slew rate - default is 111 but recommended for 3.3V i/o is 100 */
185 temp_reg = MSS_MAC_read_phy_reg(this_mac, phy_addr, 27);
186 temp_reg &= 0xFF1FU;
187 temp_reg |= 0x0080U;
188 MSS_MAC_write_phy_reg(this_mac, phy_addr, 27, temp_reg);
189
190 /* Select page 0 */
191 MSS_MAC_write_phy_reg(this_mac, phy_addr, 31, 0x0000U);
192
193 #if 0
194 /* Auto MDI/MDI-X, Do not ignore advertised ability, disable CLKOUT */
195 MSS_MAC_write_phy_reg(this_mac, phy_addr, 18, (uint16_t)(0x0084U));
196
197 /* Enable SGMII MAC link autonegotiation and Force copper media only */
198 MSS_MAC_write_phy_reg(this_mac, phy_addr, 23, (uint16_t)(0x2880U));
199
200 /* SGMII no input preamble, 2 byte output preamble, 9/12K jumbo frames (12K for 60ppm clock) */
201 MSS_MAC_write_phy_reg(this_mac, phy_addr, 23, (uint16_t)(0xC050U));
202
203 /* Select selection of LED activity modes for 4 LEDs */
204 MSS_MAC_write_phy_reg(this_mac, phy_addr, 29, (uint16_t)(0x0123U));
205
206 /* Clear this for consistency as many bits are CMODE selections */
207 MSS_MAC_write_phy_reg(this_mac, phy_addr, 30, (uint16_t)(0x0000U));
208
209 /* Select extended registers page */
210 MSS_MAC_write_phy_reg(this_mac, phy_addr, 31, 0x0001U);
211
212 /* Clear SIGDET polarity to active high */
213 temp_reg = MSS_MAC_read_phy_reg(this_mac, phy_addr, 19);
214 temp_reg &= 0xFFFE;
215 MSS_MAC_write_phy_reg(this_mac, phy_addr, 19, temp_reg);
216
217 /* Ensure all CMODE bits are clear */
218 temp_reg = MSS_MAC_read_phy_reg(this_mac, phy_addr, 20);
219 temp_reg &= 0xFE6F;
220 MSS_MAC_write_phy_reg(this_mac, phy_addr, 20, temp_reg);
221
222 /* Select general purpose registers page */
223 MSS_MAC_write_phy_reg(this_mac, phy_addr, 31, 0x0010U);
224
225 /* Disable SIGDET operation */
226 MSS_MAC_write_phy_reg(this_mac, phy_addr, 13, (uint16_t)(0x000FU));
227
228 /* Select standard registers page */
229 MSS_MAC_write_phy_reg(this_mac, phy_addr, 31, 0x0000U);
230 #endif
231
232 #endif
233
234 }
235
236 /**************************************************************************//**
237 *
238 */
MSS_MAC_VSC8541_phy_set_link_speed(void * v_this_mac,uint32_t speed_duplex_select,mss_mac_speed_mode_t speed_mode)239 void MSS_MAC_VSC8541_phy_set_link_speed(/* mss_mac_instance_t */ void *v_this_mac, uint32_t speed_duplex_select, mss_mac_speed_mode_t speed_mode)
240 {
241 mss_mac_instance_t *this_mac = (mss_mac_instance_t *)v_this_mac;
242 uint16_t phy_reg;
243 uint32_t inc;
244 uint32_t speed_select;
245 const uint16_t mii_advertise_bits[4] = {ADVERTISE_10FULL, ADVERTISE_10HALF,
246 ADVERTISE_100FULL, ADVERTISE_100HALF};
247
248 this_mac->speed_mode = speed_mode;
249
250 if(MSS_MAC_SPEED_AN == speed_mode) /* Set auto-negotiation advertisement. */
251 {
252 /* Set 10Mbps and 100Mbps advertisement. */
253 phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_ADVERTISE);
254 phy_reg &= (uint16_t)(~(ADVERTISE_10HALF | ADVERTISE_10FULL |
255 ADVERTISE_100HALF | ADVERTISE_100FULL));
256
257 speed_select = speed_duplex_select;
258 for(inc = 0U; inc < 4U; ++inc)
259 {
260 uint32_t advertise;
261 advertise = speed_select & 0x00000001U;
262 if(advertise != 0U)
263 {
264 phy_reg |= mii_advertise_bits[inc];
265 }
266 speed_select = speed_select >> 1U;
267 }
268
269 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_ADVERTISE, phy_reg);
270
271 /* Set 1000Mbps advertisement. */
272 phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000);
273 phy_reg &= (uint16_t)(~(ADVERTISE_1000FULL | ADVERTISE_1000HALF));
274
275 if((speed_duplex_select & MSS_MAC_ANEG_1000M_FD) != 0U)
276 {
277 phy_reg |= ADVERTISE_1000FULL;
278 }
279
280 if((speed_duplex_select & MSS_MAC_ANEG_1000M_HD) != 0U)
281 {
282 phy_reg |= ADVERTISE_1000HALF;
283 }
284
285 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000, phy_reg);
286 }
287 else
288 {
289 uint16_t temp_reg = 0x0000U; /* Default with 10M, half duplex */
290
291 if((MSS_MAC_10_FDX == this_mac->speed_mode) || (MSS_MAC_100_FDX == this_mac->speed_mode) || (MSS_MAC_1000_FDX == this_mac->speed_mode))
292 {
293 temp_reg |= BMCR_FULLDPLX;
294 }
295
296 if((MSS_MAC_100_FDX == this_mac->speed_mode) || (MSS_MAC_100_HDX == this_mac->speed_mode))
297 {
298 temp_reg |= BMCR_SPEED100;
299 }
300
301 if((MSS_MAC_1000_FDX == this_mac->speed_mode) || (MSS_MAC_1000_HDX == this_mac->speed_mode))
302 {
303 temp_reg |= BMCR_SPEED1000;
304 /* Set Master mode */
305 phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000);
306 phy_reg |= 0x1800U;
307 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000, phy_reg);
308 }
309
310 /* Apply static speed/duplex selection */
311 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_BMCR, temp_reg);
312
313 /* Full duplex mode or half duplex, single port device */
314 if((MSS_MAC_10_FDX == this_mac->speed_mode) || (MSS_MAC_100_FDX == this_mac->speed_mode) || (MSS_MAC_1000_FDX == this_mac->speed_mode))
315 {
316 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000, (uint16_t)(ADVERTISE_1000FULL));
317 }
318 else
319 {
320 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000, (uint16_t)(ADVERTISE_1000HALF));
321 }
322 }
323 }
324
325 /**************************************************************************//**
326 *
327 */
MSS_MAC_VSC8541_phy_autonegotiate(const void * v_this_mac)328 void MSS_MAC_VSC8541_phy_autonegotiate(/* mss_mac_instance_t */ const void *v_this_mac)
329 {
330 const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac;
331 volatile uint16_t phy_reg;
332 uint16_t autoneg_complete;
333 volatile uint32_t copper_aneg_timeout = 10000U;
334
335 if(MSS_MAC_SPEED_AN == this_mac->speed_mode) /* Only do if allowed */
336 {
337 phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 2U);
338 phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 3U);
339
340 /* Enable auto-negotiation. */
341 phy_reg = 0x1340U;
342 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_BMCR, phy_reg);
343
344 /* Wait for copper auto-negotiation to complete. */
345 do {
346 phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_BMSR);
347 autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE;
348 --copper_aneg_timeout;
349 } while(((0U == autoneg_complete) && (copper_aneg_timeout != 0u)) || (0xFFFF == phy_reg));
350 }
351 }
352
353
354 /**************************************************************************//**
355 *
356 */
MSS_MAC_VSC8541_mac_autonegotiate(const void * v_this_mac)357 void MSS_MAC_VSC8541_mac_autonegotiate(/* mss_mac_instance_t */ const void *v_this_mac)
358 {
359 (void)v_this_mac;
360 }
361
362
363 /**************************************************************************//**
364 *
365 */
MSS_MAC_VSC8541_phy_get_link_status(const void * v_this_mac,mss_mac_speed_t * speed,uint8_t * fullduplex)366 uint8_t MSS_MAC_VSC8541_phy_get_link_status
367 (
368 /* mss_mac_instance_t*/ const void *v_this_mac,
369 mss_mac_speed_t * speed,
370 uint8_t * fullduplex
371 )
372 {
373 const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac;
374 uint16_t phy_reg;
375 uint16_t link_up;
376 uint8_t link_status;
377
378 phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_BMSR);
379 link_up = phy_reg & BMSR_LSTATUS;
380 if(link_up != MSS_MAC_LINK_DOWN)
381 {
382 uint16_t duplex;
383 uint16_t speed_field;
384
385 /* Link is up. */
386 link_status = MSS_MAC_LINK_UP;
387
388 phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1CU); /* Device Auxillary Control and Status */
389 duplex = phy_reg & 0x0020U;
390 speed_field = phy_reg & 0x0018U;
391
392 if(MSS_MAC_HALF_DUPLEX == duplex)
393 {
394 *fullduplex = MSS_MAC_HALF_DUPLEX;
395 }
396 else
397 {
398 *fullduplex = MSS_MAC_FULL_DUPLEX;
399 }
400
401 switch(speed_field >> 3)
402 {
403 case 0U:
404 *speed = MSS_MAC_10MBPS;
405 break;
406
407 case 1U:
408 *speed = MSS_MAC_100MBPS;
409 break;
410
411 case 2U:
412 *speed = MSS_MAC_1000MBPS;
413 break;
414
415 default:
416 link_status = (uint8_t)MSS_MAC_LINK_DOWN;
417 break;
418 }
419 }
420 else
421 {
422 /* Link is down. */
423 link_status = (uint8_t)MSS_MAC_LINK_DOWN;
424 }
425
426 return link_status;
427 }
428
429
430 /**************************************************************************//**
431 *
432 */
433 uint16_t VSC8541_reg_0[32];
434 uint16_t VSC8541_reg_1[16];
435 uint16_t VSC8541_reg_2[16];
436 uint16_t VSC8541_reg_16[32];
437
438 void dump_vsc8541_regs(const mss_mac_instance_t * this_mac);
dump_vsc8541_regs(const mss_mac_instance_t * this_mac)439 void dump_vsc8541_regs(const mss_mac_instance_t * this_mac)
440 {
441 volatile int32_t count;
442 volatile uint16_t page;
443 volatile uint16_t old_page;
444 volatile uint16_t *pdata;
445 volatile psr_t lev;
446
447 for(page = 0U; page <= 0x10U; page++)
448 {
449 if(0U == page)
450 {
451 pdata = VSC8541_reg_0;
452 }
453 else if(1U == page)
454 {
455 pdata = VSC8541_reg_1;
456 }
457 else if(2U == page)
458 {
459 pdata = VSC8541_reg_2;
460 }
461 else if(16U == page)
462 {
463 pdata = VSC8541_reg_16;
464 }
465 else
466 {
467 pdata = VSC8541_reg_0;
468 }
469
470 if((0U == page) || (0x10U == page))
471 {
472 for(count = 0; count <= 0x1F; count++)
473 {
474 lev = HAL_disable_interrupts();
475 old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU);
476
477 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, page);
478
479 pdata[count] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, (uint8_t)count);
480
481 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page);
482 MSS_MAC_read_phy_reg(this_mac, (uint8_t)10, (uint8_t)count);
483 HAL_restore_interrupts(lev);
484 }
485 }
486 else
487 {
488 for(count = 0x10; count <= 0x1F; count++)
489 {
490 lev = HAL_disable_interrupts();
491 old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU);
492
493 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, page);
494
495 pdata[count - 0X10] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, (uint8_t)count);
496
497 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page);
498 HAL_restore_interrupts(lev);
499 }
500 }
501
502 if(2U == page)
503 {
504 page = 0x0FU;
505 }
506 }
507 }
508
509 #endif /* #if defined(TARGET_ALOE) */
510 #ifdef __cplusplus
511 }
512 #endif
513
514 /******************************** END OF FILE ******************************/
515
516
517
518
519
520
521