]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/contrib/octeon-sdk/cvmx-helper-board.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / contrib / octeon-sdk / cvmx-helper-board.c
1 /***********************license start***************
2  *  Copyright (c) 2003-2008 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  *  TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24  *  AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25  *  OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26  *  RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27  *  REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28  *  DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29  *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30  *  PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31  *  POSSESSION OR CORRESPONDENCE TO DESCRIPTION.  THE ENTIRE RISK ARISING OUT
32  *  OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
33  *
34  *
35  *  For any questions regarding licensing please contact marketing@caviumnetworks.com
36  *
37  ***********************license end**************************************/
38
39
40
41
42
43
44 /**
45  * @file
46  *
47  * Helper functions to abstract board specific data about
48  * network ports from the rest of the cvmx-helper files.
49  *
50  * <hr>$Revision: 41946 $<hr>
51  */
52 #include "cvmx.h"
53 #include "cvmx-app-init.h"
54 #include "cvmx-mdio.h"
55 #include "cvmx-sysinfo.h"
56 #include "cvmx-helper.h"
57 #include "cvmx-helper-util.h"
58 #include "cvmx-helper-board.h"
59
60 /**
61  * cvmx_override_board_link_get(int ipd_port) is a function
62  * pointer. It is meant to allow customization of the process of
63  * talking to a PHY to determine link speed. It is called every
64  * time a PHY must be polled for link status. Users should set
65  * this pointer to a function before calling any cvmx-helper
66  * operations.
67  */
68 CVMX_SHARED cvmx_helper_link_info_t (*cvmx_override_board_link_get)(int ipd_port) = NULL;
69
70 /**
71  * Return the MII PHY address associated with the given IPD
72  * port. A result of -1 means there isn't a MII capable PHY
73  * connected to this port. On chips supporting multiple MII
74  * busses the bus number is encoded in bits <15:8>.
75  *
76  * This function must be modified for every new Octeon board.
77  * Internally it uses switch statements based on the cvmx_sysinfo
78  * data to determine board types and revisions. It replies on the
79  * fact that every Octeon board receives a unique board type
80  * enumeration from the bootloader.
81  *
82  * @param ipd_port Octeon IPD port to get the MII address for.
83  *
84  * @return MII PHY address and bus number or -1.
85  */
86 int cvmx_helper_board_get_mii_address(int ipd_port)
87 {
88     /*
89      * Board types we have to know at compile-time.
90      */
91 #ifdef OCTEON_BOARD_CAPK_0100ND
92     switch (ipd_port) {
93     case 0:
94         return 2;
95     case 1:
96         return 3;
97     case 2:
98         /* XXX Switch PHY?  */
99         return -1;
100     default:
101         return -1;
102     }
103 #endif
104
105     /*
106      * For board types we can determine at runtime.
107      */
108     switch (cvmx_sysinfo_get()->board_type)
109     {
110         case CVMX_BOARD_TYPE_SIM:
111             /* Simulator doesn't have MII */
112             return -1;
113         case CVMX_BOARD_TYPE_EBT3000:
114         case CVMX_BOARD_TYPE_EBT5800:
115         case CVMX_BOARD_TYPE_THUNDER:
116         case CVMX_BOARD_TYPE_NICPRO2:
117             /* Interface 0 is SPI4, interface 1 is RGMII */
118             if ((ipd_port >= 16) && (ipd_port < 20))
119                 return ipd_port - 16;
120             else
121                 return -1;
122         case CVMX_BOARD_TYPE_KODAMA:
123         case CVMX_BOARD_TYPE_EBH3100:
124         case CVMX_BOARD_TYPE_HIKARI:
125         case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
126         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
127         case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
128             /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a
129                 switch */
130             if (ipd_port == 0)
131                 return 4;
132             else if (ipd_port == 1)
133                 return 9;
134             else
135                 return -1;
136         case CVMX_BOARD_TYPE_NAC38:
137             /* Board has 8 RGMII ports PHYs are 0-7 */
138             if ((ipd_port >= 0) && (ipd_port < 4))
139                 return ipd_port;
140             else if ((ipd_port >= 16) && (ipd_port < 20))
141                 return ipd_port - 16 + 4;
142             else
143                 return -1;
144         case CVMX_BOARD_TYPE_EBH3000:
145             /* Board has dual SPI4 and no PHYs */
146             return -1;
147         case CVMX_BOARD_TYPE_EBH5200:
148         case CVMX_BOARD_TYPE_EBH5201:
149         case CVMX_BOARD_TYPE_EBT5200:
150             /* Board has 4 SGMII ports. The PHYs start right after the MII
151                 ports MII0 = 0, MII1 = 1, SGMII = 2-5 */
152             if ((ipd_port >= 0) && (ipd_port < 4))
153                 return ipd_port+2;
154             else
155                 return -1;
156         case CVMX_BOARD_TYPE_EBH5600:
157         case CVMX_BOARD_TYPE_EBH5601:
158             /* Board has 8 SGMII ports. 4 connect out, two connect to a switch,
159                 and 2 loop to each other */
160             if ((ipd_port >= 0) && (ipd_port < 4))
161                 return ipd_port+1;
162             else
163                 return -1;
164         case CVMX_BOARD_TYPE_CUST_NB5:
165             if (ipd_port == 2)
166                 return 4;
167             else
168                 return -1;
169         case CVMX_BOARD_TYPE_NIC_XLE_4G:
170             /* Board has 4 SGMII ports. connected QLM3(interface 1) */
171             if ((ipd_port >= 16) && (ipd_port < 20))
172                 return ipd_port - 16 + 1;
173             else
174                 return -1;
175         case CVMX_BOARD_TYPE_BBGW_REF:
176             return -1;  /* No PHYs are connected to Octeon, everything is through switch */
177
178         /* Private vendor-defined boards.  */
179 #if defined(OCTEON_VENDOR_LANNER)
180         case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
181             /* Interface 1 is 12 BCM5482S PHYs.  */
182             if ((ipd_port >= 16) && (ipd_port < 28))
183                 return ipd_port - 16;
184             return -1;
185         case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
186             if ((ipd_port >= 0) && (ipd_port < 4))
187                 return ipd_port;
188             return -1;
189         case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
190             /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell
191                88E1111 interfaces.  */
192             switch (ipd_port) {
193             case 0:
194                 return 16;
195             case 1:
196                 return 1;
197             case 2:
198                 return 2;
199             default:
200                 return -1;
201             }
202 #endif
203     }
204
205     /* Some unknown board. Somebody forgot to update this function... */
206     cvmx_dprintf("cvmx_helper_board_get_mii_address: Unknown board type %d\n",
207                  cvmx_sysinfo_get()->board_type);
208     return -1;
209 }
210
211
212 /**
213  * @INTERNAL
214  * This function is the board specific method of determining an
215  * ethernet ports link speed. Most Octeon boards have Marvell PHYs
216  * and are handled by the fall through case. This function must be
217  * updated for boards that don't have the normal Marvell PHYs.
218  *
219  * This function must be modified for every new Octeon board.
220  * Internally it uses switch statements based on the cvmx_sysinfo
221  * data to determine board types and revisions. It relies on the
222  * fact that every Octeon board receives a unique board type
223  * enumeration from the bootloader.
224  *
225  * @param ipd_port IPD input port associated with the port we want to get link
226  *                 status for.
227  *
228  * @return The ports link status. If the link isn't fully resolved, this must
229  *         return zero.
230  */
231 cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
232 {
233     cvmx_helper_link_info_t result;
234     int phy_addr;
235     int is_broadcom_phy = 0;
236
237     /* Give the user a chance to override the processing of this function */
238     if (cvmx_override_board_link_get)
239         return cvmx_override_board_link_get(ipd_port);
240
241     /* Unless we fix it later, all links are defaulted to down */
242     result.u64 = 0;
243
244 #if !defined(OCTEON_BOARD_CAPK_0100ND)
245     /* This switch statement should handle all ports that either don't use
246         Marvell PHYS, or don't support in-band status */
247     switch (cvmx_sysinfo_get()->board_type)
248     {
249         case CVMX_BOARD_TYPE_SIM:
250             /* The simulator gives you a simulated 1Gbps full duplex link */
251             result.s.link_up = 1;
252             result.s.full_duplex = 1;
253             result.s.speed = 1000;
254             return result;
255         case CVMX_BOARD_TYPE_EBH3100:
256         case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
257         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
258         case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
259             /* Port 1 on these boards is always Gigabit */
260             if (ipd_port == 1)
261             {
262                 result.s.link_up = 1;
263                 result.s.full_duplex = 1;
264                 result.s.speed = 1000;
265                 return result;
266             }
267             /* Fall through to the generic code below */
268             break;
269         case CVMX_BOARD_TYPE_CUST_NB5:
270             /* Port 1 on these boards is always Gigabit */
271             if (ipd_port == 1)
272             {
273                 result.s.link_up = 1;
274                 result.s.full_duplex = 1;
275                 result.s.speed = 1000;
276                 return result;
277             }
278             else /* The other port uses a broadcom PHY */
279                 is_broadcom_phy = 1;
280             break;
281         case CVMX_BOARD_TYPE_BBGW_REF:
282             /* Port 1 on these boards is always Gigabit */
283             if (ipd_port == 2)
284             {   
285                 /* Port 2 is not hooked up */
286                 result.u64 = 0;
287                 return result;
288             }
289             else
290             {
291                 /* Ports 0 and 1 connect to the switch */
292                 result.s.link_up = 1;
293                 result.s.full_duplex = 1;
294                 result.s.speed = 1000;
295                 return result;
296             }
297             break;
298         /* Private vendor-defined boards.  */
299 #if defined(OCTEON_VENDOR_LANNER)
300         case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
301             /* Ports are BCM5482S */
302             is_broadcom_phy = 1;
303             break;
304         case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
305             /* Port 0 connects to the switch */
306             if (ipd_port == 0)
307             {
308                 result.s.link_up = 1;
309                 result.s.full_duplex = 1;
310                 result.s.speed = 1000;
311                 return result;
312             }
313             break;
314 #endif
315     }
316 #endif
317
318     phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
319     if (phy_addr != -1)
320     {
321         if (is_broadcom_phy)
322         {
323             /* Below we are going to read SMI/MDIO register 0x19 which works
324                 on Broadcom parts */
325             int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19);
326             switch ((phy_status>>8) & 0x7)
327             {
328                 case 0:
329                     result.u64 = 0;
330                     break;
331                 case 1:
332                     result.s.link_up = 1;
333                     result.s.full_duplex = 0;
334                     result.s.speed = 10;
335                     break;
336                 case 2:
337                     result.s.link_up = 1;
338                     result.s.full_duplex = 1;
339                     result.s.speed = 10;
340                     break;
341                 case 3:
342                     result.s.link_up = 1;
343                     result.s.full_duplex = 0;
344                     result.s.speed = 100;
345                     break;
346                 case 4:
347                     result.s.link_up = 1;
348                     result.s.full_duplex = 1;
349                     result.s.speed = 100;
350                     break;
351                 case 5:
352                     result.s.link_up = 1;
353                     result.s.full_duplex = 1;
354                     result.s.speed = 100;
355                     break;
356                 case 6:
357                     result.s.link_up = 1;
358                     result.s.full_duplex = 0;
359                     result.s.speed = 1000;
360                     break;
361                 case 7:
362                     result.s.link_up = 1;
363                     result.s.full_duplex = 1;
364                     result.s.speed = 1000;
365                     break;
366             }
367         }
368         else
369         {
370             /* This code assumes we are using a Marvell Gigabit PHY. All the
371                 speed information can be read from register 17 in one go. Somebody
372                 using a different PHY will need to handle it above in the board
373                 specific area */
374             int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
375
376             /* If the resolve bit 11 isn't set, see if autoneg is turned off
377                 (bit 12, reg 0). The resolve bit doesn't get set properly when
378                 autoneg is off, so force it */
379             if ((phy_status & (1<<11)) == 0)
380             {
381                 int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
382                 if ((auto_status & (1<<12)) == 0)
383                     phy_status |= 1<<11;
384             }
385
386             /* Only return a link if the PHY has finished auto negotiation
387                 and set the resolved bit (bit 11) */
388             if (phy_status & (1<<11))
389             {
390 #if defined(OCTEON_BOARD_CAPK_0100ND)
391                 result.s.link_up = (phy_status>>10)&1;
392 #else
393                 result.s.link_up = 1;
394 #endif
395                 result.s.full_duplex = ((phy_status>>13)&1);
396                 switch ((phy_status>>14)&3)
397                 {
398                     case 0: /* 10 Mbps */
399                         result.s.speed = 10;
400                         break;
401                     case 1: /* 100 Mbps */
402                         result.s.speed = 100;
403                         break;
404                     case 2: /* 1 Gbps */
405                         result.s.speed = 1000;
406                         break;
407                     case 3: /* Illegal */
408                         result.u64 = 0;
409                         break;
410                 }
411             }
412         }
413     }
414     else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
415     {
416         /* We don't have a PHY address, so attempt to use in-band status. It is
417             really important that boards not supporting in-band status never get
418             here. Reading broken in-band status tends to do bad things */
419         cvmx_gmxx_rxx_rx_inbnd_t inband_status;
420         int interface = cvmx_helper_get_interface_num(ipd_port);
421         int index = cvmx_helper_get_interface_index_num(ipd_port);
422         inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
423
424         result.s.link_up = inband_status.s.status;
425         result.s.full_duplex = inband_status.s.duplex;
426         switch (inband_status.s.speed)
427         {
428             case 0: /* 10 Mbps */
429                 result.s.speed = 10;
430                 break;
431             case 1: /* 100 Mbps */
432                 result.s.speed = 100;
433                 break;
434             case 2: /* 1 Gbps */
435                 result.s.speed = 1000;
436                 break;
437             case 3: /* Illegal */
438                 result.u64 = 0;
439                 break;
440         }
441     }
442     else
443     {
444         /* We don't have a PHY address and we don't have in-band status. There
445             is no way to determine the link speed. Return down assuming this
446             port isn't wired */
447         result.u64 = 0;
448     }
449
450     /* If link is down, return all fields as zero. */
451     if (!result.s.link_up)
452         result.u64 = 0;
453
454     return result;
455 }
456
457
458 /**
459  * This function as a board specific method of changing the PHY
460  * speed, duplex, and auto-negotiation. This programs the PHY and
461  * not Octeon. This can be used to force Octeon's links to
462  * specific settings.
463  *
464  * @param phy_addr  The address of the PHY to program
465  * @param enable_autoneg
466  *                  Non zero if you want to enable auto-negotiation.
467  * @param link_info Link speed to program. If the speed is zero and auto-negotiation
468  *                  is enabled, all possible negotiation speeds are advertised.
469  *
470  * @return Zero on success, negative on failure
471  */
472 int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags,
473                                    cvmx_helper_link_info_t link_info)
474 {
475
476     /* Set the flow control settings based on link_flags */
477     if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch)
478     {
479         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
480         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
481         reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
482         reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
483         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
484     }
485
486     /* If speed isn't set and autoneg is on advertise all supported modes */
487     if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0))
488     {
489         cvmx_mdio_phy_reg_control_t reg_control;
490         cvmx_mdio_phy_reg_status_t reg_status;
491         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
492         cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
493         cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
494
495         reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
496         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
497         reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4;
498         reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full;
499         reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half;
500         reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full;
501         reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half;
502         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
503         if (reg_status.s.capable_extended_status)
504         {
505             reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
506             reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
507             reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full;
508             reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half;
509             cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
510         }
511         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
512         reg_control.s.autoneg_enable = 1;
513         reg_control.s.restart_autoneg = 1;
514         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
515     }
516     else if ((link_flags & set_phy_link_flags_autoneg))
517     {
518         cvmx_mdio_phy_reg_control_t reg_control;
519         cvmx_mdio_phy_reg_status_t reg_status;
520         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
521         cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
522         cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
523
524         reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
525         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
526         reg_autoneg_adver.s.advert_100base_t4 = 0;
527         reg_autoneg_adver.s.advert_10base_tx_full = 0;
528         reg_autoneg_adver.s.advert_10base_tx_half = 0;
529         reg_autoneg_adver.s.advert_100base_tx_full = 0;
530         reg_autoneg_adver.s.advert_100base_tx_half = 0;
531         if (reg_status.s.capable_extended_status)
532         {
533             reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
534             reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
535             reg_control_1000.s.advert_1000base_t_full = 0;
536             reg_control_1000.s.advert_1000base_t_half = 0;
537         }
538         switch (link_info.s.speed)
539         {
540             case 10:
541                 reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex;
542                 reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex;
543                 break;
544             case 100:
545                 reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex;
546                 reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex;
547                 break;
548             case 1000:
549                 reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex;
550                 reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex;
551                 break;
552         }
553         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
554         if (reg_status.s.capable_extended_status)
555             cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
556         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
557         reg_control.s.autoneg_enable = 1;
558         reg_control.s.restart_autoneg = 1;
559         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
560     }
561     else
562     {
563         cvmx_mdio_phy_reg_control_t reg_control;
564         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
565         reg_control.s.autoneg_enable = 0;
566         reg_control.s.restart_autoneg = 1;
567         reg_control.s.duplex = link_info.s.full_duplex;
568         if (link_info.s.speed == 1000)
569         {
570             reg_control.s.speed_msb = 1;
571             reg_control.s.speed_lsb = 0;
572         }
573         else if (link_info.s.speed == 100)
574         {
575             reg_control.s.speed_msb = 0;
576             reg_control.s.speed_lsb = 1;
577         }
578         else if (link_info.s.speed == 10)
579         {
580             reg_control.s.speed_msb = 0;
581             reg_control.s.speed_lsb = 0;
582         }
583         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
584     }
585     return 0;
586 }
587
588
589 /**
590  * @INTERNAL
591  * This function is called by cvmx_helper_interface_probe() after it
592  * determines the number of ports Octeon can support on a specific
593  * interface. This function is the per board location to override
594  * this value. It is called with the number of ports Octeon might
595  * support and should return the number of actual ports on the
596  * board.
597  *
598  * This function must be modifed for every new Octeon board.
599  * Internally it uses switch statements based on the cvmx_sysinfo
600  * data to determine board types and revisions. It relys on the
601  * fact that every Octeon board receives a unique board type
602  * enumeration from the bootloader.
603  *
604  * @param interface Interface to probe
605  * @param supported_ports
606  *                  Number of ports Octeon supports.
607  *
608  * @return Number of ports the actual board supports. Many times this will
609  *         simple be "support_ports".
610  */
611 int __cvmx_helper_board_interface_probe(int interface, int supported_ports)
612 {
613     switch (cvmx_sysinfo_get()->board_type)
614     {
615         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
616             if (interface == 0)
617                 return 2;
618             break;
619         case CVMX_BOARD_TYPE_BBGW_REF:
620             if (interface == 0)
621                 return 2;
622             break;
623         case CVMX_BOARD_TYPE_NIC_XLE_4G:
624             if (interface == 0)
625                 return 0;
626             break;
627         /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
628             which we don't support. Disable ports connected to it */
629         case CVMX_BOARD_TYPE_EBH5600:
630             if (interface == 1)
631                 return 0;
632             break;
633 #if defined(OCTEON_VENDOR_LANNER)
634         case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
635             if (interface == 1)
636                 return 12;
637             break;
638 #endif
639     }
640 #ifdef CVMX_BUILD_FOR_UBOOT
641     if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi"))
642         return 0;
643 #endif
644     return supported_ports;
645 }
646
647
648 /**
649  * @INTERNAL
650  * Enable packet input/output from the hardware. This function is
651  * called after by cvmx_helper_packet_hardware_enable() to
652  * perform board specific initialization. For most boards
653  * nothing is needed.
654  *
655  * @param interface Interface to enable
656  *
657  * @return Zero on success, negative on failure
658  */
659 int __cvmx_helper_board_hardware_enable(int interface)
660 {
661     if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5)
662     {
663         if (interface == 0)
664         {
665             /* Different config for switch port */
666             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
667             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
668             /* Boards with gigabit WAN ports need a different setting that is
669                 compatible with 100 Mbit settings */
670             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc);
671             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc);
672         }
673     }
674     else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5)
675     {
676         /* Broadcom PHYs require differnet ASX clocks. Unfortunately
677             many customer don't define a new board Id and simply
678             mangle the CN3010_EVB_HS5 */
679         if (interface == 0)
680         {
681             /* Some customers boards use a hacked up bootloader that identifies them as
682             ** CN3010_EVB_HS5 evaluation boards.  This leads to all kinds of configuration
683             ** problems.  Detect one case, and print warning, while trying to do the right thing.
684             */
685             int phy_addr = cvmx_helper_board_get_mii_address(0);
686             if (phy_addr != -1)
687             {
688                 int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2);
689                 /* Is it a Broadcom PHY? */
690                 if (phy_identifier == 0x0143)
691                 {
692                     cvmx_dprintf("\n");
693                     cvmx_dprintf("ERROR:\n");
694                     cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
695                     cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
696                     cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n");
697                     cvmx_dprintf("ERROR:\n");
698                     cvmx_dprintf("\n");
699                     cvmx_wait(1000000000);
700                     cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5);
701                     cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5);
702                 }
703             }
704         }
705     }
706     return 0;
707 }
708
709 cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void)
710 {
711     switch (cvmx_sysinfo_get()->board_type) {
712     case CVMX_BOARD_TYPE_BBGW_REF:
713 #if defined(OCTEON_VENDOR_LANNER)
714     case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
715 #endif
716             return USB_CLOCK_TYPE_CRYSTAL_12;
717     }
718     return USB_CLOCK_TYPE_REF_48;
719 }
720
721 int __cvmx_helper_board_usb_get_num_ports(int supported_ports)
722 {
723     switch (cvmx_sysinfo_get()->board_type) {
724         case CVMX_BOARD_TYPE_NIC_XLE_4G:
725             return 0;
726     }
727
728     return supported_ports;
729 }
730
731