1 /*******************************************************************************
2  * Copyright 2020 Microchip Corporation.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Microsemi VSC8575 PHY interface driver implementation to support the
7  * peripheral daughter board for the G5 SoC Emulation Platform.
8  *
9  */
10 
11 #include "mpfs_hal/mss_hal.h"
12 #include "hal/hal.h"
13 
14 #include "drivers/mss_ethernet_mac/mss_ethernet_registers.h"
15 #include "drivers/mss_ethernet_mac/mss_ethernet_mac_regs.h"
16 #include "drivers/mss_ethernet_mac/mss_ethernet_mac_sw_cfg.h"
17 #include "drivers/mss_ethernet_mac/mss_ethernet_mac.h"
18 #include "drivers/mss_ethernet_mac/phy.h"
19 
20 #include "drivers/mss_ethernet_mac/mss_ethernet_mac_types.h"
21 
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdint.h>
25 #include <inttypes.h>
26 #if MSS_MAC_USE_PHY_VSC8575
27 #include "vtss_api.h"   /* For BOOL and friends */
28 #include "vtss_phy_api.h"   /* For PHY API Pre and Post Resets */
29 #include "vtss_init_api.h"
30 
31 extern int32_t viper_fmc_board_init(vtss_init_conf_t *config);
32 #endif
33 
34 #if MSS_MAC_USE_PHY_VSC8575_LITE
35 #include "vtss_phy_common.h"
36 #include "vtss_viper_phy_prototypes.h"
37 
38 extern int32_t viper_fmc_board_init(struct phy_control_t *control);
39 #endif
40 
41 
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45 
46 /**************************************************************************/
47 /* Preprocessor Macros                                                    */
48 /**************************************************************************/
49 
50 #define BMSR_AUTO_NEGOTIATION_COMPLETE  (0x0020U)
51 
52 /**************************************************************************//**
53  *
54  */
55 
56 
57 uint16_t VSC8575_reg_0[32];
58 uint16_t VSC8575_reg_1[16];
59 uint16_t VSC8575_reg_2[16];
60 uint16_t VSC8575_reg_3[20]; /* Additional 4 to hold MAC Serdes RX and TX stats */
61 uint16_t VSC8575_reg_4[16];
62 uint16_t VSC8575_reg_16[32];
63 uint16_t VSC8575_MSS_SGMII_reg16[17];
64 uint32_t VSC8575_MSS_MAC_reg[80];
65 uint32_t VSC8575_MSS_PLIC_REG[80];
66 
67 void dump_vsc8575_regs(const mss_mac_instance_t * this_mac);
dump_vsc8575_regs(const mss_mac_instance_t * this_mac)68 void dump_vsc8575_regs(const mss_mac_instance_t * this_mac)
69 {
70     int32_t count;
71     uint16_t page;
72     uint16_t old_page;
73     uint16_t *pdata;
74     volatile psr_t lev;
75 
76     for(page = 0U; page <= 0x10U; page++)
77     {
78         if(0U == page)
79         {
80             pdata = VSC8575_reg_0;
81         }
82         else if(1U == page)
83         {
84             pdata = VSC8575_reg_1;
85         }
86         else if(2U == page)
87         {
88             pdata = VSC8575_reg_2;
89         }
90         else if(3U == page)
91         {
92             pdata = VSC8575_reg_3;
93         }
94         else if(4U == page)
95         {
96             pdata = VSC8575_reg_4;
97         }
98         else if(16U == page)
99         {
100             pdata = VSC8575_reg_16;
101         }
102         else
103         {
104             pdata = VSC8575_reg_0;
105         }
106 
107         if((0U == page) || (0x10U == page))
108         {
109             for(count = 0; count <= 0x1F; count++)
110             {
111                 lev = HAL_disable_interrupts();
112                 old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU);
113 
114                 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, page);
115 
116                 pdata[count] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, (uint8_t)count);
117 
118                 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page);
119                 HAL_restore_interrupts(lev);
120 
121             }
122         }
123         else
124         {
125             for(count = 0x10; count <= 0x1F; count++)
126             {
127                 lev = HAL_disable_interrupts();
128                 old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU);
129 
130                 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, page);
131 
132                 pdata[count - 0X10] = MSS_MAC_read_phy_reg(this_mac,(uint8_t) this_mac->phy_addr, (uint8_t)count);
133 
134                 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page);
135                 HAL_restore_interrupts(lev);
136             }
137 
138             if(3U == page) /* Circle back and get MAC Serdes stats... */
139             {
140                 lev = HAL_disable_interrupts();
141                 old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU);
142 
143                 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, page);
144                 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU, 0x4000U); /* Select MAC stats */
145                 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x16U, 0x4000U); /* Select MAC stats */
146 
147                 pdata[0x10] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1CU); /* Fetch MAC stats */
148                 pdata[0x11] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU);
149                 pdata[0x12] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x15U); /* Fetch MAC stats */
150                 pdata[0x13] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x16U);
151 
152                 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x16U, 0x0000U); /* Select Media stats */
153                 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU, 0x0000U); /* Select Media stats */
154                 MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page);
155                 HAL_restore_interrupts(lev);
156             }
157         }
158 
159         if(4U == page)
160         {
161             page = 0x0FU;
162         }
163     }
164 
165     for(count = 0; count <= 0x10; count++)
166     {
167         VSC8575_MSS_SGMII_reg16[count] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, (uint8_t)count);
168     }
169 
170 #if 0 /* Only enable as necessary as reading some regs can interfere with ISR operation */
171     {
172         uint32_t *pbigdata;
173 
174         pbigdata = (uint32_t *)0x20110000UL;
175         for(count = 0; count < 19; count++, pbigdata++)
176         {
177             VSC8575_MSS_MAC_reg[count] = *pbigdata;
178         }
179 
180         pbigdata =(uint32_t *)0x0C000000UL;
181         for(count = 0; count < 8; count++, pbigdata++)
182         {
183             VSC8575_MSS_PLIC_REG[count] = *pbigdata;
184         }
185     }
186 #endif
187 }
188 
189 
190 /**************************************************************************//**
191  * Note: The following assumes there is only one VSC8757 PHY in the system.
192  *       We will need to revisit it at some stage to provide for multiple
193  *       devices connected to separate GEMs or for the case of multiple
194  *       GEMs connected to the same PHY but to different ports.
195  *
196  *       For now we need to at least record somewhere which GEM this PHY
197  *       is associated with so that the MDIO functions can work correctly as
198  *       it is currently assumed GEM0 is the one connected to the VSC8575.
199  *
200  *       May need to consider adding entry to vtss_inst_t to hold the mac
201  *       reference so MDIO can figure out who to talk to. This will also mean
202  *       that the some or all of following globals will need to be changed to
203  *       allow for multiple connections...
204  *
205  */
206 
207 mss_mac_instance_t     *g_my_mac = (mss_mac_instance_t *)0;
208 
209 
210 #if MSS_MAC_USE_PHY_VSC8575
MSS_MAC_VSC8575_phy_init(const void * v_this_mac,uint8_t phy_addr)211 void MSS_MAC_VSC8575_phy_init(/* mss_mac_instance_t*/ const void *v_this_mac, uint8_t phy_addr)
212 {
213     static vtss_inst_t             g_vtss_inst_p;
214     static vtss_inst_create_t      g_vtss_create_inst;
215     static vtss_init_conf_t        g_vtss_init_conf;
216     static vtss_phy_conf_t         g_phy;
217     static vtss_phy_conf_1g_t      g_phy_conf_1g;
218     static vtss_phy_reset_conf_t   g_phy_reset_conf;
219 
220     static vtss_phy_reset_conf_t vts_phy_init_params = {VTSS_PORT_INTERFACE_SGMII, VTSS_PHY_MEDIA_IF_CU, {1,2},
221          {TRUE},VTSS_PHY_FORCE_RESET, VTSS_PHY_PKT_MODE_IEEE_1_5_KB, TRUE};
222 
223     const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac;
224     volatile vtss_rc vrc;
225     volatile int32_t vrc_i32;
226 
227     (void)phy_addr;
228     g_my_mac = this_mac; /* For now, simply record which MAC we are associated with
229                           * assuming there is only one...
230                           */
231     (void)memset (&g_phy, 0, sizeof(vtss_phy_conf_t));
232 
233     g_vtss_create_inst.target = VTSS_TARGET_CU_PHY;
234 
235     vrc = vtss_inst_create(&g_vtss_create_inst, &g_vtss_inst_p);
236 
237     vrc = vtss_init_conf_get(g_vtss_inst_p, &g_vtss_init_conf);
238     vrc_i32 = viper_fmc_board_init(&g_vtss_init_conf);
239 
240     g_vtss_init_conf.warm_start_enable = 0;
241     g_vtss_init_conf.restart_info_src  = VTSS_RESTART_INFO_SRC_CU_PHY;
242     g_vtss_init_conf.restart_info_port = 0;
243 
244     vrc = vtss_init_conf_set(g_vtss_inst_p, &g_vtss_init_conf);
245 
246     (void)memset(&g_phy_reset_conf, 0, sizeof(g_phy_reset_conf));
247 
248     g_phy_reset_conf.mac_if = VTSS_PORT_INTERFACE_SGMII;
249     g_phy_reset_conf.media_if = VTSS_PHY_MEDIA_IF_CU;
250     g_phy_reset_conf.rgmii.rx_clk_skew_ps = 0;
251     g_phy_reset_conf.rgmii.tx_clk_skew_ps = 0;
252     g_phy_reset_conf.tbi.aneg_enable = 1;
253 
254     vrc = vtss_phy_pre_reset(g_vtss_inst_p, 0);
255     /* HH:  unsure why vts_phy_init_params being passed instead of g_phy_reset_conf to vtss_phy_reset(...) ??? */
256     vrc = vtss_phy_reset(g_vtss_inst_p, 0, &vts_phy_init_params);
257     /* HH:  moved SerDes calibration to after the MAC PCS settings configured */
258 
259     /* Configure PHY 1G master/slave preference (for SyncE timing) */
260     (void)memset(&g_phy_conf_1g, 0, sizeof(g_phy_conf_1g));
261     /* HH:  conf_get to pre-populate all entries with valid defaults, prior to application settings */
262     vtss_phy_conf_get(g_vtss_inst_p, 0 /* port_no */, &g_phy);
263 
264     g_phy_conf_1g.master.cfg = TRUE;   /* 1=Enabled */
265     g_phy_conf_1g.master.val = TRUE;   /* 1=Master */
266 
267     /* HH move conf get/set until after port conf setting configured below */
268 
269     g_phy.mode = VTSS_PHY_MODE_ANEG;
270 
271     /* Example for PHY speed support for auto-neg  */
272     g_phy.aneg.speed_10m_hdx  = 1;
273     g_phy.aneg.speed_10m_fdx  = 1;
274     g_phy.aneg.speed_100m_hdx = 1;
275     g_phy.aneg.speed_100m_fdx = 1;
276     g_phy.aneg.speed_1g_hdx   = 0;
277     g_phy.aneg.speed_1g_fdx   = 1;
278 
279     g_phy.sigdet = VTSS_PHY_SIGDET_POLARITY_ACT_HIGH;
280 
281     /* Example for PHY flow control settings  */
282     g_phy.aneg.symmetric_pause =  1;
283     g_phy.aneg.tx_remote_fault =  1;
284 
285     g_phy.mdi = VTSS_PHY_MDIX_AUTO; /* always enable auto detection of crossed/non-crossed cables */
286     g_phy.flf = VTSS_PHY_FAST_LINK_FAIL_DISABLE;
287 
288     /*  Setup the MAC Interface PCS Parameters */
289     g_phy.mac_if_pcs.disable           = 0;
290     g_phy.mac_if_pcs.restart           = 0;
291     g_phy.mac_if_pcs.pd_enable         = 0;
292     g_phy.mac_if_pcs.aneg_restart      = 0;
293     g_phy.mac_if_pcs.force_adv_ability = 0;
294     g_phy.mac_if_pcs.sgmii_in_pre = VTSS_PHY_MAC_SERD_PCS_SGMII_IN_PRE_NONE;
295     g_phy.mac_if_pcs.sgmii_out_pre      = 0;
296     g_phy.mac_if_pcs.serdes_aneg_ena    = 1;
297     g_phy.mac_if_pcs.serdes_pol_inv_in  = 0;
298     g_phy.mac_if_pcs.serdes_pol_inv_out = 0;
299     g_phy.mac_if_pcs.fast_link_stat_ena = 0;
300     g_phy.mac_if_pcs.inhibit_odd_start  = 0; /* Does nothing as this bit id default on... */
301 
302 /*  Setup the MEDIA Interface PCS Parameters */
303     g_phy.media_if_pcs.remote_fault       = VTSS_PHY_MEDIA_SERD_PCS_REM_FAULT_NO_ERROR;
304     g_phy.media_if_pcs.aneg_pd_detect     = 0;
305     g_phy.media_if_pcs.force_adv_ability  = 0;
306     g_phy.media_if_pcs.serdes_pol_inv_in  = 0;
307     g_phy.media_if_pcs.serdes_pol_inv_out = 0;
308     g_phy.media_if_pcs.inhibit_odd_start  = 1;
309     g_phy.media_if_pcs.force_hls          = 0;
310     g_phy.media_if_pcs.force_fefi         = 0;
311     g_phy.media_if_pcs.force_fefi_value   = 0;
312 
313 #if 0
314     {
315         vtss_phy_clock_conf_t clock_conf;
316         clock_conf.freq = VTSS_PHY_FREQ_125M;
317         clock_conf.squelch = VTSS_PHY_CLK_SQUELCH_MAX;
318         clock_conf.src = 0;
319         vtss_phy_clock_conf_set(g_vtss_inst_p, 0, 0, &clock_conf);
320     }
321 #endif
322 
323      vrc = vtss_phy_conf_set(g_vtss_inst_p, 0 /*port_no*/, &g_phy);
324 
325     /* HH:  moved SerDes calibration here */
326     vrc = vtss_phy_post_reset(g_vtss_inst_p, 0);
327 
328     {
329         uint16_t old_page;
330         uint16_t temp_reg;
331 
332         old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU);
333         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, 3U);
334         temp_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U);
335         temp_reg &= (uint16_t)(~0x0010U); /* Clear media inhibit odd start delay  bit */
336         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U, temp_reg);
337 
338         temp_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U);
339         temp_reg &= (uint16_t)(~0x0004U); /* Clear mac inhibit odd start delay  bit */
340         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U, temp_reg);
341 
342         temp_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U);
343         temp_reg &= (uint16_t)(~0x0100U); /* Turn off 2 byte preamble */
344         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U, temp_reg);
345 
346         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page);
347     }
348     {
349         uint16_t phy_reg;
350         volatile uint32_t sgmii_aneg_timeout = 100000U;
351         uint16_t autoneg_complete;
352 
353         if(TBI == this_mac->interface_type)
354         {
355             phy_reg = (uint16_t)this_mac->mac_base->PCS_CONTROL;
356             phy_reg |= 0x1000U;
357             this_mac->mac_base->PCS_CONTROL = phy_reg;
358             phy_reg |= 0x0200U;
359             this_mac->mac_base->PCS_CONTROL = phy_reg;
360 
361             /* Wait for SGMII auto-negotiation to complete. */
362             do {
363                 phy_reg = (uint16_t)this_mac->mac_base->PCS_STATUS;
364                 autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE;
365                 --sgmii_aneg_timeout;
366             } while(((0U == autoneg_complete) && (0U != sgmii_aneg_timeout)) || (0xFFFF == phy_reg));
367         }
368 
369         if(GMII_SGMII == this_mac->interface_type)
370         {
371             /*
372              * SGMII to GMII core with embedded MDIO interface for SGMII
373              * link control.
374              *
375              * Reset SGMII core side of I/F.
376              */
377             phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR);
378             phy_reg |= 0x9000U;    /* Reset and start autonegotiation */
379             phy_reg &= 0xFBFFU;    /* Clear Isolate bit */
380             MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR, phy_reg);
381 
382             phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR);
383             phy_reg |= 0x1000U;    /* start autonegotiation */
384             phy_reg &= 0xFBFFU;    /* Clear gmii Isolate bit */
385             MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR, phy_reg);
386         }
387 #if 0
388         /* Far-end loopback - enable at your peril... DO NOT try this on an open network*/
389         phy_reg =  MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U);
390         phy_reg |= 0x8U;
391         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U, phy_reg);
392 #endif
393         /* LED control - configure LED 0 as RX indicator and LED 1 as TX indicator */
394         phy_reg =  MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU);
395         phy_reg &= 0xFF00U;
396         phy_reg |= 0x00ABU;
397         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU, phy_reg);
398 
399         phy_reg =  MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1EU);
400         phy_reg |= 0x4000U;
401         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1EU, phy_reg);
402 #if 0
403         /* Ethernet Packet Generator - enable at your peril... DO NOT try this on an open network */
404         old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU);
405 
406         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, 1U);
407 
408         phy_reg =  MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU);
409         phy_reg |= 0xC000U;
410         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU, phy_reg);
411 
412         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page);
413 #endif
414     }
415 }
416 #endif /* MSS_MAC_USE_PHY_VSC8575 */
417 
418 
419 #if MSS_MAC_USE_PHY_VSC8575_LITE
420 extern int32_t usleep(uint32_t usecs);
421 
MSS_MAC_VSC8575_phy_init(const void * v_this_mac,uint8_t phy_addr)422 void MSS_MAC_VSC8575_phy_init(/* mss_mac_instance_t */ const void *v_this_mac, uint8_t phy_addr)
423 {
424     static vsc_phy_loopback_t    loopback;
425     static vsc_phy_control_t     cntrl;
426     static vsc_phy_conf_t        phy_config;
427     static vsc_phy_port_status_t phy_status;
428 
429     uint16_t old_page;
430     uint16_t temp_reg;
431     uint16_t phy_reg;
432     volatile uint32_t sgmii_aneg_timeout = 100000U;
433     uint16_t autoneg_complete;
434     const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac;
435     volatile int32_t rc; /* Volatile so we can see rc when debugging as
436                           * otherwise it tends to get removed as we don't use
437                           * it.
438                           */
439 
440     (void)phy_addr;
441     /* For now, simply record which MAC we are associated with, this is not
442      * going to work with more than 1 VSC8575 in the system so we should really
443      * have this stored in the cntrl structure but this involves modifying the
444      * API code...
445      */
446     g_my_mac = this_mac;
447 
448     /* Start out blank for consistency */
449     (void)memset (&cntrl, 0, sizeof(cntrl));
450     (void)memset (&phy_config, 0, sizeof(phy_config));
451     (void)memset (&phy_status, 0, sizeof(phy_status));
452     (void)memset (&loopback, 0, sizeof(vsc_phy_loopback_t));
453 
454     phy_config.mode = VSC_PHY_MODE_ANEG;
455 
456     /* Forced Mode Config */
457     phy_config.forced.port_speed = VSC_SPEED_1G;
458     phy_config.forced.fdx = 1;
459 
460     /* ANEG Config */
461     phy_config.aneg.speed_10m_hdx    = 1U;
462     phy_config.aneg.speed_10m_fdx    = 1U;
463     phy_config.aneg.speed_100m_hdx   = 1U;
464     phy_config.aneg.speed_100m_fdx   = 1U;
465     phy_config.aneg.speed_1g_hdx     = 0U;
466     phy_config.aneg.speed_1g_fdx     = 1U;
467     phy_config.aneg.symmetric_pause  = 1U;
468     phy_config.aneg.asymmetric_pause = 0U;
469     phy_config.aneg.tx_remote_fault  = 1U;
470 
471     /* forced Mode, 1G Config of Master/Slave */
472     phy_config.conf_1g.master.cfg = 0U;  /* Manual Master/Slave config to Force Master cfg  */
473     phy_config.conf_1g.master.val = 0U;  /* Master=1, Slave=0 */
474 
475     /* MDI/MDIX Config */
476     phy_config.mdi = VSC_PHY_AUTO_MDIX;
477 
478     /* FastLink Fail Config */
479     phy_config.flf.flf = VSC_PHY_FAST_LINK_FAIL_DISABLE;
480 
481     /* SigDet Config */
482     phy_config.sigdet = VSC_PHY_SIGDET_POLARITY_ACT_HIGH;
483 
484     /* UniDirectional Config */
485     phy_config.unidir = VSC_PHY_UNIDIR_DISABLE;
486 
487     /* Pkt Mode Config */
488     phy_config.pkt_mode = VSC_PHY_PKT_MODE_IEEE_1_5_KB;
489 
490     /* MAC PCS Config */
491     /* Note: MAC PCS Config only sets bits, does not clear bits */
492     /*       Therefore, to use Chip Defaults, just use all 0's  */
493     phy_config.mac_if_pcs.disable            = 0U;
494     phy_config.mac_if_pcs.restart            = 0U;
495     phy_config.mac_if_pcs.pd_enable          = 0U;
496     phy_config.mac_if_pcs.aneg_restart       = 0U;
497     phy_config.mac_if_pcs.force_adv_ability  = 0U;
498     phy_config.mac_if_pcs.sgmii_in_pre       = 0U;
499     phy_config.mac_if_pcs.sgmii_out_pre      = 0U;
500     phy_config.mac_if_pcs.serdes_aneg_ena    = 1U;
501     phy_config.mac_if_pcs.serdes_pol_inv_in  = 0U;
502     phy_config.mac_if_pcs.serdes_pol_inv_out = 0U;
503     phy_config.mac_if_pcs.fast_link_stat_ena = 0U;
504     phy_config.mac_if_pcs.inhibit_odd_start  = 0U;
505 
506     /* Media PCS Config */
507     /* Note: Media PCS Config only sets bits, does not clear bits */
508     /*       Therefore, to use Chip Defaults, just use all 0's  */
509     phy_config.media_if_pcs.remote_fault       = VSC_PHY_MEDIA_SERD_PCS_REM_FAULT_NO_ERROR;
510     phy_config.media_if_pcs.aneg_pd_detect     = 1U;
511     phy_config.media_if_pcs.force_adv_ability  = 0U;
512     phy_config.media_if_pcs.serdes_pol_inv_in  = 0U;
513     phy_config.media_if_pcs.serdes_pol_inv_out = 0U;
514     phy_config.media_if_pcs.inhibit_odd_start  = 1U;
515     phy_config.media_if_pcs.force_hls          = 0U;
516     phy_config.media_if_pcs.force_fefi         = 0U;
517     phy_config.media_if_pcs.force_fefi_value   = 0U;
518 
519     rc = viper_fmc_board_init(&cntrl);
520 
521     cntrl.phy_addr = 0U; /* This is actually the port number 0-3 on the VSC8575 */
522     cntrl.phy_usleep = usleep;
523 
524     rc = vsc_get_phy_type(&cntrl);
525     cntrl.mac_if    = PHY_MAC_IF_MODE_SGMII;
526     cntrl.media_if  = PHY_MEDIA_IF_CU;
527 
528     /*------------------------------------------------------------------------------------------------
529      * Initialize PHY, Only run on Base Port of the PHY, Run any Init Scripts and Micro-Patch Downloads
530      *------------------------------------------------------------------------------------------------*/
531     rc = initialize_viper_phy(&cntrl);
532 
533     /*------------------------------------------------------------------------------------------------
534      * Reset the PHY Port, Run on each Port of the PHY, Run any configs, etc.
535      *------------------------------------------------------------------------------------------------*/
536     rc = reset_viper_phy(&cntrl);
537     rc = viper_phy_config_set(&cntrl, &phy_config);
538 
539     /* The cntrl struct only saves the MEDIA i/f for the current port */
540     /* Adjust the 1G SerDes SigDet Input Threshold and Signal Sensitivity for 100FX */
541     /* This function gets called from Port 0, ie. cntrl->portAddr == BasePort
542      * The tgt_port_no is the port_no that the operation is to occur upon.
543      * The tgt_media_if is the tgt_port_no's Media i/f setting, which may or may
544      * not be the same as Port 0, found in the cntl struct.
545      */
546 #if 0 /* Not needed for our setup as we are Cu only... */
547     cntrl.phy_addr = 0U;
548     rc = viper_phy_media_sig_adjust(&cntrl, cntrl.media_if, 0);
549 #endif
550 
551     /*------------------------------------------------------------------------------------------------
552      *  Post-Reset the PHY, Run on the Base Port of the PHY, This will release Comma Mode
553      *------------------------------------------------------------------------------------------------*/
554     /* Now Run Post Reset on PHY Port 0, Initialized the 6G SerDes */
555     rc = post_reset_viper_phy(&cntrl);
556 
557     /*------------------------------------------------------------------------------------------------
558      *  Manually tweak some settings in the PHY
559      *------------------------------------------------------------------------------------------------*/
560     old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU);
561     MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, 3U);
562     temp_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U);
563     temp_reg &= (uint16_t)(~0x0010U); /* Clear media inhibit odd start delay  bit */
564     MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U, temp_reg);
565 
566     temp_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U);
567     temp_reg &= (uint16_t)(~0x0004U); /* Clear mac inhibit odd start delay  bit */
568     MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U, temp_reg);
569 
570     temp_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U);
571     temp_reg &= (uint16_t)(~0x0100U); /* Turn off 2 byte preamble */
572     MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U, temp_reg);
573 
574     MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page);
575 
576     if(TBI == this_mac->interface_type)
577     {
578         phy_reg = (uint16_t)this_mac->mac_base->PCS_CONTROL;
579         phy_reg |= 0x1000U;
580         this_mac->mac_base->PCS_CONTROL = phy_reg;
581         phy_reg |= 0x0200U;
582         this_mac->mac_base->PCS_CONTROL = phy_reg;
583 
584         /* Wait for SGMII auto-negotiation to complete. */
585         do {
586             phy_reg = (uint16_t)this_mac->mac_base->PCS_STATUS;
587             autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE;
588             --sgmii_aneg_timeout;
589         } while(((0U == autoneg_complete) && (0U != sgmii_aneg_timeout)) || (0xFFFFU == phy_reg));
590     }
591 
592     if(GMII_SGMII == this_mac->interface_type)
593     {
594         /*
595          * SGMII to GMII core with embedded MDIO interface for SGMII
596          * link control.
597          *
598          * Reset SGMII core side of I/F.
599          */
600         phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR);
601         phy_reg |= 0x9000U;    /* Reset and start autonegotiation */
602         phy_reg &= 0xFBFFU;    /* Clear Isolate bit */
603         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR, phy_reg);
604 
605         phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR);
606         phy_reg |= 0x1000U;    /* start autonegotiation */
607         phy_reg &= 0xFBFFU;    /* Clear gmii Isolate bit */
608         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR, phy_reg);
609     }
610 #if 0
611     /* Far-end loopback - enable at your peril... DO NOT try this on an open network*/
612     phy_reg =  MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U);
613     phy_reg |= 0x8U;
614     MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U, phy_reg);
615 #endif
616     /* LED control - configure LED 0 as RX indicator and LED 1 as TX indicator */
617     phy_reg =  MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU);
618     phy_reg &= 0xFF00U;
619     phy_reg |= 0x00ABU;
620     MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU, phy_reg);
621 
622     phy_reg =  MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1EU);
623     phy_reg |= 0x4000U;
624     MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1EU, phy_reg);
625 #if 0
626     /* Ethernet Packet Generator - enable at your peril... DO NOT try this on an open network */
627     old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU);
628 
629     MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, 1U);
630 
631     phy_reg =  MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU);
632     phy_reg |= 0xC000U;
633     MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU, phy_reg);
634 
635     MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page);
636 #endif
637 }
638 #endif /* MSS_MAC_USE_PHY_VSC8575_LITE */
639 
640 
641 /**************************************************************************//**
642  *
643  */
MSS_MAC_VSC8575_phy_set_link_speed(void * v_this_mac,uint32_t speed_duplex_select,mss_mac_speed_mode_t speed_mode)644 void MSS_MAC_VSC8575_phy_set_link_speed(/* mss_mac_instance_t */ void *v_this_mac, uint32_t speed_duplex_select, mss_mac_speed_mode_t speed_mode)
645 {
646     mss_mac_instance_t *this_mac = (mss_mac_instance_t *)v_this_mac;
647     uint16_t phy_reg;
648     uint32_t inc;
649     uint32_t speed_select;
650     const uint16_t mii_advertise_bits[4] = {ADVERTISE_10FULL, ADVERTISE_10HALF,
651                                             ADVERTISE_100FULL, ADVERTISE_100HALF};
652     this_mac->speed_mode = speed_mode;
653 
654     if(MSS_MAC_SPEED_AN == speed_mode) /* Set auto-negotiation advertisement. */
655     {
656         /* Set 10Mbps and 100Mbps advertisement. */
657         phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_ADVERTISE);
658         phy_reg &= (uint16_t)(~(ADVERTISE_10HALF | ADVERTISE_10FULL |
659                      ADVERTISE_100HALF | ADVERTISE_100FULL));
660 
661         speed_select = speed_duplex_select;
662         for(inc = 0U; inc < 4U; ++inc)
663         {
664             uint32_t advertise;
665             advertise = speed_select & 0x00000001U;
666             if(advertise != 0U)
667             {
668                 phy_reg |= mii_advertise_bits[inc];
669             }
670             speed_select = speed_select >> 1U;
671         }
672 
673         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_ADVERTISE, phy_reg);
674 
675         /* Set 1000Mbps advertisement. */
676         phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000);
677         phy_reg &= (uint16_t)(~(ADVERTISE_1000FULL | ADVERTISE_1000HALF));
678 
679         if((speed_duplex_select & MSS_MAC_ANEG_1000M_FD) != 0U)
680         {
681             phy_reg |= ADVERTISE_1000FULL;
682         }
683 
684         if((speed_duplex_select & MSS_MAC_ANEG_1000M_HD) != 0U)
685         {
686             phy_reg |= ADVERTISE_1000HALF;
687         }
688 
689         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000, phy_reg);
690     }
691     else
692     {
693         uint16_t temp_reg = 0x0000U; /* Default with 10M, half duplex */
694 
695         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))
696         {
697             temp_reg |= BMCR_FULLDPLX;
698         }
699 
700         if((MSS_MAC_100_FDX == this_mac->speed_mode) || (MSS_MAC_100_HDX == this_mac->speed_mode))
701         {
702             temp_reg |= BMCR_SPEED100;
703         }
704 
705         if((MSS_MAC_1000_FDX == this_mac->speed_mode) || (MSS_MAC_1000_HDX == this_mac->speed_mode))
706         {
707             temp_reg |=  BMCR_SPEED1000;
708             /* Set Master mode */
709             phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000);
710             phy_reg |= 0x1800U;
711             MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000, phy_reg);
712         }
713 
714         /* Apply static speed/duplex selection */
715         MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_BMCR, temp_reg);
716 
717         /* Full duplex mode or half duplex, multi port device */
718         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))
719         {
720             MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000, (uint16_t)(ADVERTISE_1000FULL | 0x0400U ));
721         }
722         else
723         {
724             MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000, (uint16_t)(ADVERTISE_1000HALF | 0x0400U ));
725         }
726     }
727 }
728 
729 
730 /**************************************************************************//**
731  *
732  */
MSS_MAC_VSC8575_phy_autonegotiate(const void * v_this_mac)733 void MSS_MAC_VSC8575_phy_autonegotiate(/* mss_mac_instance_t */ const void *v_this_mac)
734 {
735     const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac;
736     uint8_t link_fullduplex;
737     mss_mac_speed_t link_speed;
738     uint8_t copper_link_up;
739     volatile uint16_t phy_reg;
740     uint16_t autoneg_complete;
741     volatile uint32_t sgmii_aneg_timeout = 100000U;
742 
743     copper_link_up = this_mac->phy_get_link_status(this_mac, &link_speed, &link_fullduplex);
744     if(1U == copper_link_up)
745     {
746 #if 0 /* PMCS fixup */
747         SYSREG->MAC_CR = (SYSREG->MAC_CR & ~MAC_CONFIG_SPEED_MASK) | link_speed;
748         /* Configure duplex mode */
749         if(0U == link_fullduplex)
750         {
751             /* half duplex */
752             MAC->CFG2 &= ~CFG2_FDX_MASK;
753         }
754         else
755         {
756             /* full duplex */
757             MAC->CFG2 |= CFG2_FDX_MASK;
758         }
759 #endif
760         if(TBI == this_mac->interface_type)
761         {
762             phy_reg = (uint16_t)this_mac->mac_base->PCS_CONTROL;
763             phy_reg |= 0x1000U;
764             this_mac->mac_base->PCS_CONTROL = phy_reg;
765             phy_reg |= 0x0200U;
766             this_mac->mac_base->PCS_CONTROL = phy_reg;
767 
768             /* Wait for SGMII auto-negotiation to complete. */
769             do {
770                 phy_reg = (uint16_t)this_mac->mac_base->PCS_STATUS;
771                 autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE;
772                 --sgmii_aneg_timeout;
773             } while(((0U == autoneg_complete) && (0U != sgmii_aneg_timeout)) || (0xFFFFU == phy_reg));
774         }
775 
776         if(GMII_SGMII == this_mac->interface_type)
777         {
778             /*
779              * SGMII to GMII core with embedded MDIO interface for SGMII
780              * link control.
781              *
782              * Initiate auto-negotiation on the SGMII link.
783              */
784             phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, 0x00U);
785             phy_reg |= 0x1000U;
786             MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, 0x00U, phy_reg);
787             phy_reg |= 0x0200U;
788             MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, 0x00U, phy_reg);
789 
790             /* Wait for SGMII auto-negotiation to complete. */
791             do {
792                 phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMSR);
793                 autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE;
794                 --sgmii_aneg_timeout;
795             } while((0U == autoneg_complete) && (0U != sgmii_aneg_timeout));
796         }
797     }
798 }
799 
800 
801 /**************************************************************************//**
802  *
803  */
MSS_MAC_VSC8575_mac_autonegotiate(const void * v_this_mac)804 void MSS_MAC_VSC8575_mac_autonegotiate(/* mss_mac_instance_t */ const void *v_this_mac)
805 {
806     (void)v_this_mac;
807 }
808 
809 
810 /**************************************************************************//**
811  *
812  */
813 
MSS_MAC_VSC8575_phy_get_link_status(const void * v_this_mac,mss_mac_speed_t * speed,uint8_t * fullduplex)814 uint8_t MSS_MAC_VSC8575_phy_get_link_status
815 (
816         /* mss_mac_instance_t*/ const void *v_this_mac,
817     mss_mac_speed_t * speed,
818     uint8_t *     fullduplex
819 )
820 {
821     const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac;
822     volatile uint16_t phy_reg;
823     uint16_t copper_link_up;
824     uint8_t link_status;
825 
826     phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_BMSR);
827     copper_link_up = phy_reg & BMSR_LSTATUS;
828 
829     if(copper_link_up != MSS_MAC_LINK_DOWN)
830     {
831         uint16_t op_mode;
832 
833         /* Link is up. */
834         link_status = MSS_MAC_LINK_UP;
835 
836         phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1CU);
837 
838         op_mode = (phy_reg >> 3) & 0x0003U;
839         if(0U == (phy_reg & 0x0020U))
840         {
841             *fullduplex = MSS_MAC_HALF_DUPLEX;
842         }
843         else
844         {
845             *fullduplex = MSS_MAC_FULL_DUPLEX;
846         }
847 
848         switch(op_mode)
849         {
850             case 0U:
851                 *speed = MSS_MAC_10MBPS;
852             break;
853 
854             case 1U:
855                 *speed = MSS_MAC_100MBPS;
856             break;
857 
858             case 2U:
859                 *speed = MSS_MAC_1000MBPS;
860             break;
861 
862             default:
863                 link_status = (uint8_t)MSS_MAC_LINK_DOWN;
864             break;
865         }
866     }
867     else
868     {
869         /* Link is down. */
870         link_status = (uint8_t)MSS_MAC_LINK_DOWN;
871     }
872 
873     return link_status;
874 }
875 
876 #ifdef __cplusplus
877 }
878 #endif
879 /******************************** END OF FILE ******************************/
880 
881 
882