1 /***********************license start***************
2  * Copyright (c) 2003-2011  Cavium Inc. ([email protected]). All rights
3  * reserved.
4  *
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *   * Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  *
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17 
18  *   * Neither the name of Cavium Inc. nor the names of
19  *     its contributors may be used to endorse or promote products
20  *     derived from this software without specific prior written
21  *     permission.
22 
23  * This Software, including technical data, may be subject to U.S. export  control
24  * laws, including the U.S. Export Administration Act and its  associated
25  * regulations, and may be subject to export or import  regulations in other
26  * countries.
27 
28  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29  * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30  * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31  * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32  * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33  * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34  * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35  * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36  * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37  * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38  ***********************license end**************************************/
39 
40 
41 
42 
43 
44 
45 
46 /**
47  * @file
48  *
49  * Helper functions to abstract board specific data about
50  * network ports from the rest of the cvmx-helper files.
51  *
52  * <hr>$Revision: 70030 $<hr>
53  */
54 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
55 #include <linux/module.h>
56 #include <asm/octeon/cvmx.h>
57 #include <asm/octeon/cvmx-bootinfo.h>
58 #include <asm/octeon/cvmx-smix-defs.h>
59 #include <asm/octeon/cvmx-gmxx-defs.h>
60 #include <asm/octeon/cvmx-asxx-defs.h>
61 #include <asm/octeon/cvmx-mdio.h>
62 #include <asm/octeon/cvmx-helper.h>
63 #include <asm/octeon/cvmx-helper-util.h>
64 #include <asm/octeon/cvmx-helper-board.h>
65 #include <asm/octeon/cvmx-twsi.h>
66 #else
67 #include "cvmx.h"
68 #include "cvmx-app-init.h"
69 #include "cvmx-sysinfo.h"
70 #include "cvmx-twsi.h"
71 #include "cvmx-mdio.h"
72 #include "cvmx-helper.h"
73 #include "cvmx-helper-util.h"
74 #include "cvmx-helper-board.h"
75 #include "cvmx-gpio.h"
76 #if !defined(__FreeBSD__) || !defined(_KERNEL)
77 #ifdef __U_BOOT__
78 # include <libfdt.h>
79 #else
80 # include "libfdt/libfdt.h"
81 #endif
82 #endif
83 #include "cvmx-swap.h"
84 #endif
85 
86 /**
87  * cvmx_override_board_link_get(int ipd_port) is a function
88  * pointer. It is meant to allow customization of the process of
89  * talking to a PHY to determine link speed. It is called every
90  * time a PHY must be polled for link status. Users should set
91  * this pointer to a function before calling any cvmx-helper
92  * operations.
93  */
94 CVMX_SHARED cvmx_helper_link_info_t (*cvmx_override_board_link_get)(int ipd_port) = NULL;
95 
96 #if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
97 
cvmx_retry_i2c_write(int twsi_id,uint8_t dev_addr,uint16_t internal_addr,int num_bytes,int ia_width_bytes,uint64_t data)98 static void cvmx_retry_i2c_write(int twsi_id, uint8_t dev_addr, uint16_t internal_addr, int num_bytes, int ia_width_bytes, uint64_t data)
99 {
100     int tries = 3;
101     int r;
102     do {
103         r = cvmx_twsix_write_ia(twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes, data);
104     } while (tries-- > 0 && r < 0);
105 }
106 
__pip_eth_node(const void * fdt_addr,int aliases,int ipd_port)107 static int __pip_eth_node(const void *fdt_addr, int aliases, int ipd_port)
108 {
109     char name_buffer[20];
110     const char*pip_path;
111     int pip, iface, eth;
112     int interface_num    = cvmx_helper_get_interface_num(ipd_port);
113     int interface_index  = cvmx_helper_get_interface_index_num(ipd_port);
114 
115     pip_path = fdt_getprop(fdt_addr, aliases, "pip", NULL);
116     if (!pip_path)
117     {
118         cvmx_dprintf("ERROR: pip path not found in device tree\n");
119         return -1;
120     }
121     pip = fdt_path_offset(fdt_addr, pip_path);
122     if (pip < 0)
123     {
124         cvmx_dprintf("ERROR: pip not found in device tree\n");
125         return -1;
126     }
127 #ifdef __U_BOOT__
128     sprintf(name_buffer, "interface@%d", interface_num);
129 #else
130     snprintf(name_buffer, sizeof(name_buffer), "interface@%d", interface_num);
131 #endif
132     iface =  fdt_subnode_offset(fdt_addr, pip, name_buffer);
133     if (iface < 0)
134     {
135         cvmx_dprintf("ERROR : pip intf %d not found in device tree \n",
136                      interface_num);
137         return -1;
138     }
139 #ifdef __U_BOOT__
140     sprintf(name_buffer, "ethernet@%x", interface_index);
141 #else
142     snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", interface_index);
143 #endif
144     eth = fdt_subnode_offset(fdt_addr, iface, name_buffer);
145     if (eth < 0)
146     {
147         cvmx_dprintf("ERROR : pip interface@%d ethernet@%d not found in device "
148                      "tree\n", interface_num, interface_index);
149         return -1;
150     }
151     return eth;
152 }
153 
__mix_eth_node(const void * fdt_addr,int aliases,int interface_index)154 static int __mix_eth_node(const void *fdt_addr, int aliases, int interface_index)
155 {
156     char name_buffer[20];
157     const char*mix_path;
158     int mix;
159 
160 #ifdef __U_BOOT__
161     sprintf(name_buffer, "mix%d", interface_index);
162 #else
163     snprintf(name_buffer, sizeof(name_buffer), "mix%d", interface_index);
164 #endif
165     mix_path = fdt_getprop(fdt_addr, aliases, name_buffer, NULL);
166     if (!mix_path)
167     {
168         cvmx_dprintf("ERROR: mix%d path not found in device tree\n",interface_index);
169     }
170     mix = fdt_path_offset(fdt_addr, mix_path);
171     if (mix < 0)
172     {
173         cvmx_dprintf("ERROR: %s not found in device tree\n", mix_path);
174         return -1;
175     }
176     return mix;
177 }
178 
179 typedef struct cvmx_phy_info
180 {
181     int phy_addr;
182     int direct_connect;
183     cvmx_phy_type_t phy_type;
184 }cvmx_phy_info_t;
185 
186 
__mdiobus_addr_to_unit(uint32_t addr)187 static int __mdiobus_addr_to_unit(uint32_t addr)
188 {
189     int unit = (addr >> 7) & 3;
190     if (!OCTEON_IS_MODEL(OCTEON_CN68XX))
191         unit >>= 1;
192     return unit;
193 }
194 /**
195  * Return the MII PHY address associated with the given IPD
196  * port. The phy address is obtained from the device tree.
197  *
198  * @param ipd_port Octeon IPD port to get the MII address for.
199  *
200  * @return MII PHY address and bus number or -1.
201  */
202 
__get_phy_info_from_dt(int ipd_port)203 static cvmx_phy_info_t __get_phy_info_from_dt(int ipd_port)
204 {
205     const void *fdt_addr = CASTPTR(const void *, cvmx_sysinfo_get()->fdt_addr);
206     uint32_t *phy_handle;
207     int aliases, eth, phy, phy_parent, phandle, ret;
208     cvmx_phy_info_t phy_info;
209     int mdio_unit=-1;
210     const char *phy_comaptible_str;
211     uint32_t *phy_addr_ptr;
212 
213     phy_info.phy_addr = -1;
214     phy_info.direct_connect = -1;
215     phy_info.phy_type = (cvmx_phy_type_t) -1;
216 
217     if (!fdt_addr)
218     {
219         cvmx_dprintf("No device tree found.\n");
220         return phy_info;
221     }
222     aliases = fdt_path_offset(fdt_addr, "/aliases");
223     if (aliases < 0) {
224         cvmx_dprintf("Error: No /aliases node in device tree.\n");
225         return phy_info;
226     }
227     if (ipd_port < 0)
228     {
229         int interface_index = ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
230         eth = __mix_eth_node(fdt_addr, aliases, interface_index) ;
231     }
232     else
233     {
234         eth = __pip_eth_node(fdt_addr, aliases, ipd_port);
235     }
236     if (eth < 0 )
237     {
238         cvmx_dprintf("ERROR : cannot find interface for ipd_port=%d\n", ipd_port);
239         return phy_info;
240     }
241     /* Get handle to phy */
242     phy_handle = (uint32_t *) fdt_getprop(fdt_addr, eth, "phy-handle", NULL);
243     if (!phy_handle)
244     {
245         cvmx_dprintf("ERROR : phy handle not found in device tree ipd_port=%d"
246                      "\n", ipd_port);
247         return phy_info;
248     }
249     phandle = cvmx_be32_to_cpu(*phy_handle);
250     phy = fdt_node_offset_by_phandle(fdt_addr, phandle);
251     if (phy < 0)
252     {
253         cvmx_dprintf("ERROR : cannot find phy for ipd_port=%d ret=%d\n",
254                      ipd_port, phy);
255         return phy_info;
256     }
257     phy_comaptible_str = (const char *) fdt_getprop(fdt_addr, phy,
258                                                     "compatible", NULL);
259     if (!phy_comaptible_str)
260     {
261         cvmx_dprintf("ERROR : no compatible prop in phy\n");
262         return phy_info;
263     }
264     if (memcmp("marvell", phy_comaptible_str, strlen("marvell")) == 0)
265     {
266         phy_info.phy_type = MARVELL_GENERIC_PHY;
267     }
268     else if (memcmp("broadcom", phy_comaptible_str, strlen("broadcom")) == 0)
269     {
270         phy_info.phy_type = BROADCOM_GENERIC_PHY;
271     }
272     else
273     {
274         phy_info.phy_type = -1;
275     }
276 
277     /* Check if PHY parent is the octeon MDIO bus. Some boards are connected
278        though a MUX and for them direct_connect_to_phy will be 0 */
279     phy_parent = fdt_parent_offset(fdt_addr, phy);
280     if (phy_parent < 0)
281     {
282         cvmx_dprintf("ERROR : cannot find phy parent for ipd_port=%d ret=%d\n",
283                      ipd_port, phy_parent);
284         return phy_info;
285     }
286     ret = fdt_node_check_compatible(fdt_addr, phy_parent,
287                                     "cavium,octeon-3860-mdio");
288     if (ret == 0)
289     {
290         phy_info.direct_connect = 1 ;
291         uint32_t *mdio_reg_base = (uint32_t *) fdt_getprop(fdt_addr, phy_parent,"reg",0);
292         if (mdio_reg_base == 0)
293         {
294             cvmx_dprintf("ERROR : unable to get reg property in phy mdio\n");
295             return phy_info;
296         }
297         mdio_unit = __mdiobus_addr_to_unit(mdio_reg_base[1]);
298         //cvmx_dprintf("phy parent=%s reg_base=%08x unit=%d \n",
299         //             fdt_get_name(fdt_addr,phy_parent, NULL), mdio_reg_base[1], mdio_unit);
300     }
301     else
302     {
303         phy_info.direct_connect = 0;
304         /* The PHY is not directly connected to the Octeon MDIO bus.
305            SE doesn't  have abstractions for MDIO MUX or MDIO MUX drivers and
306            hence for the non direct cases code will be needed which is
307            board specific.
308            For now the the MDIO Unit is defaulted to 1.
309         */
310         mdio_unit = 1;
311     }
312 
313     phy_addr_ptr = (uint32_t *) fdt_getprop(fdt_addr, phy, "reg", NULL);
314     phy_info.phy_addr = cvmx_be32_to_cpu(*phy_addr_ptr) | mdio_unit << 8;
315     return phy_info;
316 
317 }
318 
319 /**
320  * Return the MII PHY address associated with the given IPD
321  * port. The phy address is obtained from the device tree.
322  *
323  * @param ipd_port Octeon IPD port to get the MII address for.
324  *
325  * @return MII PHY address and bus number or -1.
326  */
327 
cvmx_helper_board_get_mii_address_from_dt(int ipd_port)328 int cvmx_helper_board_get_mii_address_from_dt(int ipd_port)
329 {
330         cvmx_phy_info_t phy_info = __get_phy_info_from_dt(ipd_port);
331         return phy_info.phy_addr;
332 }
333 #endif
334 
335 /**
336  * Return the MII PHY address associated with the given IPD
337  * port. A result of -1 means there isn't a MII capable PHY
338  * connected to this port. On chips supporting multiple MII
339  * busses the bus number is encoded in bits <15:8>.
340  *
341  * This function must be modified for every new Octeon board.
342  * Internally it uses switch statements based on the cvmx_sysinfo
343  * data to determine board types and revisions. It replies on the
344  * fact that every Octeon board receives a unique board type
345  * enumeration from the bootloader.
346  *
347  * @param ipd_port Octeon IPD port to get the MII address for.
348  *
349  * @return MII PHY address and bus number or -1.
350  */
cvmx_helper_board_get_mii_address(int ipd_port)351 int cvmx_helper_board_get_mii_address(int ipd_port)
352 {
353     /*
354      * Board types we have to know at compile-time.
355      */
356 #ifdef OCTEON_BOARD_CAPK_0100ND
357     switch (ipd_port) {
358     case 0:
359 	return 2;
360     case 1:
361 	return 3;
362     case 2:
363 	/* XXX Switch PHY?  */
364 	return -1;
365     default:
366 	return -1;
367     }
368 #endif
369 
370     /*
371      * For board types we can determine at runtime.
372      */
373     if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
374         return -1;
375 #if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
376     if (cvmx_sysinfo_get()->fdt_addr)
377     {
378         cvmx_phy_info_t phy_info = __get_phy_info_from_dt(ipd_port);
379         //cvmx_dprintf("ipd_port=%d phy_addr=%d\n", ipd_port, phy_info.phy_addr);
380         if (phy_info.phy_addr >= 0) return phy_info.phy_addr;
381     }
382 #endif
383     switch (cvmx_sysinfo_get()->board_type)
384     {
385         case CVMX_BOARD_TYPE_SIM:
386             /* Simulator doesn't have MII */
387             return -1;
388 #if !defined(OCTEON_VENDOR_GEFES)
389         case CVMX_BOARD_TYPE_EBT5800:
390         case CVMX_BOARD_TYPE_NICPRO2:
391 #endif
392         case CVMX_BOARD_TYPE_EBT3000:
393         case CVMX_BOARD_TYPE_THUNDER:
394             /* Interface 0 is SPI4, interface 1 is RGMII */
395             if ((ipd_port >= 16) && (ipd_port < 20))
396                 return ipd_port - 16;
397             else
398                 return -1;
399         case CVMX_BOARD_TYPE_LANAI2_A:
400             if (ipd_port == 0)
401                 return 0;
402             else
403                 return -1;
404         case CVMX_BOARD_TYPE_LANAI2_U:
405         case CVMX_BOARD_TYPE_LANAI2_G:
406             if (ipd_port == 0)
407                 return 0x1c;
408             else
409                 return -1;
410         case CVMX_BOARD_TYPE_KODAMA:
411         case CVMX_BOARD_TYPE_EBH3100:
412         case CVMX_BOARD_TYPE_HIKARI:
413         case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
414         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
415 #if !defined(OCTEON_VENDOR_GEFES)
416         case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
417 #endif
418             /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a
419                 switch */
420             if (ipd_port == 0)
421                 return 4;
422             else if (ipd_port == 1)
423                 return 9;
424             else
425                 return -1;
426         case CVMX_BOARD_TYPE_EBH3000:
427             /* Board has dual SPI4 and no PHYs */
428             return -1;
429         case CVMX_BOARD_TYPE_EBT5810:
430             /* Board has 10g PHYs hooked up to the MII controller on the
431             ** IXF18201 MAC.  The 10G PHYS use clause 45 MDIO which the CN58XX
432             ** does not support. All MII accesses go through the IXF part. */
433             return -1;
434         case CVMX_BOARD_TYPE_EBH5200:
435         case CVMX_BOARD_TYPE_EBH5201:
436         case CVMX_BOARD_TYPE_EBT5200:
437             /* Board has 2 management ports */
438             if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
439                 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
440             /* Board has 4 SGMII ports. The PHYs start right after the MII
441                 ports MII0 = 0, MII1 = 1, SGMII = 2-5 */
442             if ((ipd_port >= 0) && (ipd_port < 4))
443                 return ipd_port+2;
444             else
445                 return -1;
446         case CVMX_BOARD_TYPE_EBH5600:
447         case CVMX_BOARD_TYPE_EBH5601:
448         case CVMX_BOARD_TYPE_EBH5610:
449             /* Board has 1 management port */
450             if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
451                 return 0;
452             /* Board has 8 SGMII ports. 4 connect out, two connect to a switch,
453                 and 2 loop to each other */
454             if ((ipd_port >= 0) && (ipd_port < 4))
455                 return ipd_port+1;
456             else
457                 return -1;
458         case CVMX_BOARD_TYPE_EBT5600:
459 	    /* Board has 1 management port */
460             if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
461                 return 0;
462 	    /* Board has 1 XAUI port connected to a switch.  */
463 	    return -1;
464         case CVMX_BOARD_TYPE_EBB5600:
465             {
466                 static unsigned char qlm_switch_addr = 0;
467 
468                 /* Board has 1 management port */
469                 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
470                     return 0;
471 
472                 /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */
473                 if ((ipd_port >= 0) && (ipd_port < 4))
474                 {
475                     if (qlm_switch_addr != 0x3)
476                     {
477                         qlm_switch_addr = 0x3;  /* QLM1 */
478                         cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
479                         cvmx_wait_usec(11000); /* Let the write complete */
480                     }
481                     return ipd_port+1 + (1<<8);
482                 }
483                 else if ((ipd_port >= 16) && (ipd_port < 20))
484                 {
485                     if (qlm_switch_addr != 0xC)
486                     {
487                         qlm_switch_addr = 0xC;  /* QLM3 */
488                         cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
489                         cvmx_wait_usec(11000); /* Let the write complete */
490                     }
491                     return ipd_port-16+1 + (1<<8);
492                 }
493                 else
494                     return -1;
495             }
496         case CVMX_BOARD_TYPE_EBB6300:
497             /* Board has 2 management ports */
498             if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
499                 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
500             if ((ipd_port >= 0) && (ipd_port < 4))
501                 return ipd_port + 1 + (1<<8);
502             else
503                 return -1;
504         case CVMX_BOARD_TYPE_EBB6800:
505             /* Board has 1 management ports */
506             if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
507                 return 6;
508             if (ipd_port >= 0x800 && ipd_port < 0x900) /* QLM 0*/
509                 return 0x101 + ((ipd_port >> 4) & 3); /* SMI 1*/
510             if (ipd_port >= 0xa00 && ipd_port < 0xb00) /* QLM 2*/
511                 return 0x201 + ((ipd_port >> 4) & 3); /* SMI 2*/
512             if (ipd_port >= 0xb00 && ipd_port < 0xc00) /* QLM 3*/
513                 return 0x301 + ((ipd_port >> 4) & 3); /* SMI 3*/
514             if (ipd_port >= 0xc00 && ipd_port < 0xd00) /* QLM 4*/
515                 return 0x001 + ((ipd_port >> 4) & 3); /* SMI 0*/
516             return -1;
517         case CVMX_BOARD_TYPE_EP6300C:
518             if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
519                 return 0x01;
520             if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT+1)
521                 return 0x02;
522 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
523             {
524                 int interface = cvmx_helper_get_interface_num(ipd_port);
525                 int mode = cvmx_helper_interface_get_mode(interface);
526                 if (mode == CVMX_HELPER_INTERFACE_MODE_XAUI)
527                     return ipd_port;
528                 else if ((ipd_port >= 0) && (ipd_port < 4))
529                     return ipd_port + 3;
530                 else
531                     return -1;
532             }
533 #endif
534             break;
535         case CVMX_BOARD_TYPE_CUST_NB5:
536             if (ipd_port == 2)
537                 return 4;
538             else
539                 return -1;
540         case CVMX_BOARD_TYPE_NIC_XLE_4G:
541             /* Board has 4 SGMII ports. connected QLM3(interface 1) */
542             if ((ipd_port >= 16) && (ipd_port < 20))
543                 return ipd_port - 16 + 1;
544             else
545                 return -1;
546         case CVMX_BOARD_TYPE_NIC_XLE_10G:
547         case CVMX_BOARD_TYPE_NIC10E:
548             return -1;  /* We don't use clause 45 MDIO for anything */
549         case CVMX_BOARD_TYPE_NIC4E:
550             if (ipd_port >= 0 && ipd_port <= 3)
551                 return (ipd_port + 0x1f) & 0x1f;
552             else
553                 return -1;
554         case CVMX_BOARD_TYPE_NIC2E:
555             if (ipd_port >= 0 && ipd_port <= 1)
556                 return (ipd_port + 1);
557             else
558                 return -1;
559         case CVMX_BOARD_TYPE_REDWING:
560 	    return -1;  /* No PHYs connected to Octeon */
561         case CVMX_BOARD_TYPE_BBGW_REF:
562             return -1;  /* No PHYs are connected to Octeon, everything is through switch */
563 	case CVMX_BOARD_TYPE_CUST_WSX16:
564 		if (ipd_port >= 0 && ipd_port <= 3)
565 			return ipd_port;
566 		else if (ipd_port >= 16 && ipd_port <= 19)
567 			return ipd_port - 16 + 4;
568 		else
569 			return -1;
570 
571 	/* Private vendor-defined boards.  */
572 #if defined(OCTEON_VENDOR_LANNER)
573 	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
574 	    /* Interface 1 is 12 BCM5482S PHYs.  */
575             if ((ipd_port >= 16) && (ipd_port < 28))
576                 return ipd_port - 16;
577 	    return -1;
578 	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
579             if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
580 		return (ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT) + 0x81;
581             if ((ipd_port >= 0) && (ipd_port < 4))
582                 return ipd_port;
583 	    return -1;
584 	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
585 	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
586 	    /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell
587 	       88E1111 interfaces.  */
588 	    switch (ipd_port) {
589 	    case 0:
590 		return 16;
591 	    case 1:
592 		return 1;
593 	    case 2:
594 		return 2;
595 	    default:
596 		return -1;
597 	    }
598 #endif
599 #if defined(OCTEON_VENDOR_UBIQUITI)
600 	case CVMX_BOARD_TYPE_CUST_UBIQUITI_E100:
601 	case CVMX_BOARD_TYPE_CUST_UBIQUITI_E120:
602 	    if (ipd_port > 2)
603 		return -1;
604 	    return (7 - ipd_port);
605 #endif
606 #if defined(OCTEON_VENDOR_RADISYS)
607 	case CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE:
608 	    /* No MII.  */
609 	    return -1;
610 #endif
611 #if defined(OCTEON_VENDOR_GEFES)
612         case CVMX_BOARD_TYPE_AT5810:
613 		return -1;
614         case CVMX_BOARD_TYPE_TNPA3804:
615     	case CVMX_BOARD_TYPE_CUST_TNPA5804:
616 	case CVMX_BOARD_TYPE_CUST_W5800:
617 	case CVMX_BOARD_TYPE_WNPA3850:
618 	case CVMX_BOARD_TYPE_W3860:
619 		return -1;// RGMII boards should use inbad status
620 	case CVMX_BOARD_TYPE_CUST_W5651X:
621 	case CVMX_BOARD_TYPE_CUST_W5650:
622 	case CVMX_BOARD_TYPE_CUST_TNPA56X4:
623 	case CVMX_BOARD_TYPE_CUST_TNPA5651X:
624         case CVMX_BOARD_TYPE_CUST_W63XX:
625 		return -1; /* No PHYs are connected to Octeon, PHYs inside of SFPs which is accessed over TWSI */
626 	case CVMX_BOARD_TYPE_CUST_W5434:
627 		/* Board has 4 SGMII ports. 4 connect out
628 		 * must return the MII address of the PHY connected to each IPD port
629 		 */
630 		if ((ipd_port >= 16) && (ipd_port < 20))
631 			return ipd_port - 16 + 0x40;
632 		else
633 			return -1;
634 #endif
635     }
636 
637     /* Some unknown board. Somebody forgot to update this function... */
638     cvmx_dprintf("%s: Unknown board type %d\n",
639                  __FUNCTION__, cvmx_sysinfo_get()->board_type);
640     return -1;
641 }
642 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
643 EXPORT_SYMBOL(cvmx_helper_board_get_mii_address);
644 #endif
645 
646 /**
647  * @INTERNAL
648  * Get link state of marvell PHY
649  */
__get_marvell_phy_link_state(int phy_addr)650 static cvmx_helper_link_info_t __get_marvell_phy_link_state(int phy_addr)
651 {
652     cvmx_helper_link_info_t  result;
653     int phy_status;
654 
655     result.u64 = 0;
656     /*All the speed information can be read from register 17 in one go.*/
657     phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
658 
659     /* If the resolve bit 11 isn't set, see if autoneg is turned off
660        (bit 12, reg 0). The resolve bit doesn't get set properly when
661        autoneg is off, so force it */
662     if ((phy_status & (1<<11)) == 0)
663     {
664         int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
665         if ((auto_status & (1<<12)) == 0)
666             phy_status |= 1<<11;
667     }
668 
669     /* Only return a link if the PHY has finished auto negotiation
670        and set the resolved bit (bit 11) */
671     if (phy_status & (1<<11))
672     {
673         result.s.link_up = 1;
674         result.s.full_duplex = ((phy_status>>13)&1);
675         switch ((phy_status>>14)&3)
676         {
677             case 0: /* 10 Mbps */
678                 result.s.speed = 10;
679                 break;
680             case 1: /* 100 Mbps */
681                 result.s.speed = 100;
682                 break;
683             case 2: /* 1 Gbps */
684                 result.s.speed = 1000;
685                 break;
686             case 3: /* Illegal */
687                 result.u64 = 0;
688                 break;
689         }
690     }
691     return result;
692 }
693 
694 /**
695  * @INTERNAL
696  * Get link state of broadcom PHY
697  */
__get_broadcom_phy_link_state(int phy_addr)698 static cvmx_helper_link_info_t __get_broadcom_phy_link_state(int phy_addr)
699 {
700     cvmx_helper_link_info_t  result;
701     int phy_status;
702 
703     result.u64 = 0;
704     /* Below we are going to read SMI/MDIO register 0x19 which works
705        on Broadcom parts */
706     phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19);
707     switch ((phy_status>>8) & 0x7)
708     {
709         case 0:
710             result.u64 = 0;
711             break;
712         case 1:
713             result.s.link_up = 1;
714             result.s.full_duplex = 0;
715             result.s.speed = 10;
716             break;
717         case 2:
718             result.s.link_up = 1;
719             result.s.full_duplex = 1;
720             result.s.speed = 10;
721             break;
722         case 3:
723             result.s.link_up = 1;
724             result.s.full_duplex = 0;
725             result.s.speed = 100;
726             break;
727         case 4:
728             result.s.link_up = 1;
729             result.s.full_duplex = 1;
730             result.s.speed = 100;
731             break;
732         case 5:
733             result.s.link_up = 1;
734             result.s.full_duplex = 1;
735             result.s.speed = 100;
736             break;
737         case 6:
738             result.s.link_up = 1;
739             result.s.full_duplex = 0;
740             result.s.speed = 1000;
741             break;
742         case 7:
743             result.s.link_up = 1;
744             result.s.full_duplex = 1;
745             result.s.speed = 1000;
746             break;
747     }
748     return result;
749 }
750 
751 
752 /**
753  * @INTERNAL
754  * Get link state using inband status
755  */
__get_inband_link_state(int ipd_port)756 static cvmx_helper_link_info_t __get_inband_link_state(int ipd_port)
757 {
758     cvmx_helper_link_info_t  result;
759     cvmx_gmxx_rxx_rx_inbnd_t inband_status;
760     int interface = cvmx_helper_get_interface_num(ipd_port);
761     int index = cvmx_helper_get_interface_index_num(ipd_port);
762 
763     result.u64 = 0;
764     inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
765     result.s.link_up = inband_status.s.status;
766     result.s.full_duplex = inband_status.s.duplex;
767     switch (inband_status.s.speed)
768     {
769         case 0: /* 10 Mbps */
770             result.s.speed = 10;
771             break;
772         case 1: /* 100 Mbps */
773             result.s.speed = 100;
774             break;
775         case 2: /* 1 Gbps */
776             result.s.speed = 1000;
777             break;
778         case 3: /* Illegal */
779             result.u64 = 0;
780             break;
781     }
782     return result;
783 }
784 
785 #if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
786 /**
787  * @INTERNAL
788  * Switch MDIO mux to the specified port.
789  */
__switch_mdio_mux(int ipd_port)790 static int __switch_mdio_mux(int ipd_port)
791 {
792     /* This method is board specific and doesn't use the device tree
793        information as SE doesn't implement MDIO MUX abstration */
794     switch (cvmx_sysinfo_get()->board_type)
795     {
796         case CVMX_BOARD_TYPE_EBB5600:
797         {
798             static unsigned char qlm_switch_addr = 0;
799             /* Board has 1 management port */
800             if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
801                 return 0;
802             /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */
803             if ((ipd_port >= 0) && (ipd_port < 4))
804             {
805                 if (qlm_switch_addr != 0x3)
806                 {
807                     qlm_switch_addr = 0x3;  /* QLM1 */
808                     cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
809                     cvmx_wait_usec(11000); /* Let the write complete */
810                 }
811                 return ipd_port+1 + (1<<8);
812             }
813             else if ((ipd_port >= 16) && (ipd_port < 20))
814             {
815                 if (qlm_switch_addr != 0xC)
816                 {
817                     qlm_switch_addr = 0xC;  /* QLM3 */
818                     cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
819                     cvmx_wait_usec(11000); /* Let the write complete */
820                 }
821                 return ipd_port-16+1 + (1<<8);
822             }
823             else
824                 return -1;
825         }
826         case CVMX_BOARD_TYPE_EBB6600:
827         {
828             static unsigned char qlm_switch_addr = 0;
829             int old_twsi_switch_reg;
830             /* Board has 2 management ports */
831             if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) &&
832                 (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
833                 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
834             if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */
835             {
836                 if (qlm_switch_addr != 2)
837                 {
838                     int tries;
839                     qlm_switch_addr = 2;
840                     tries = 3;
841                     do {
842                         old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0);
843                     } while (tries-- > 0 && old_twsi_switch_reg < 0);
844                     /* Set I2C MUX to enable port expander */
845                     cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8);
846                     /* Set selecter to QLM 1 */
847                     cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xff);
848                     /* disable port expander */
849                     cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg);
850                 }
851                 return 0x101 + ipd_port;
852             }
853             else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 1 */
854             {
855                 if (qlm_switch_addr != 1)
856                 {
857                     int tries;
858                     qlm_switch_addr = 1;
859                     tries = 3;
860                     do {
861                             old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0);
862                     } while (tries-- > 0 && old_twsi_switch_reg < 0);
863                     /* Set I2C MUX to enable port expander */
864                     cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8);
865                     /* Set selecter to QLM 2 */
866                     cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xf7);
867                     /* disable port expander */
868                     cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg);
869                 }
870                 return 0x101 + (ipd_port - 16);
871             } else
872                 return -1;
873         }
874         case CVMX_BOARD_TYPE_EBB6100:
875         {
876             static char gpio_configured = 0;
877 
878             if (!gpio_configured)
879             {
880                 cvmx_gpio_cfg(3, 1);
881                 gpio_configured = 1;
882             }
883             /* Board has 2 management ports */
884             if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) &&
885                 (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
886                 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
887             if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */
888             {
889                 cvmx_gpio_set(1ull << 3);
890                 return 0x101 + ipd_port;
891             }
892             else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 0 */
893             {
894                 cvmx_gpio_clear(1ull << 3);
895                 return 0x101 + (ipd_port - 16);
896             }
897             else
898             {
899                 printf("%s: Unknown ipd port 0x%x\n", __func__, ipd_port);
900                 return -1;
901             }
902         }
903         default:
904         {
905             cvmx_dprintf("ERROR : unexpected mdio switch for board=%08x\n",
906                          cvmx_sysinfo_get()->board_type);
907             return -1;
908         }
909     }
910     /* should never get here */
911     return -1;
912 }
913 
914 /**
915  * @INTERNAL
916  * This function is used ethernet ports link speed. This functions uses the
917  * device tree information to determine the phy address and type of PHY.
918  * The only supproted PHYs are Marvell and Broadcom.
919  *
920  * @param ipd_port IPD input port associated with the port we want to get link
921  *                 status for.
922  *
923  * @return The ports link status. If the link isn't fully resolved, this must
924  *         return zero.
925  */
926 
__cvmx_helper_board_link_get_from_dt(int ipd_port)927 cvmx_helper_link_info_t __cvmx_helper_board_link_get_from_dt(int ipd_port)
928 {
929     cvmx_helper_link_info_t  result;
930     cvmx_phy_info_t phy_info;
931 
932     result.u64 = 0;
933     if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
934     {
935         /* The simulator gives you a simulated 1Gbps full duplex link */
936         result.s.link_up = 1;
937         result.s.full_duplex = 1;
938         result.s.speed = 1000;
939         return result;
940     }
941     phy_info = __get_phy_info_from_dt(ipd_port);
942     //cvmx_dprintf("ipd_port=%d phy_addr=%d dc=%d type=%d \n", ipd_port,
943     //             phy_info.phy_addr, phy_info.direct_connect, phy_info.phy_type);
944     if (phy_info.phy_addr < 0) return result;
945 
946     if (phy_info.direct_connect == 0)
947         __switch_mdio_mux(ipd_port);
948     switch(phy_info.phy_type)
949     {
950         case BROADCOM_GENERIC_PHY:
951             result = __get_broadcom_phy_link_state(phy_info.phy_addr);
952             break;
953         case MARVELL_GENERIC_PHY:
954             result = __get_marvell_phy_link_state(phy_info.phy_addr);
955             break;
956         default:
957             result = __get_inband_link_state(ipd_port);
958     }
959     return result;
960 
961 }
962 #endif
963 
964 /**
965  * @INTERNAL
966  * This function invokes  __cvmx_helper_board_link_get_from_dt when device tree
967  * info is available. When the device tree information is not available then
968  * this function is the board specific method of determining an
969  * ethernet ports link speed. Most Octeon boards have Marvell PHYs
970  * and are handled by the fall through case. This function must be
971  * updated for boards that don't have the normal Marvell PHYs.
972  *
973  * This function must be modified for every new Octeon board.
974  * Internally it uses switch statements based on the cvmx_sysinfo
975  * data to determine board types and revisions. It relies on the
976  * fact that every Octeon board receives a unique board type
977  * enumeration from the bootloader.
978  *
979  * @param ipd_port IPD input port associated with the port we want to get link
980  *                 status for.
981  *
982  * @return The ports link status. If the link isn't fully resolved, this must
983  *         return zero.
984  */
__cvmx_helper_board_link_get(int ipd_port)985 cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
986 {
987     cvmx_helper_link_info_t result;
988     int phy_addr;
989     int is_broadcom_phy = 0;
990 
991 #if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
992     if (cvmx_sysinfo_get()->fdt_addr)
993     {
994         return __cvmx_helper_board_link_get_from_dt(ipd_port);
995     }
996 #endif
997 
998     /* Give the user a chance to override the processing of this function */
999     if (cvmx_override_board_link_get)
1000         return cvmx_override_board_link_get(ipd_port);
1001 
1002     /* Unless we fix it later, all links are defaulted to down */
1003     result.u64 = 0;
1004 
1005 #if !defined(OCTEON_BOARD_CAPK_0100ND)
1006     /* This switch statement should handle all ports that either don't use
1007         Marvell PHYS, or don't support in-band status */
1008     switch (cvmx_sysinfo_get()->board_type)
1009     {
1010         case CVMX_BOARD_TYPE_SIM:
1011             /* The simulator gives you a simulated 1Gbps full duplex link */
1012             result.s.link_up = 1;
1013             result.s.full_duplex = 1;
1014             result.s.speed = 1000;
1015             return result;
1016         case CVMX_BOARD_TYPE_LANAI2_A:
1017         case CVMX_BOARD_TYPE_LANAI2_U:
1018         case CVMX_BOARD_TYPE_LANAI2_G:
1019             break;
1020         case CVMX_BOARD_TYPE_EBH3100:
1021         case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
1022         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
1023 #if !defined(OCTEON_VENDOR_GEFES)
1024         case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
1025 #endif
1026             /* Port 1 on these boards is always Gigabit */
1027             if (ipd_port == 1)
1028             {
1029                 result.s.link_up = 1;
1030                 result.s.full_duplex = 1;
1031                 result.s.speed = 1000;
1032                 return result;
1033             }
1034             /* Fall through to the generic code below */
1035             break;
1036         case CVMX_BOARD_TYPE_EBT5600:
1037         case CVMX_BOARD_TYPE_EBH5600:
1038         case CVMX_BOARD_TYPE_EBH5601:
1039         case CVMX_BOARD_TYPE_EBH5610:
1040             /* Board has 1 management ports */
1041             if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
1042                 is_broadcom_phy = 1;
1043             break;
1044         case CVMX_BOARD_TYPE_EBH5200:
1045         case CVMX_BOARD_TYPE_EBH5201:
1046         case CVMX_BOARD_TYPE_EBT5200:
1047             /* Board has 2 management ports */
1048             if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
1049                 is_broadcom_phy = 1;
1050             break;
1051         case CVMX_BOARD_TYPE_EBB6100:
1052         case CVMX_BOARD_TYPE_EBB6300:   /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/
1053         case CVMX_BOARD_TYPE_EBB6600:   /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/
1054             if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))
1055                 && cvmx_helper_board_get_mii_address(ipd_port) >= 0 && cvmx_helper_board_get_mii_address(ipd_port) <= 1)
1056                 is_broadcom_phy = 1;
1057             break;
1058         case CVMX_BOARD_TYPE_EP6300C:
1059             is_broadcom_phy = 1;
1060             break;
1061         case CVMX_BOARD_TYPE_CUST_NB5:
1062             /* Port 1 on these boards is always Gigabit */
1063             if (ipd_port == 1)
1064             {
1065                 result.s.link_up = 1;
1066                 result.s.full_duplex = 1;
1067                 result.s.speed = 1000;
1068                 return result;
1069             }
1070             else /* The other port uses a broadcom PHY */
1071                 is_broadcom_phy = 1;
1072             break;
1073         case CVMX_BOARD_TYPE_BBGW_REF:
1074             /* Port 1 on these boards is always Gigabit */
1075             if (ipd_port == 2)
1076             {
1077                 /* Port 2 is not hooked up */
1078                 result.u64 = 0;
1079                 return result;
1080             }
1081             else
1082             {
1083                 /* Ports 0 and 1 connect to the switch */
1084                 result.s.link_up = 1;
1085                 result.s.full_duplex = 1;
1086                 result.s.speed = 1000;
1087                 return result;
1088             }
1089         case CVMX_BOARD_TYPE_NIC4E:
1090         case CVMX_BOARD_TYPE_NIC2E:
1091             is_broadcom_phy = 1;
1092             break;
1093 	/* Private vendor-defined boards.  */
1094 #if defined(OCTEON_VENDOR_LANNER)
1095 	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
1096 	    /* Ports are BCM5482S */
1097 	    is_broadcom_phy = 1;
1098 	    break;
1099 	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
1100 	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
1101 	    /* Port 0 connects to the switch */
1102 	    if (ipd_port == 0)
1103 	    {
1104                 result.s.link_up = 1;
1105                 result.s.full_duplex = 1;
1106                 result.s.speed = 1000;
1107 		return result;
1108 	    }
1109 	    break;
1110 #endif
1111 #if defined(OCTEON_VENDOR_GEFES)
1112 	case CVMX_BOARD_TYPE_CUST_TNPA5651X:
1113 	   /* Since we don't auto-negotiate... 1Gbps full duplex link */
1114 	   result.s.link_up = 1;
1115 	   result.s.full_duplex = 1;
1116 	   result.s.speed = 1000;
1117 	   return result;
1118 	   break;
1119 #endif
1120     }
1121 #endif
1122 
1123     phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
1124     //cvmx_dprintf("ipd_port=%d phy_addr=%d broadcom=%d\n",
1125     //             ipd_port, phy_addr, is_broadcom_phy);
1126     if (phy_addr != -1)
1127     {
1128         if (is_broadcom_phy)
1129         {
1130             result =  __get_broadcom_phy_link_state(phy_addr);
1131         }
1132         else
1133         {
1134             /* This code assumes we are using a Marvell Gigabit PHY. */
1135             result = __get_marvell_phy_link_state(phy_addr);
1136         }
1137     }
1138     else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX)
1139              || OCTEON_IS_MODEL(OCTEON_CN50XX))
1140     {
1141         /* We don't have a PHY address, so attempt to use in-band status. It is
1142             really important that boards not supporting in-band status never get
1143             here. Reading broken in-band status tends to do bad things */
1144         result = __get_inband_link_state(ipd_port);
1145     }
1146 #if defined(OCTEON_VENDOR_GEFES)
1147     else if( (OCTEON_IS_MODEL(OCTEON_CN56XX)) || (OCTEON_IS_MODEL(OCTEON_CN63XX)) )
1148     {
1149         int interface = cvmx_helper_get_interface_num(ipd_port);
1150         int index = cvmx_helper_get_interface_index_num(ipd_port);
1151         cvmx_pcsx_miscx_ctl_reg_t mode_type;
1152         cvmx_pcsx_mrx_status_reg_t mrx_status;
1153         cvmx_pcsx_anx_adv_reg_t anxx_adv;
1154         cvmx_pcsx_sgmx_lp_adv_reg_t sgmii_inband_status;
1155 
1156         anxx_adv.u64 = cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface));
1157         mrx_status.u64 = cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG(index, interface));
1158 
1159         mode_type.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
1160 
1161         /* Read Octeon's inband status */
1162         sgmii_inband_status.u64 = cvmx_read_csr(CVMX_PCSX_SGMX_LP_ADV_REG(index, interface));
1163 
1164         result.s.link_up = sgmii_inband_status.s.link;
1165         result.s.full_duplex = sgmii_inband_status.s.dup;
1166         switch (sgmii_inband_status.s.speed)
1167         {
1168         case 0: /* 10 Mbps */
1169             result.s.speed = 10;
1170             break;
1171         case 1: /* 100 Mbps */
1172             result.s.speed = 100;
1173             break;
1174         case 2: /* 1 Gbps */
1175             result.s.speed = 1000;
1176             break;
1177         case 3: /* Illegal */
1178             result.s.speed = 0;
1179             result.s.link_up = 0;
1180             break;
1181         }
1182     }
1183 #endif
1184     else
1185     {
1186         /* We don't have a PHY address and we don't have in-band status. There
1187             is no way to determine the link speed. Return down assuming this
1188             port isn't wired */
1189         result.u64 = 0;
1190     }
1191 
1192     /* If link is down, return all fields as zero. */
1193     if (!result.s.link_up)
1194         result.u64 = 0;
1195 
1196     return result;
1197 }
1198 
1199 
1200 /**
1201  * This function as a board specific method of changing the PHY
1202  * speed, duplex, and autonegotiation. This programs the PHY and
1203  * not Octeon. This can be used to force Octeon's links to
1204  * specific settings.
1205  *
1206  * @param phy_addr  The address of the PHY to program
1207  * @param link_flags
1208  *                  Flags to control autonegotiation.  Bit 0 is autonegotiation
1209  *                  enable/disable to maintain backward compatibility.
1210  * @param link_info Link speed to program. If the speed is zero and autonegotiation
1211  *                  is enabled, all possible negotiation speeds are advertised.
1212  *
1213  * @return Zero on success, negative on failure
1214  */
cvmx_helper_board_link_set_phy(int phy_addr,cvmx_helper_board_set_phy_link_flags_types_t link_flags,cvmx_helper_link_info_t link_info)1215 int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags,
1216                                    cvmx_helper_link_info_t link_info)
1217 {
1218 
1219     /* Set the flow control settings based on link_flags */
1220     if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch)
1221     {
1222         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1223         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1224         reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
1225         reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
1226         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1227     }
1228 
1229     /* If speed isn't set and autoneg is on advertise all supported modes */
1230     if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0))
1231     {
1232         cvmx_mdio_phy_reg_control_t reg_control;
1233         cvmx_mdio_phy_reg_status_t reg_status;
1234         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1235         cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
1236         cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
1237 
1238         reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
1239         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1240         reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4;
1241         reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full;
1242         reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half;
1243         reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full;
1244         reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half;
1245         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1246         if (reg_status.s.capable_extended_status)
1247         {
1248             reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
1249             reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
1250             reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full;
1251             reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half;
1252             cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
1253         }
1254         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1255         reg_control.s.autoneg_enable = 1;
1256         reg_control.s.restart_autoneg = 1;
1257         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1258     }
1259     else if ((link_flags & set_phy_link_flags_autoneg))
1260     {
1261         cvmx_mdio_phy_reg_control_t reg_control;
1262         cvmx_mdio_phy_reg_status_t reg_status;
1263         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1264         cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
1265 
1266         reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
1267         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1268         reg_autoneg_adver.s.advert_100base_t4 = 0;
1269         reg_autoneg_adver.s.advert_10base_tx_full = 0;
1270         reg_autoneg_adver.s.advert_10base_tx_half = 0;
1271         reg_autoneg_adver.s.advert_100base_tx_full = 0;
1272         reg_autoneg_adver.s.advert_100base_tx_half = 0;
1273         if (reg_status.s.capable_extended_status)
1274         {
1275             reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
1276             reg_control_1000.s.advert_1000base_t_full = 0;
1277             reg_control_1000.s.advert_1000base_t_half = 0;
1278         }
1279         switch (link_info.s.speed)
1280         {
1281             case 10:
1282                 reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex;
1283                 reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex;
1284                 break;
1285             case 100:
1286                 reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex;
1287                 reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex;
1288                 break;
1289             case 1000:
1290                 reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex;
1291                 reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex;
1292                 break;
1293         }
1294         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1295         if (reg_status.s.capable_extended_status)
1296             cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
1297         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1298         reg_control.s.autoneg_enable = 1;
1299         reg_control.s.restart_autoneg = 1;
1300         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1301     }
1302     else
1303     {
1304         cvmx_mdio_phy_reg_control_t reg_control;
1305         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1306         reg_control.s.autoneg_enable = 0;
1307         reg_control.s.restart_autoneg = 1;
1308         reg_control.s.duplex = link_info.s.full_duplex;
1309         if (link_info.s.speed == 1000)
1310         {
1311             reg_control.s.speed_msb = 1;
1312             reg_control.s.speed_lsb = 0;
1313         }
1314         else if (link_info.s.speed == 100)
1315         {
1316             reg_control.s.speed_msb = 0;
1317             reg_control.s.speed_lsb = 1;
1318         }
1319         else if (link_info.s.speed == 10)
1320         {
1321             reg_control.s.speed_msb = 0;
1322             reg_control.s.speed_lsb = 0;
1323         }
1324         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1325     }
1326     return 0;
1327 }
1328 
1329 
1330 /**
1331  * @INTERNAL
1332  * This function is called by cvmx_helper_interface_probe() after it
1333  * determines the number of ports Octeon can support on a specific
1334  * interface. This function is the per board location to override
1335  * this value. It is called with the number of ports Octeon might
1336  * support and should return the number of actual ports on the
1337  * board.
1338  *
1339  * This function must be modified for every new Octeon board.
1340  * Internally it uses switch statements based on the cvmx_sysinfo
1341  * data to determine board types and revisions. It relies on the
1342  * fact that every Octeon board receives a unique board type
1343  * enumeration from the bootloader.
1344  *
1345  * @param interface Interface to probe
1346  * @param supported_ports
1347  *                  Number of ports Octeon supports.
1348  *
1349  * @return Number of ports the actual board supports. Many times this will
1350  *         simple be "support_ports".
1351  */
__cvmx_helper_board_interface_probe(int interface,int supported_ports)1352 int __cvmx_helper_board_interface_probe(int interface, int supported_ports)
1353 {
1354     switch (cvmx_sysinfo_get()->board_type)
1355     {
1356         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
1357         case CVMX_BOARD_TYPE_LANAI2_A:
1358         case CVMX_BOARD_TYPE_LANAI2_U:
1359         case CVMX_BOARD_TYPE_LANAI2_G:
1360             if (interface == 0)
1361                 return 2;
1362 	    break;
1363         case CVMX_BOARD_TYPE_BBGW_REF:
1364             if (interface == 0)
1365                 return 2;
1366 	    break;
1367         case CVMX_BOARD_TYPE_NIC_XLE_4G:
1368             if (interface == 0)
1369                 return 0;
1370 	    break;
1371         /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
1372             which we don't support. Disable ports connected to it */
1373         case CVMX_BOARD_TYPE_EBH5600:
1374             if (interface == 1)
1375                 return 0;
1376 	    break;
1377         case CVMX_BOARD_TYPE_EBB5600:
1378 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
1379             if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_PICMG)
1380                 return 0;
1381 #endif
1382 	    break;
1383         case CVMX_BOARD_TYPE_EBT5600:
1384 	    /* Disable loopback.  */
1385 	    if (interface == 3)
1386 		return 0;
1387 	    break;
1388         case CVMX_BOARD_TYPE_EBT5810:
1389             return 1;  /* Two ports on each SPI: 1 hooked to MAC, 1 loopback
1390                        ** Loopback disabled by default. */
1391         case CVMX_BOARD_TYPE_NIC2E:
1392             if (interface == 0)
1393                 return 2;
1394 #if defined(OCTEON_VENDOR_LANNER)
1395 	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
1396 	    if (interface == 1)
1397 	        return 12;
1398 	    break;
1399 #endif
1400 #if defined(OCTEON_VENDOR_GEFES)
1401         case CVMX_BOARD_TYPE_CUST_TNPA5651X:
1402                 if (interface < 2) /* interface can be EITHER 0 or 1 */
1403 			return 1;//always return 1 for XAUI and SGMII mode.
1404 		break;
1405         case CVMX_BOARD_TYPE_CUST_TNPA56X4:
1406 		if ((interface == 0) &&
1407 			(cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_SGMII))
1408 		{
1409 			cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
1410 
1411 			/* For this port we need to set the mode to 1000BaseX */
1412 			pcsx_miscx_ctl_reg.u64 =
1413 				cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(0, interface));
1414 			pcsx_miscx_ctl_reg.cn56xx.mode = 1;
1415 			cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(0, interface),
1416 						   pcsx_miscx_ctl_reg.u64);
1417 			pcsx_miscx_ctl_reg.u64 =
1418 				cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(1, interface));
1419 			pcsx_miscx_ctl_reg.cn56xx.mode = 1;
1420 			cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(1, interface),
1421 						   pcsx_miscx_ctl_reg.u64);
1422 
1423 			return 2;
1424 		}
1425 		break;
1426 #endif
1427     }
1428 #ifdef CVMX_BUILD_FOR_UBOOT
1429     if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi"))
1430         return 0;
1431 #endif
1432     return supported_ports;
1433 }
1434 
1435 
1436 /**
1437  * @INTERNAL
1438  * Enable packet input/output from the hardware. This function is
1439  * called after by cvmx_helper_packet_hardware_enable() to
1440  * perform board specific initialization. For most boards
1441  * nothing is needed.
1442  *
1443  * @param interface Interface to enable
1444  *
1445  * @return Zero on success, negative on failure
1446  */
__cvmx_helper_board_hardware_enable(int interface)1447 int __cvmx_helper_board_hardware_enable(int interface)
1448 {
1449     if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5)
1450     {
1451         if (interface == 0)
1452         {
1453             /* Different config for switch port */
1454             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
1455             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
1456             /* Boards with gigabit WAN ports need a different setting that is
1457                 compatible with 100 Mbit settings */
1458             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc);
1459             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc);
1460         }
1461     }
1462     else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_LANAI2_U)
1463     {
1464         if (interface == 0)
1465         {
1466             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 16);
1467             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 16);
1468         }
1469     }
1470     else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5)
1471     {
1472         /* Broadcom PHYs require different ASX clocks. Unfortunately
1473             many customer don't define a new board Id and simply
1474             mangle the CN3010_EVB_HS5 */
1475         if (interface == 0)
1476         {
1477             /* Some customers boards use a hacked up bootloader that identifies them as
1478             ** CN3010_EVB_HS5 evaluation boards.  This leads to all kinds of configuration
1479             ** problems.  Detect one case, and print warning, while trying to do the right thing.
1480             */
1481             int phy_addr = cvmx_helper_board_get_mii_address(0);
1482             if (phy_addr != -1)
1483             {
1484                 int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2);
1485                 /* Is it a Broadcom PHY? */
1486                 if (phy_identifier == 0x0143)
1487                 {
1488                     cvmx_dprintf("\n");
1489                     cvmx_dprintf("ERROR:\n");
1490                     cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
1491                     cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
1492                     cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n");
1493                     cvmx_dprintf("ERROR:\n");
1494                     cvmx_dprintf("\n");
1495                     cvmx_wait(1000000000);
1496                     cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5);
1497                     cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5);
1498                 }
1499             }
1500         }
1501     }
1502 #if defined(OCTEON_VENDOR_UBIQUITI)
1503     else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_UBIQUITI_E100 ||
1504         cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_UBIQUITI_E120)
1505     {
1506 	/* Configure ASX cloks for all ports on interface 0.  */
1507 	if (interface == 0)
1508 	{
1509 	    int port;
1510 
1511 	    for (port = 0; port < 3; port++) {
1512                 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 16);
1513                 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 0);
1514 	    }
1515 	}
1516     }
1517 #endif
1518     return 0;
1519 }
1520 
1521 
1522 /**
1523  * @INTERNAL
1524  * Gets the clock type used for the USB block based on board type.
1525  * Used by the USB code for auto configuration of clock type.
1526  *
1527  * @return USB clock type enumeration
1528  */
__cvmx_helper_board_usb_get_clock_type(void)1529 cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void)
1530 {
1531 #if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
1532     const void *fdt_addr = CASTPTR(const void *, cvmx_sysinfo_get()->fdt_addr);
1533     int nodeoffset;
1534     const void *nodep;
1535     int len;
1536     uint32_t speed = 0;
1537     const char *type = NULL;
1538 
1539     if (fdt_addr)
1540     {
1541         nodeoffset = fdt_path_offset(fdt_addr, "/soc/uctl");
1542         if (nodeoffset < 0)
1543             nodeoffset = fdt_path_offset(fdt_addr, "/soc/usbn");
1544 
1545         if (nodeoffset >= 0)
1546         {
1547             nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-type", &len);
1548             if (nodep != NULL && len > 0)
1549                 type = (const char *)nodep;
1550             else
1551                 type = "unknown";
1552             nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-frequency", &len);
1553             if (nodep != NULL && len == sizeof(uint32_t))
1554                 speed = fdt32_to_cpu(*(int *)nodep);
1555             else
1556                 speed = 0;
1557             if (!strcmp(type, "crystal"))
1558             {
1559                 if (speed == 0 || speed == 12000000)
1560                     return USB_CLOCK_TYPE_CRYSTAL_12;
1561                 else
1562                     printf("Warning: invalid crystal speed for USB clock type in FDT\n");
1563             }
1564             else if (!strcmp(type, "external"))
1565             {
1566                 switch (speed) {
1567                 case 12000000:
1568                     return USB_CLOCK_TYPE_REF_12;
1569                 case 24000000:
1570                     return USB_CLOCK_TYPE_REF_24;
1571                 case 0:
1572                 case 48000000:
1573                     return USB_CLOCK_TYPE_REF_48;
1574                 default:
1575                     printf("Warning: invalid USB clock speed of %u hz in FDT\n", speed);
1576                 }
1577             }
1578             else
1579                 printf("Warning: invalid USB reference clock type \"%s\" in FDT\n", type ? type : "NULL");
1580         }
1581     }
1582 #endif
1583     switch (cvmx_sysinfo_get()->board_type)
1584     {
1585         case CVMX_BOARD_TYPE_BBGW_REF:
1586         case CVMX_BOARD_TYPE_LANAI2_A:
1587         case CVMX_BOARD_TYPE_LANAI2_U:
1588         case CVMX_BOARD_TYPE_LANAI2_G:
1589 #if defined(OCTEON_VENDOR_LANNER)
1590         case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
1591         case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
1592 #endif
1593 #if defined(OCTEON_VENDOR_UBIQUITI)
1594         case CVMX_BOARD_TYPE_CUST_UBIQUITI_E100:
1595         case CVMX_BOARD_TYPE_CUST_UBIQUITI_E120:
1596 #endif
1597 #if defined(OCTEON_BOARD_CAPK_0100ND)
1598 	case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
1599 #endif
1600 #if defined(OCTEON_VENDOR_GEFES) /* All GEFES' boards use same xtal type */
1601         case CVMX_BOARD_TYPE_TNPA3804:
1602         case CVMX_BOARD_TYPE_AT5810:
1603         case CVMX_BOARD_TYPE_WNPA3850:
1604         case CVMX_BOARD_TYPE_W3860:
1605         case CVMX_BOARD_TYPE_CUST_TNPA5804:
1606         case CVMX_BOARD_TYPE_CUST_W5434:
1607         case CVMX_BOARD_TYPE_CUST_W5650:
1608         case CVMX_BOARD_TYPE_CUST_W5800:
1609         case CVMX_BOARD_TYPE_CUST_W5651X:
1610         case CVMX_BOARD_TYPE_CUST_TNPA5651X:
1611         case CVMX_BOARD_TYPE_CUST_TNPA56X4:
1612         case CVMX_BOARD_TYPE_CUST_W63XX:
1613 #endif
1614         case CVMX_BOARD_TYPE_NIC10E_66:
1615             return USB_CLOCK_TYPE_CRYSTAL_12;
1616         case CVMX_BOARD_TYPE_NIC10E:
1617             return USB_CLOCK_TYPE_REF_12;
1618         default:
1619             break;
1620     }
1621     if (OCTEON_IS_MODEL(OCTEON_CN6XXX)	/* Most boards except NIC10e use a 12MHz crystal */
1622         || OCTEON_IS_MODEL(OCTEON_CNF7XXX))
1623         return USB_CLOCK_TYPE_CRYSTAL_12;
1624     return USB_CLOCK_TYPE_REF_48;
1625 }
1626 
1627 
1628 /**
1629  * @INTERNAL
1630  * Adjusts the number of available USB ports on Octeon based on board
1631  * specifics.
1632  *
1633  * @param supported_ports expected number of ports based on chip type;
1634  *
1635  *
1636  * @return number of available usb ports, based on board specifics.
1637  *         Return value is supported_ports if function does not
1638  *         override.
1639  */
__cvmx_helper_board_usb_get_num_ports(int supported_ports)1640 int __cvmx_helper_board_usb_get_num_ports(int supported_ports)
1641 {
1642     switch (cvmx_sysinfo_get()->board_type)
1643     {
1644         case CVMX_BOARD_TYPE_NIC_XLE_4G:
1645         case CVMX_BOARD_TYPE_NIC2E:
1646             return 0;
1647     }
1648 
1649     return supported_ports;
1650 }
1651 
1652 
1653