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