]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/contrib/octeon-sdk/cvmx-helper-board.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / contrib / octeon-sdk / cvmx-helper-board.c
1 /***********************license start***************
2  * Copyright (c) 2003-2010  Cavium Networks (support@cavium.com). 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 Networks 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  NETWORKS 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: 49627 $<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 #endif
76
77 /**
78  * cvmx_override_board_link_get(int ipd_port) is a function
79  * pointer. It is meant to allow customization of the process of
80  * talking to a PHY to determine link speed. It is called every
81  * time a PHY must be polled for link status. Users should set
82  * this pointer to a function before calling any cvmx-helper
83  * operations.
84  */
85 CVMX_SHARED cvmx_helper_link_info_t (*cvmx_override_board_link_get)(int ipd_port) = NULL;
86
87 /**
88  * Return the MII PHY address associated with the given IPD
89  * port. A result of -1 means there isn't a MII capable PHY
90  * connected to this port. On chips supporting multiple MII
91  * busses the bus number is encoded in bits <15:8>.
92  *
93  * This function must be modified for every new Octeon board.
94  * Internally it uses switch statements based on the cvmx_sysinfo
95  * data to determine board types and revisions. It replies on the
96  * fact that every Octeon board receives a unique board type
97  * enumeration from the bootloader.
98  *
99  * @param ipd_port Octeon IPD port to get the MII address for.
100  *
101  * @return MII PHY address and bus number or -1.
102  */
103 int cvmx_helper_board_get_mii_address(int ipd_port)
104 {
105     /*
106      * Board types we have to know at compile-time.
107      */
108 #ifdef OCTEON_BOARD_CAPK_0100ND
109     switch (ipd_port) {
110     case 0:
111         return 2;
112     case 1:
113         return 3;
114     case 2:
115         /* XXX Switch PHY?  */
116         return -1;
117     default:
118         return -1;
119     }
120 #endif
121
122     /*
123      * For board types we can determine at runtime.
124      */
125     switch (cvmx_sysinfo_get()->board_type)
126     {
127         case CVMX_BOARD_TYPE_SIM:
128             /* Simulator doesn't have MII */
129             return -1;
130         case CVMX_BOARD_TYPE_EBT3000:
131         case CVMX_BOARD_TYPE_EBT5800:
132         case CVMX_BOARD_TYPE_THUNDER:
133         case CVMX_BOARD_TYPE_NICPRO2:
134             /* Interface 0 is SPI4, interface 1 is RGMII */
135             if ((ipd_port >= 16) && (ipd_port < 20))
136                 return ipd_port - 16;
137             else
138                 return -1;
139         case CVMX_BOARD_TYPE_LANAI2_A:
140             if (ipd_port == 0)
141                 return 0;
142             else
143                 return -1;
144         case CVMX_BOARD_TYPE_LANAI2_U:
145         case CVMX_BOARD_TYPE_LANAI2_G:
146             if (ipd_port == 0)
147                 return 0x1c;
148             else
149                 return -1;
150         case CVMX_BOARD_TYPE_KODAMA:
151         case CVMX_BOARD_TYPE_EBH3100:
152         case CVMX_BOARD_TYPE_HIKARI:
153         case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
154         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
155         case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
156             /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a
157                 switch */
158             if (ipd_port == 0)
159                 return 4;
160             else if (ipd_port == 1)
161                 return 9;
162             else
163                 return -1;
164         case CVMX_BOARD_TYPE_NAC38:
165             /* Board has 8 RGMII ports PHYs are 0-7 */
166             if ((ipd_port >= 0) && (ipd_port < 4))
167                 return ipd_port;
168             else if ((ipd_port >= 16) && (ipd_port < 20))
169                 return ipd_port - 16 + 4;
170             else
171                 return -1;
172         case CVMX_BOARD_TYPE_EBH3000:
173             /* Board has dual SPI4 and no PHYs */
174             return -1;
175         case CVMX_BOARD_TYPE_EBT5810:
176             /* Board has 10g PHYs hooked up to the MII controller on the
177             ** IXF18201 MAC.  The 10G PHYS use clause 45 MDIO which the CN58XX
178             ** does not support. All MII accesses go through the IXF part. */
179             return -1;
180         case CVMX_BOARD_TYPE_EBH5200:
181         case CVMX_BOARD_TYPE_EBH5201:
182         case CVMX_BOARD_TYPE_EBT5200:
183             /* Board has 2 management ports */
184             if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
185                 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
186             /* Board has 4 SGMII ports. The PHYs start right after the MII
187                 ports MII0 = 0, MII1 = 1, SGMII = 2-5 */
188             if ((ipd_port >= 0) && (ipd_port < 4))
189                 return ipd_port+2;
190             else
191                 return -1;
192         case CVMX_BOARD_TYPE_EBH5600:
193         case CVMX_BOARD_TYPE_EBH5601:
194         case CVMX_BOARD_TYPE_EBH5610:
195             /* Board has 1 management port */
196             if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
197                 return 0;
198             /* Board has 8 SGMII ports. 4 connect out, two connect to a switch,
199                 and 2 loop to each other */
200             if ((ipd_port >= 0) && (ipd_port < 4))
201                 return ipd_port+1;
202             else
203                 return -1;
204         case CVMX_BOARD_TYPE_EBB5600:
205             {
206                 static unsigned char qlm_switch_addr = 0;
207
208                 /* Board has 1 management port */
209                 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
210                     return 0;
211
212                 /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */
213                 if ((ipd_port >= 0) && (ipd_port < 4))
214                 {
215                     if (qlm_switch_addr != 0x3)
216                     {
217                         qlm_switch_addr = 0x3;  /* QLM1 */
218                         cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
219                         cvmx_wait_usec(11000); /* Let the write complete */
220                     }
221                     return ipd_port+1 + (1<<8);
222                 }
223                 else if ((ipd_port >= 16) && (ipd_port < 20))
224                 {
225                     if (qlm_switch_addr != 0xC)
226                     {
227                         qlm_switch_addr = 0xC;  /* QLM3 */
228                         cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
229                         cvmx_wait_usec(11000); /* Let the write complete */
230                     }
231                     return ipd_port-16+1 + (1<<8);
232                 }
233                 else
234                     return -1;
235             }
236         case CVMX_BOARD_TYPE_EBB6300:
237             /* Board has 2 management ports */
238             if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
239                 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
240             if ((ipd_port >= 0) && (ipd_port < 4))
241                 return ipd_port + 1 + (1<<8);
242             else
243                 return -1;
244         case CVMX_BOARD_TYPE_CUST_NB5:
245             if (ipd_port == 2)
246                 return 4;
247             else
248                 return -1;
249         case CVMX_BOARD_TYPE_NIC_XLE_4G:
250             /* Board has 4 SGMII ports. connected QLM3(interface 1) */
251             if ((ipd_port >= 16) && (ipd_port < 20))
252                 return ipd_port - 16 + 1;
253             else
254                 return -1;
255         case CVMX_BOARD_TYPE_NIC_XLE_10G:
256             return -1;  /* We don't use clause 45 MDIO for anything */
257         case CVMX_BOARD_TYPE_BBGW_REF:
258             return -1;  /* No PHYs are connected to Octeon, everything is through switch */
259         case CVMX_BOARD_TYPE_CUST_WSX16:
260                 if (ipd_port >= 0 && ipd_port <= 3)
261                         return ipd_port;
262                 else if (ipd_port >= 16 && ipd_port <= 19)
263                         return ipd_port - 16 + 4;
264                 else
265                         return -1;
266
267         /* Private vendor-defined boards.  */
268 #if defined(OCTEON_VENDOR_LANNER)
269         case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
270             /* Interface 1 is 12 BCM5482S PHYs.  */
271             if ((ipd_port >= 16) && (ipd_port < 28))
272                 return ipd_port - 16;
273             return -1;
274         case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
275             if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
276                 return (ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT) + 0x81;
277             if ((ipd_port >= 0) && (ipd_port < 4))
278                 return ipd_port;
279             return -1;
280         case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
281         case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
282             /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell
283                88E1111 interfaces.  */
284             switch (ipd_port) {
285             case 0:
286                 return 16;
287             case 1:
288                 return 1;
289             case 2:
290                 return 2;
291             default:
292                 return -1;
293             }
294 #endif
295     }
296
297     /* Some unknown board. Somebody forgot to update this function... */
298     cvmx_dprintf("%s: Unknown board type %d\n",
299                  __FUNCTION__, cvmx_sysinfo_get()->board_type);
300     return -1;
301 }
302 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
303 EXPORT_SYMBOL(cvmx_helper_board_get_mii_address);
304 #endif
305
306
307 /**
308  * @INTERNAL
309  * This function is the board specific method of determining an
310  * ethernet ports link speed. Most Octeon boards have Marvell PHYs
311  * and are handled by the fall through case. This function must be
312  * updated for boards that don't have the normal Marvell PHYs.
313  *
314  * This function must be modified for every new Octeon board.
315  * Internally it uses switch statements based on the cvmx_sysinfo
316  * data to determine board types and revisions. It relies on the
317  * fact that every Octeon board receives a unique board type
318  * enumeration from the bootloader.
319  *
320  * @param ipd_port IPD input port associated with the port we want to get link
321  *                 status for.
322  *
323  * @return The ports link status. If the link isn't fully resolved, this must
324  *         return zero.
325  */
326 cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
327 {
328     cvmx_helper_link_info_t result;
329     int phy_addr;
330     int is_broadcom_phy = 0;
331
332     /* Give the user a chance to override the processing of this function */
333     if (cvmx_override_board_link_get)
334         return cvmx_override_board_link_get(ipd_port);
335
336     /* Unless we fix it later, all links are defaulted to down */
337     result.u64 = 0;
338
339 #if !defined(OCTEON_BOARD_CAPK_0100ND)
340     /* This switch statement should handle all ports that either don't use
341         Marvell PHYS, or don't support in-band status */
342     switch (cvmx_sysinfo_get()->board_type)
343     {
344         case CVMX_BOARD_TYPE_SIM:
345             /* The simulator gives you a simulated 1Gbps full duplex link */
346             result.s.link_up = 1;
347             result.s.full_duplex = 1;
348             result.s.speed = 1000;
349             return result;
350         case CVMX_BOARD_TYPE_LANAI2_A:
351         case CVMX_BOARD_TYPE_LANAI2_U:
352         case CVMX_BOARD_TYPE_LANAI2_G:
353             break;
354         case CVMX_BOARD_TYPE_EBH3100:
355         case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
356         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
357         case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
358             /* Port 1 on these boards is always Gigabit */
359             if (ipd_port == 1)
360             {
361                 result.s.link_up = 1;
362                 result.s.full_duplex = 1;
363                 result.s.speed = 1000;
364                 return result;
365             }
366             /* Fall through to the generic code below */
367             break;
368         case CVMX_BOARD_TYPE_EBH5600:
369         case CVMX_BOARD_TYPE_EBH5601:
370         case CVMX_BOARD_TYPE_EBH5610:
371             /* Board has 1 management ports */
372             if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
373                 is_broadcom_phy = 1;
374             break;
375         case CVMX_BOARD_TYPE_EBH5200:
376         case CVMX_BOARD_TYPE_EBH5201:
377         case CVMX_BOARD_TYPE_EBT5200:
378             /* Board has 2 management ports */
379             if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
380                 is_broadcom_phy = 1;
381             break;
382         case CVMX_BOARD_TYPE_EBB6300:   /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/
383             if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))
384                 && cvmx_helper_board_get_mii_address(ipd_port) >= 0 && cvmx_helper_board_get_mii_address(ipd_port) <= 1)
385                 is_broadcom_phy = 1;
386             break;
387         case CVMX_BOARD_TYPE_CUST_NB5:
388             /* Port 1 on these boards is always Gigabit */
389             if (ipd_port == 1)
390             {
391                 result.s.link_up = 1;
392                 result.s.full_duplex = 1;
393                 result.s.speed = 1000;
394                 return result;
395             }
396             else /* The other port uses a broadcom PHY */
397                 is_broadcom_phy = 1;
398             break;
399         case CVMX_BOARD_TYPE_BBGW_REF:
400             /* Port 1 on these boards is always Gigabit */
401             if (ipd_port == 2)
402             {
403                 /* Port 2 is not hooked up */
404                 result.u64 = 0;
405                 return result;
406             }
407             else
408             {
409                 /* Ports 0 and 1 connect to the switch */
410                 result.s.link_up = 1;
411                 result.s.full_duplex = 1;
412                 result.s.speed = 1000;
413                 return result;
414             }
415             break;
416         /* Private vendor-defined boards.  */
417 #if defined(OCTEON_VENDOR_LANNER)
418         case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
419             /* Ports are BCM5482S */
420             is_broadcom_phy = 1;
421             break;
422         case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
423         case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
424             /* Port 0 connects to the switch */
425             if (ipd_port == 0)
426             {
427                 result.s.link_up = 1;
428                 result.s.full_duplex = 1;
429                 result.s.speed = 1000;
430                 return result;
431             }
432             break;
433 #endif
434     }
435 #endif
436
437     phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
438     if (phy_addr != -1)
439     {
440         if (is_broadcom_phy)
441         {
442             /* Below we are going to read SMI/MDIO register 0x19 which works
443                 on Broadcom parts */
444             int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19);
445             switch ((phy_status>>8) & 0x7)
446             {
447                 case 0:
448                     result.u64 = 0;
449                     break;
450                 case 1:
451                     result.s.link_up = 1;
452                     result.s.full_duplex = 0;
453                     result.s.speed = 10;
454                     break;
455                 case 2:
456                     result.s.link_up = 1;
457                     result.s.full_duplex = 1;
458                     result.s.speed = 10;
459                     break;
460                 case 3:
461                     result.s.link_up = 1;
462                     result.s.full_duplex = 0;
463                     result.s.speed = 100;
464                     break;
465                 case 4:
466                     result.s.link_up = 1;
467                     result.s.full_duplex = 1;
468                     result.s.speed = 100;
469                     break;
470                 case 5:
471                     result.s.link_up = 1;
472                     result.s.full_duplex = 1;
473                     result.s.speed = 100;
474                     break;
475                 case 6:
476                     result.s.link_up = 1;
477                     result.s.full_duplex = 0;
478                     result.s.speed = 1000;
479                     break;
480                 case 7:
481                     result.s.link_up = 1;
482                     result.s.full_duplex = 1;
483                     result.s.speed = 1000;
484                     break;
485             }
486         }
487         else
488         {
489             /* This code assumes we are using a Marvell Gigabit PHY. All the
490                 speed information can be read from register 17 in one go. Somebody
491                 using a different PHY will need to handle it above in the board
492                 specific area */
493             int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
494
495             /* If the resolve bit 11 isn't set, see if autoneg is turned off
496                 (bit 12, reg 0). The resolve bit doesn't get set properly when
497                 autoneg is off, so force it */
498             if ((phy_status & (1<<11)) == 0)
499             {
500                 int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
501                 if ((auto_status & (1<<12)) == 0)
502                     phy_status |= 1<<11;
503             }
504
505             /* Only return a link if the PHY has finished auto negotiation
506                 and set the resolved bit (bit 11) */
507             if (phy_status & (1<<11))
508             {
509 #if defined(OCTEON_BOARD_CAPK_0100ND)
510                 result.s.link_up = (phy_status>>10)&1;
511 #else
512                 result.s.link_up = 1;
513 #endif
514                 result.s.full_duplex = ((phy_status>>13)&1);
515                 switch ((phy_status>>14)&3)
516                 {
517                     case 0: /* 10 Mbps */
518                         result.s.speed = 10;
519                         break;
520                     case 1: /* 100 Mbps */
521                         result.s.speed = 100;
522                         break;
523                     case 2: /* 1 Gbps */
524                         result.s.speed = 1000;
525                         break;
526                     case 3: /* Illegal */
527                         result.u64 = 0;
528                         break;
529                 }
530             }
531         }
532     }
533     else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
534     {
535         /* We don't have a PHY address, so attempt to use in-band status. It is
536             really important that boards not supporting in-band status never get
537             here. Reading broken in-band status tends to do bad things */
538         cvmx_gmxx_rxx_rx_inbnd_t inband_status;
539         int interface = cvmx_helper_get_interface_num(ipd_port);
540         int index = cvmx_helper_get_interface_index_num(ipd_port);
541         inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
542
543         result.s.link_up = inband_status.s.status;
544         result.s.full_duplex = inband_status.s.duplex;
545         switch (inband_status.s.speed)
546         {
547             case 0: /* 10 Mbps */
548                 result.s.speed = 10;
549                 break;
550             case 1: /* 100 Mbps */
551                 result.s.speed = 100;
552                 break;
553             case 2: /* 1 Gbps */
554                 result.s.speed = 1000;
555                 break;
556             case 3: /* Illegal */
557                 result.u64 = 0;
558                 break;
559         }
560     }
561     else
562     {
563         /* We don't have a PHY address and we don't have in-band status. There
564             is no way to determine the link speed. Return down assuming this
565             port isn't wired */
566         result.u64 = 0;
567     }
568
569     /* If link is down, return all fields as zero. */
570     if (!result.s.link_up)
571         result.u64 = 0;
572
573     return result;
574 }
575
576
577 /**
578  * This function as a board specific method of changing the PHY
579  * speed, duplex, and autonegotiation. This programs the PHY and
580  * not Octeon. This can be used to force Octeon's links to
581  * specific settings.
582  *
583  * @param phy_addr  The address of the PHY to program
584  * @param link_flags
585  *                  Flags to control autonegotiation.  Bit 0 is autonegotiation
586  *                  enable/disable to maintain backward compatibility.
587  * @param link_info Link speed to program. If the speed is zero and autonegotiation
588  *                  is enabled, all possible negotiation speeds are advertised.
589  *
590  * @return Zero on success, negative on failure
591  */
592 int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags,
593                                    cvmx_helper_link_info_t link_info)
594 {
595
596     /* Set the flow control settings based on link_flags */
597     if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch)
598     {
599         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
600         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
601         reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
602         reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
603         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
604     }
605
606     /* If speed isn't set and autoneg is on advertise all supported modes */
607     if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0))
608     {
609         cvmx_mdio_phy_reg_control_t reg_control;
610         cvmx_mdio_phy_reg_status_t reg_status;
611         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
612         cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
613         cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
614
615         reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
616         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
617         reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4;
618         reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full;
619         reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half;
620         reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full;
621         reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half;
622         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
623         if (reg_status.s.capable_extended_status)
624         {
625             reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
626             reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
627             reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full;
628             reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half;
629             cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
630         }
631         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
632         reg_control.s.autoneg_enable = 1;
633         reg_control.s.restart_autoneg = 1;
634         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
635     }
636     else if ((link_flags & set_phy_link_flags_autoneg))
637     {
638         cvmx_mdio_phy_reg_control_t reg_control;
639         cvmx_mdio_phy_reg_status_t reg_status;
640         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
641         cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
642         cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
643
644         reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
645         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
646         reg_autoneg_adver.s.advert_100base_t4 = 0;
647         reg_autoneg_adver.s.advert_10base_tx_full = 0;
648         reg_autoneg_adver.s.advert_10base_tx_half = 0;
649         reg_autoneg_adver.s.advert_100base_tx_full = 0;
650         reg_autoneg_adver.s.advert_100base_tx_half = 0;
651         if (reg_status.s.capable_extended_status)
652         {
653             reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
654             reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
655             reg_control_1000.s.advert_1000base_t_full = 0;
656             reg_control_1000.s.advert_1000base_t_half = 0;
657         }
658         switch (link_info.s.speed)
659         {
660             case 10:
661                 reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex;
662                 reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex;
663                 break;
664             case 100:
665                 reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex;
666                 reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex;
667                 break;
668             case 1000:
669                 reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex;
670                 reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex;
671                 break;
672         }
673         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
674         if (reg_status.s.capable_extended_status)
675             cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
676         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
677         reg_control.s.autoneg_enable = 1;
678         reg_control.s.restart_autoneg = 1;
679         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
680     }
681     else
682     {
683         cvmx_mdio_phy_reg_control_t reg_control;
684         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
685         reg_control.s.autoneg_enable = 0;
686         reg_control.s.restart_autoneg = 1;
687         reg_control.s.duplex = link_info.s.full_duplex;
688         if (link_info.s.speed == 1000)
689         {
690             reg_control.s.speed_msb = 1;
691             reg_control.s.speed_lsb = 0;
692         }
693         else if (link_info.s.speed == 100)
694         {
695             reg_control.s.speed_msb = 0;
696             reg_control.s.speed_lsb = 1;
697         }
698         else if (link_info.s.speed == 10)
699         {
700             reg_control.s.speed_msb = 0;
701             reg_control.s.speed_lsb = 0;
702         }
703         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
704     }
705     return 0;
706 }
707
708
709 /**
710  * @INTERNAL
711  * This function is called by cvmx_helper_interface_probe() after it
712  * determines the number of ports Octeon can support on a specific
713  * interface. This function is the per board location to override
714  * this value. It is called with the number of ports Octeon might
715  * support and should return the number of actual ports on the
716  * board.
717  *
718  * This function must be modified for every new Octeon board.
719  * Internally it uses switch statements based on the cvmx_sysinfo
720  * data to determine board types and revisions. It relies on the
721  * fact that every Octeon board receives a unique board type
722  * enumeration from the bootloader.
723  *
724  * @param interface Interface to probe
725  * @param supported_ports
726  *                  Number of ports Octeon supports.
727  *
728  * @return Number of ports the actual board supports. Many times this will
729  *         simple be "support_ports".
730  */
731 int __cvmx_helper_board_interface_probe(int interface, int supported_ports)
732 {
733     switch (cvmx_sysinfo_get()->board_type)
734     {
735         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
736         case CVMX_BOARD_TYPE_LANAI2_A:
737         case CVMX_BOARD_TYPE_LANAI2_U:
738         case CVMX_BOARD_TYPE_LANAI2_G:
739             if (interface == 0)
740                 return 2;
741             break;
742         case CVMX_BOARD_TYPE_BBGW_REF:
743             if (interface == 0)
744                 return 2;
745             break;
746         case CVMX_BOARD_TYPE_NIC_XLE_4G:
747             if (interface == 0)
748                 return 0;
749             break;
750         /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
751             which we don't support. Disable ports connected to it */
752         case CVMX_BOARD_TYPE_EBH5600:
753             if (interface == 1)
754                 return 0;
755             break;
756         case CVMX_BOARD_TYPE_EBB5600:
757 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
758             if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_PICMG)
759                 return 0;
760 #endif
761             break;
762         case CVMX_BOARD_TYPE_EBT5810:
763             return 1;  /* Two ports on each SPI: 1 hooked to MAC, 1 loopback
764                        ** Loopback disabled by default. */
765 #if defined(OCTEON_VENDOR_LANNER)
766         case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
767             if (interface == 1)
768                 return 12;
769             break;
770 #endif
771     }
772 #ifdef CVMX_BUILD_FOR_UBOOT
773     if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi"))
774         return 0;
775 #endif
776     return supported_ports;
777 }
778
779
780 /**
781  * @INTERNAL
782  * Enable packet input/output from the hardware. This function is
783  * called after by cvmx_helper_packet_hardware_enable() to
784  * perform board specific initialization. For most boards
785  * nothing is needed.
786  *
787  * @param interface Interface to enable
788  *
789  * @return Zero on success, negative on failure
790  */
791 int __cvmx_helper_board_hardware_enable(int interface)
792 {
793     if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5)
794     {
795         if (interface == 0)
796         {
797             /* Different config for switch port */
798             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
799             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
800             /* Boards with gigabit WAN ports need a different setting that is
801                 compatible with 100 Mbit settings */
802             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc);
803             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc);
804         }
805     }
806     else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_LANAI2_U)
807     {
808         if (interface == 0)
809         {
810             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 16);
811             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 16);
812         }
813     }
814     else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5)
815     {
816         /* Broadcom PHYs require different ASX clocks. Unfortunately
817             many customer don't define a new board Id and simply
818             mangle the CN3010_EVB_HS5 */
819         if (interface == 0)
820         {
821             /* Some customers boards use a hacked up bootloader that identifies them as
822             ** CN3010_EVB_HS5 evaluation boards.  This leads to all kinds of configuration
823             ** problems.  Detect one case, and print warning, while trying to do the right thing.
824             */
825             int phy_addr = cvmx_helper_board_get_mii_address(0);
826             if (phy_addr != -1)
827             {
828                 int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2);
829                 /* Is it a Broadcom PHY? */
830                 if (phy_identifier == 0x0143)
831                 {
832                     cvmx_dprintf("\n");
833                     cvmx_dprintf("ERROR:\n");
834                     cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
835                     cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
836                     cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n");
837                     cvmx_dprintf("ERROR:\n");
838                     cvmx_dprintf("\n");
839                     cvmx_wait(1000000000);
840                     cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5);
841                     cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5);
842                 }
843             }
844         }
845     }
846     return 0;
847 }
848
849
850 /**
851  * @INTERNAL
852  * Gets the clock type used for the USB block based on board type.
853  * Used by the USB code for auto configuration of clock type.
854  *
855  * @return USB clock type enumeration
856  */
857 cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void)
858 {
859     switch (cvmx_sysinfo_get()->board_type)
860     {
861         case CVMX_BOARD_TYPE_BBGW_REF:
862         case CVMX_BOARD_TYPE_LANAI2_A:
863         case CVMX_BOARD_TYPE_LANAI2_U:
864         case CVMX_BOARD_TYPE_LANAI2_G:
865 #if defined(OCTEON_VENDOR_LANNER)
866     case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
867     case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
868 #endif
869             return USB_CLOCK_TYPE_CRYSTAL_12;
870     }
871     return USB_CLOCK_TYPE_REF_48;
872 }
873
874
875 /**
876  * @INTERNAL
877  * Adjusts the number of available USB ports on Octeon based on board
878  * specifics.
879  *
880  * @param supported_ports expected number of ports based on chip type;
881  *
882  *
883  * @return number of available usb ports, based on board specifics.
884  *         Return value is supported_ports if function does not
885  *         override.
886  */
887 int __cvmx_helper_board_usb_get_num_ports(int supported_ports)
888 {
889     switch (cvmx_sysinfo_get()->board_type)
890     {
891         case CVMX_BOARD_TYPE_NIC_XLE_4G:
892             return 0;
893     }
894
895     return supported_ports;
896 }
897
898