1 /*******************************************************************************
2 * Copyright 2020 Microchip Corporation.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Support routines for the VTS API for the Microsemi VSC8575 PHY interface
7 * to support the peripheral daughter board for the G5 SoC Emulation Platform.
8 *
9 */
10 #include <stdio.h>
11 #include <stdarg.h> /* For va_list */
12 #include <stdlib.h>
13 #include <string.h>
14 #include <stdint.h>
15 #include <inttypes.h>
16
17 #include "mpfs_hal/mss_hal.h"
18 #include "hal/hal.h"
19
20 #include "drivers/mss_ethernet_mac/mss_ethernet_mac_sw_cfg.h"
21
22 #if MSS_MAC_USE_PHY_VSC8575
23 #include "vtss_api.h" /* For BOOL and friends */
24 #include "vtss_phy_api.h" /* For PHY API Pre and Post Resets */
25 #endif
26
27 #if MSS_MAC_USE_PHY_VSC8575_LITE
28 #include "vtss_phy_common.h"
29 #include "vtss_viper_phy_prototypes.h"
30 #endif
31
32
33 #include "drivers/mss_ethernet_mac/mss_ethernet_registers.h"
34 #include "drivers/mss_ethernet_mac/mss_ethernet_mac_regs.h"
35 #include "drivers/mss_ethernet_mac/mss_ethernet_mac.h"
36 #include "drivers/mss_ethernet_mac/phy.h"
37
38 #include "drivers/mss_ethernet_mac/mss_ethernet_mac_types.h"
39
40 #ifdef _ZL303XX_FMC_BOARD
41 /* Only needed if SPI interfaces required */
42 #include "mss_spi.h"
43 #include "core_spi.h"
44 #endif
45 /* Kernel includes. */
46 #if defined(USING_FREERTOS)
47 #include "FreeRTOS.h"
48 #include "task.h"
49 #else
50 extern volatile uint64_t g_tick_counter;
51 #endif
52
53 /* Uncomment the following to enable logging of MDIO writes to memory */
54 /* VSC8575_DEBUG_MDIO */
55
56 #ifdef __DEBUG_SOCKET__
57
58 #ifndef T_E
59 #define T_E(...) \
60 printf("Error: %s, %s, %d, \n", __FILE__, __FUNCTION__, __LINE__); \
61 printf(__VA_ARGS__);
62 #endif
63
64 #ifndef T_W
65 #define T_W(...) \
66 printf("Warning: %s, %s, %d, \n", __FILE__, __FUNCTION__, __LINE__); \
67 printf(__VA_ARGS__);
68 #endif
69
70 #ifndef T_N
71 #define T_N(...) \
72 printf("Notify: %s, %s, %d, \n", __FILE__, __FUNCTION__, __LINE__); \
73 printf(__VA_ARGS__);
74 #endif
75
76 #else
77
78 #define T_E(...)
79 #define T_W(...)
80 #define T_N(...)
81 #endif
82
83 extern mss_mac_instance_t *g_my_mac;
84
85 #if MSS_MAC_USE_PHY_VSC8575
86 /* ================================================================= *
87 * Trace
88 * ================================================================= */
89
90 vtss_trace_conf_t vtss_appl_trace_conf = {
91 .level = {VTSS_TRACE_LEVEL_ERROR, VTSS_TRACE_LEVEL_ERROR}
92 };
93
printf_trace_head(const vtss_trace_layer_t layer,const vtss_trace_group_t group,const vtss_trace_level_t level,const char * file,const int line,const char * function,const char * lcont)94 static void printf_trace_head(const vtss_trace_layer_t layer,
95 const vtss_trace_group_t group,
96 const vtss_trace_level_t level,
97 const char *file,
98 const int line,
99 const char *function,
100 const char *lcont)
101 {
102 time_t t;
103 int h, m, s;
104
105 (void)group;
106 (void)file;
107 (void)line;
108 t = 0; /* time(NULL); */
109 h = (int)(t / 3600 % 24);
110 m = (int)(t / 60 % 60);
111 s = (int)(t % 60);
112 printf("%u:%02u:%02u %s/%s %s%s",
113 h, m, s,
114 layer == VTSS_TRACE_LAYER_COUNT ? "APPL": layer == VTSS_TRACE_LAYER_AIL ? "AIL" : "CIL",
115 level == VTSS_TRACE_LEVEL_ERROR ? "Error" :
116 level == VTSS_TRACE_LEVEL_INFO ? "Info " :
117 level == VTSS_TRACE_LEVEL_DEBUG ? "Debug" :
118 level == VTSS_TRACE_LEVEL_NOISE ? "Noise" : "?????",
119 function, lcont);
120 }
121
122
123 /* Trace callout function */
vtss_callout_trace_printf(const vtss_trace_layer_t layer,const vtss_trace_group_t group,const vtss_trace_level_t level,const char * file,const int line,const char * function,const char * format,...)124 void vtss_callout_trace_printf(const vtss_trace_layer_t layer,
125 const vtss_trace_group_t group,
126 const vtss_trace_level_t level,
127 const char *file,
128 const int line,
129 const char *function,
130 const char *format,
131 ...)
132 {
133 va_list va;
134 printf_trace_head(layer, group, level, file, line, function, ": ");
135
136 va_start(va, format);
137 vprintf(format, va);
138 va_end(va);
139 printf("\n");
140 }
141
142
143 /* Trace hex-dump callout function */
vtss_callout_trace_hex_dump(const vtss_trace_layer_t layer,const vtss_trace_group_t group,const vtss_trace_level_t level,const char * file,const int line,const char * function,const unsigned char * byte_p,const int byte_cnt)144 void vtss_callout_trace_hex_dump(const vtss_trace_layer_t layer,
145 const vtss_trace_group_t group,
146 const vtss_trace_level_t level,
147 const char *file,
148 const int line,
149 const char *function,
150 const unsigned char *byte_p,
151 const int byte_cnt)
152 {
153 int i;
154
155 printf_trace_head(layer, group, level, file, line, function, "\n");
156
157 for (i= 0; i < byte_cnt; i += 16) {
158 int j = 0;
159 printf("%04x:", i);
160 while (j+i < byte_cnt && j < 16) {
161 printf(" %02x", byte_p[i+j]);
162 j++;
163 }
164 putchar('\n');
165 }
166 }
167
168 vtss_rc miim_read(const vtss_inst_t inst,
169 const vtss_port_no_t phy_port,
170 const u8 phy_reg,
171 u16 *const value);
172
173 vtss_rc miim_write(const vtss_inst_t inst,
174 const vtss_port_no_t phy_port,
175 const u8 phy_reg,
176 const u16 value);
177
178 int32_t viper_fmc_board_init(vtss_init_conf_t *target);
179
180
181
182 /* Function for initializing the hardware board. */
viper_fmc_board_init(vtss_init_conf_t * target)183 int32_t viper_fmc_board_init(vtss_init_conf_t *target)
184 {
185 #ifdef _ZL303XX_FMC_BOARD
186 /* 0x30200000U is the base address of the CoreSPI in the fabric */
187 SPI_init(&g_vsc_spi, 0x30200000U , 32); /* Now is probably a good time to take care of this... */
188 /*
189 * Note: for the FMC board, the APB clock frequency is 83MHz and the maximum
190 * allowed clock frequency for the 1588 SPI interface is 25MHz. We can only choose
191 * even clock divisors and a divisor of 4 used in the design gives us a 20.75MHz SPI clock.
192 */
193 SPI_configure_master_mode(&g_vsc_spi); /* Motorola Mode 0, 8 bits selected in design */
194 SPI_set_slave_select(&g_vsc_spi, SPI_SLAVE_0);
195
196 target->spi_read_write = spi_read_write; /* Set pointer to SPI interface r/w function for this board */
197 #endif
198
199 target->miim_read = miim_read; /* Set pointer to the MIIM read function for this board. */
200 target->miim_write = miim_write; /* Set pointer to the MIIM write function for this board. */
201 return 0;
202 }
203
204
vtss_callout_lock(const vtss_api_lock_t * const lock)205 void vtss_callout_lock(const vtss_api_lock_t *const lock)
206 {
207 (void)lock;
208 }
209
210
vtss_callout_unlock(const vtss_api_lock_t * const lock)211 void vtss_callout_unlock(const vtss_api_lock_t *const lock)
212 {
213 (void)lock;
214 }
215
216
217 /**
218 * brief SPI read/write function
219 *
220 * param inst [IN] Vitesse API instance.
221 * param port_no [IN] Port number.
222 * param bitsize [IN] Size (in bytes) of bitstream following this parameter.
223 * param data [IN|OUT] Pointer to the data to be written to SPI Slave, if doing write operation.
224 * Pointer to the data read from SPI Slave, if doing read operation.
225 *
226 * return Return code.
227 **/
228 /* G5 SOC Emulation platform has no SPI interface at the moment... */
229 #ifdef _ZL303XX_FMC_BOARD
230
231 vtss_rc spi_read_write(const vtss_inst_t inst,
232 const vtss_port_no_t port_no,
233 const u8 bitsize,
234 u8 *const bitstream);
spi_read_write(const vtss_inst_t inst,const vtss_port_no_t port_no,const u8 bitsize,u8 * const bitstream)235 vtss_rc spi_read_write(const vtss_inst_t inst,
236 const vtss_port_no_t port_no,
237 const u8 bitsize,
238 u8 *const bitstream)
239 {
240 (void)inst;
241 (void)port_no;
242 /*
243 * The VTSS API transfers 32 bit values using this function.
244 *
245 * We use the bitsize parameter to determine read vs write as
246 * it will be 7 for writes and 10 for reads.
247 *
248 * The first 3 bytes are the R/W status and the register address
249 * information.
250 *
251 * When writing, the next 4 values are the frame to write,
252 * When reading, the next 3 values are padding and the last 4
253 * bytes are the read data.
254 */
255 if(7 == bitsize) /* Write operation */
256 {
257 SPI_transfer_block_vsc(&g_vsc_spi, bitstream, bitsize, 0, 0);
258 }
259 else
260 {
261 SPI_transfer_block_vsc(&g_vsc_spi, bitstream, 6, &bitstream[6], 4);
262 }
263 return VTSS_RC_OK;
264 }
265 #endif /* _ZL303XX_FMC_BOARD */
266
267
268
269 /* ================================================================= *
270 * Misc. functions
271 * ================================================================= */
272 #if 0 /* PMCS: Remove for now */
273 /* Function defining the port interface. */
274 static vtss_port_interface_t port_interface(vtss_port_no_t port_no)
275 {
276 return VTSS_PORT_INTERFACE_SGMII;
277 }
278
279 /* Function defining the port interface. */
280 static void viper_phy_pre_reset(void)
281 {
282 vtss_rc rc;
283 rc = vtss_phy_pre_reset (NULL, 0);
284 return;
285 }
286
287 /* Function defining the port interface. */
288 static vtss_rc viper_phy_post_reset(void)
289 {
290 return (vtss_phy_post_reset (NULL, 0));
291 }
292 #endif
293
294
295 /*
296 * Each board can have it own way of communicating with the chip. The miim read and write function are called by the API
297 * when the API needs to do register access.
298 *
299 * Miim read access specific for this board.
300 * In : port_no - The port to access.
301 * addr - The address to access
302 *
303 * In/Out: value - Pointer to the value to be returned
304 */
305
306
miim_read(const vtss_inst_t inst,const vtss_port_no_t phy_port,const u8 phy_reg,u16 * const value)307 vtss_rc miim_read(const vtss_inst_t inst,
308 const vtss_port_no_t phy_port,
309 const u8 phy_reg,
310 u16 *const value)
311 {
312 #ifdef __DEBUG_SOCKET__
313 const uint16_t port_no = (uint16_t) phy_port;
314 uint8_t addr = (uint8_t)phy_reg & 0xff;
315 #endif
316 (void)inst;
317 if((void *)0 != g_my_mac)
318 {
319 *value = MSS_MAC_read_phy_reg(g_my_mac, (uint8_t)(phy_port + g_my_mac->phy_addr), (uint8_t)phy_reg); /* TBD: PMCS Warning only works for single MAC/VSC8575 combination */
320 }
321
322 T_N("miim read port_no = %d, addr = %d, value = 0x%X", port_no, addr, *value);
323
324 return VTSS_RC_OK;
325 }
326
327
328 #if defined(VSC8575_DEBUG_MDIO)
329 /* Store all in 32 bit values so mem dump can view them neatly on 16 byte boundaries... */
330 typedef struct mii_debug_data
331 {
332 #if defined(USING_FREERTOS)
333 TickType_t time;
334 #else
335 uint64_t time;
336 #endif
337 /* vtss_port_no_t */ uint32_t page;
338 /* u8 */ uint32_t reg;
339 /*u16 */ uint32_t data;
340 } mii_debug_data_t;
341
342 mii_debug_data_t mii_data[1000];
343 uint32_t mii_data_index = 0;
344 uint32_t mii_page;
345 #endif
346 /*
347 * Miim write access specific for this board.
348 * In : port_no - The port to access.
349 * addr - The address to access
350 * value - The value to written
351 */
miim_write(const vtss_inst_t inst,const vtss_port_no_t phy_port,const u8 phy_reg,const u16 value)352 vtss_rc miim_write(const vtss_inst_t inst,
353 const vtss_port_no_t phy_port,
354 const u8 phy_reg,
355 const u16 value)
356 {
357 #ifdef __DEBUG_SOCKET__
358 const uint16_t port_no = (uint16_t) phy_port;
359 uint8_t addr = phy_reg & 0xff;
360 #endif
361
362 (void)inst;
363 #if defined(VSC8575_DEBUG_MDIO)
364 if(0x1f == phy_reg)
365 {
366 mii_page = value;
367 }
368 else
369 {
370 #if defined(USING_FREERTOS)
371 mii_data[mii_data_index].time = xTaskGetTickCount();
372 #else
373 mii_data[mii_data_index].time = g_tick_counter;
374 #endif
375 mii_data[mii_data_index].page = mii_page;
376 mii_data[mii_data_index].reg = phy_reg;
377 mii_data[mii_data_index].data = value;
378 mii_data_index++;
379 if(1000 == mii_data_index)
380 {
381 mii_data_index = 0;
382 }
383 }
384 #endif
385 T_N("miim_writes port_no = %d, addr = %d, value = 0x%X", port_no, addr ,value);
386 if((void *)0 != g_my_mac)
387 {
388 MSS_MAC_write_phy_reg(g_my_mac, (uint8_t)(phy_port + g_my_mac->phy_addr), (uint8_t)phy_reg, value); /* TBD: PMCS Warning only works for single MAC/VSC8575 combination */
389 }
390
391 return VTSS_RC_OK;
392 }
393 #endif /* MSS_MAC_USE_PHY_VSC8575 */
394 #if MSS_MAC_USE_PHY_VSC8575_LITE
395 int32_t miim_read(const uint32_t phy_port, const uint16_t phy_reg, uint16_t *const value);
396 int32_t miim_write(const uint32_t phy_port, const uint16_t phy_reg, const uint16_t value);
397 int32_t usleep(uint32_t usecs);
398 int32_t viper_fmc_board_init(struct phy_control_t *cntrl);
399
400
401 /*==============================================================================
402 * emulate the Unix usleep function using the taskdelay functionality of
403 * FreeRTOS. It is not very close as our example system currently uses a 1mS
404 * tick but all the instances of usleep() being called in the VTSS API Lite are
405 * for 1000uS so it should do...
406 */
usleep(uint32_t usecs)407 int32_t usleep(uint32_t usecs)
408 {
409 #if defined(USING_FREERTOS)
410 uint32_t ustick = portTICK_PERIOD_MS * 1000U; /* calculate microseconds per tick */
411
412 /* convert uS to ticks, rounding up to the nearest tick */
413 usecs = (usecs + (ustick - 1)) / ustick;
414
415 vTaskDelay(usecs);
416 #else
417 /* Assumes 1mS tick... */
418 volatile uint64_t timeout = g_tick_counter + (((uint64_t)usecs + 999ULL) / 1000ULL);
419 volatile uint64_t index = 0U;
420
421 while(g_tick_counter <= timeout)
422 {
423 index++; /* Stop debugger from locking up... */
424 }
425 #endif
426
427 return(0);
428 }
429
430
431 /*
432 * Each board can have it own way of communicating with the chip. The miim read and write function are called by the API
433 * when the API needs to do register access.
434 *
435 * Miim read access specific for this board.
436 * In : port_no - The port to access.
437 * addr - The address to access
438 *
439 * In/Out: value - Pointer to the value to be returned
440 */
miim_read(const uint32_t phy_port,const uint16_t phy_reg,uint16_t * const value)441 int32_t miim_read( const uint32_t phy_port,
442 const uint16_t phy_reg,
443 uint16_t *const value)
444 {
445 #ifdef __DEBUG_SOCKET__
446 const uint16_t port_no = (uint16_t) phy_port;
447 uint8_t addr = (uint8_t)phy_reg & 0xff;
448 #endif
449
450 if((void *)0 != g_my_mac)
451 {
452 *value = MSS_MAC_read_phy_reg(g_my_mac, (uint8_t)(phy_port + g_my_mac->phy_addr), (uint8_t)phy_reg); /* TBD: PMCS Warning only works for single MAC/VSC8575 combination */
453 }
454
455 T_N("miim read port_no = %d, addr = %d, value = 0x%X", port_no, addr, *value);
456
457 return 0;
458 }
459
460
461 /*
462 * Miim write access specific for this board.
463 * In : port_no - The port to access.
464 * addr - The address to access
465 * value - The value to written
466 *
467 * Store all in 32 bit values so mem dump can view them neatly on 16 byte boundaries...
468 */
469 #if defined(VSC8575_DEBUG_MDIO)
470 typedef struct mii_debug_data
471 {
472 TickType_t time;
473 /* vtss_port_no_t */ uint32_t page;
474 /* u8 */ uint32_t reg;
475 /*u16 */ uint32_t data;
476 } mii_debug_data_t;
477
478 mii_debug_data_t mii_data[1000];
479 uint32_t mii_data_index = 0;
480 uint32_t mii_page = 0;
481 #endif
miim_write(const uint32_t phy_port,const uint16_t phy_reg,const uint16_t value)482 int32_t miim_write( const uint32_t phy_port,
483 const uint16_t phy_reg,
484 const uint16_t value)
485 {
486 #ifdef __DEBUG_SOCKET__
487 const uint16_t port_no = (uint16_t) phy_port;
488 uint8_t addr = phy_reg & 0xff;
489 #endif
490
491 #if defined(VSC8575_DEBUG_MDIO)
492 if(0 == phy_port)
493 {
494 if(0x1f == phy_reg)
495 {
496 mii_page = value;
497 }
498 else
499 {
500 mii_data[mii_data_index].time = xTaskGetTickCount();
501 mii_data[mii_data_index].page = mii_page;
502 mii_data[mii_data_index].reg = phy_reg;
503 mii_data[mii_data_index].data = value;
504 mii_data_index++;
505 if(1000 == mii_data_index)
506 {
507 mii_data_index = 0;
508 }
509 }
510 }
511 #endif
512
513 T_N("miim_writes port_no = %d, addr = %d, value = 0x%X", port_no, addr ,value);
514 if((void *)0 != g_my_mac)
515 {
516 MSS_MAC_write_phy_reg(g_my_mac, (uint8_t)(phy_port + g_my_mac->phy_addr), (uint8_t)phy_reg, value); /* TBD: PMCS Warning only works for single MAC/VSC8575 combination */
517 }
518
519 return 0;
520 }
521
522
523 /* Function for initializing the hardware board. */
viper_fmc_board_init(struct phy_control_t * cntrl)524 int32_t viper_fmc_board_init(struct phy_control_t *cntrl)
525 {
526 cntrl->phy_reg_read = miim_read; /* Set pointer to the MIIM read function for this board. */
527 cntrl->phy_reg_write = miim_write; /* Set pointer to the MIIM write function for this board. */
528
529 return 0;
530 }
531 #endif /* MSS_MAC_USE_PHY_VSC8575_LITE */
532