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