]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/octeon-sdk/cvmx-helper-board.c
Merge ACPICA 20100915.
[FreeBSD/FreeBSD.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_MR320:
181             switch (ipd_port) {
182             case 0:
183                 /* XXX Switch PHY?  */
184                 return -1;
185             case 1:
186                 return 1;
187             case 2:
188                 return 2;
189             default:
190                 return -1;
191             }
192 #endif
193     }
194
195     /* Some unknown board. Somebody forgot to update this function... */
196     cvmx_dprintf("cvmx_helper_board_get_mii_address: Unknown board type %d\n",
197                  cvmx_sysinfo_get()->board_type);
198     return -1;
199 }
200
201
202 /**
203  * @INTERNAL
204  * This function is the board specific method of determining an
205  * ethernet ports link speed. Most Octeon boards have Marvell PHYs
206  * and are handled by the fall through case. This function must be
207  * updated for boards that don't have the normal Marvell PHYs.
208  *
209  * This function must be modified for every new Octeon board.
210  * Internally it uses switch statements based on the cvmx_sysinfo
211  * data to determine board types and revisions. It relies on the
212  * fact that every Octeon board receives a unique board type
213  * enumeration from the bootloader.
214  *
215  * @param ipd_port IPD input port associated with the port we want to get link
216  *                 status for.
217  *
218  * @return The ports link status. If the link isn't fully resolved, this must
219  *         return zero.
220  */
221 cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
222 {
223     cvmx_helper_link_info_t result;
224     int phy_addr;
225     int is_broadcom_phy = 0;
226
227     /* Give the user a chance to override the processing of this function */
228     if (cvmx_override_board_link_get)
229         return cvmx_override_board_link_get(ipd_port);
230
231     /* Unless we fix it later, all links are defaulted to down */
232     result.u64 = 0;
233
234 #if !defined(OCTEON_BOARD_CAPK_0100ND)
235     /* This switch statement should handle all ports that either don't use
236         Marvell PHYS, or don't support in-band status */
237     switch (cvmx_sysinfo_get()->board_type)
238     {
239         case CVMX_BOARD_TYPE_SIM:
240             /* The simulator gives you a simulated 1Gbps full duplex link */
241             result.s.link_up = 1;
242             result.s.full_duplex = 1;
243             result.s.speed = 1000;
244             return result;
245         case CVMX_BOARD_TYPE_EBH3100:
246         case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
247         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
248         case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
249             /* Port 1 on these boards is always Gigabit */
250             if (ipd_port == 1)
251             {
252                 result.s.link_up = 1;
253                 result.s.full_duplex = 1;
254                 result.s.speed = 1000;
255                 return result;
256             }
257             /* Fall through to the generic code below */
258             break;
259         case CVMX_BOARD_TYPE_CUST_NB5:
260             /* Port 1 on these boards is always Gigabit */
261             if (ipd_port == 1)
262             {
263                 result.s.link_up = 1;
264                 result.s.full_duplex = 1;
265                 result.s.speed = 1000;
266                 return result;
267             }
268             else /* The other port uses a broadcom PHY */
269                 is_broadcom_phy = 1;
270             break;
271         case CVMX_BOARD_TYPE_BBGW_REF:
272             /* Port 1 on these boards is always Gigabit */
273             if (ipd_port == 2)
274             {   
275                 /* Port 2 is not hooked up */
276                 result.u64 = 0;
277                 return result;
278             }
279             else
280             {
281                 /* Ports 0 and 1 connect to the switch */
282                 result.s.link_up = 1;
283                 result.s.full_duplex = 1;
284                 result.s.speed = 1000;
285                 return result;
286             }
287             break;
288         /* Private vendor-defined boards.  */
289 #if defined(OCTEON_VENDOR_LANNER)
290         case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
291             /* Port 0 connects to the switch */
292             if (ipd_port == 0)
293             {
294                 result.s.link_up = 1;
295                 result.s.full_duplex = 1;
296                 result.s.speed = 1000;
297                 return result;
298             }
299             break;
300 #endif
301     }
302 #endif
303
304     phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
305     if (phy_addr != -1)
306     {
307         if (is_broadcom_phy)
308         {
309             /* Below we are going to read SMI/MDIO register 0x19 which works
310                 on Broadcom parts */
311             int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19);
312             switch ((phy_status>>8) & 0x7)
313             {
314                 case 0:
315                     result.u64 = 0;
316                     break;
317                 case 1:
318                     result.s.link_up = 1;
319                     result.s.full_duplex = 0;
320                     result.s.speed = 10;
321                     break;
322                 case 2:
323                     result.s.link_up = 1;
324                     result.s.full_duplex = 1;
325                     result.s.speed = 10;
326                     break;
327                 case 3:
328                     result.s.link_up = 1;
329                     result.s.full_duplex = 0;
330                     result.s.speed = 100;
331                     break;
332                 case 4:
333                     result.s.link_up = 1;
334                     result.s.full_duplex = 1;
335                     result.s.speed = 100;
336                     break;
337                 case 5:
338                     result.s.link_up = 1;
339                     result.s.full_duplex = 1;
340                     result.s.speed = 100;
341                     break;
342                 case 6:
343                     result.s.link_up = 1;
344                     result.s.full_duplex = 0;
345                     result.s.speed = 1000;
346                     break;
347                 case 7:
348                     result.s.link_up = 1;
349                     result.s.full_duplex = 1;
350                     result.s.speed = 1000;
351                     break;
352             }
353         }
354         else
355         {
356             /* This code assumes we are using a Marvell Gigabit PHY. All the
357                 speed information can be read from register 17 in one go. Somebody
358                 using a different PHY will need to handle it above in the board
359                 specific area */
360             int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
361
362             /* If the resolve bit 11 isn't set, see if autoneg is turned off
363                 (bit 12, reg 0). The resolve bit doesn't get set properly when
364                 autoneg is off, so force it */
365             if ((phy_status & (1<<11)) == 0)
366             {
367                 int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
368                 if ((auto_status & (1<<12)) == 0)
369                     phy_status |= 1<<11;
370             }
371
372             /* Only return a link if the PHY has finished auto negotiation
373                 and set the resolved bit (bit 11) */
374             if (phy_status & (1<<11))
375             {
376 #if defined(OCTEON_BOARD_CAPK_0100ND)
377                 result.s.link_up = (phy_status>>10)&1;
378 #else
379                 result.s.link_up = 1;
380 #endif
381                 result.s.full_duplex = ((phy_status>>13)&1);
382                 switch ((phy_status>>14)&3)
383                 {
384                     case 0: /* 10 Mbps */
385                         result.s.speed = 10;
386                         break;
387                     case 1: /* 100 Mbps */
388                         result.s.speed = 100;
389                         break;
390                     case 2: /* 1 Gbps */
391                         result.s.speed = 1000;
392                         break;
393                     case 3: /* Illegal */
394                         result.u64 = 0;
395                         break;
396                 }
397             }
398         }
399     }
400     else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
401     {
402         /* We don't have a PHY address, so attempt to use in-band status. It is
403             really important that boards not supporting in-band status never get
404             here. Reading broken in-band status tends to do bad things */
405         cvmx_gmxx_rxx_rx_inbnd_t inband_status;
406         int interface = cvmx_helper_get_interface_num(ipd_port);
407         int index = cvmx_helper_get_interface_index_num(ipd_port);
408         inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
409
410         result.s.link_up = inband_status.s.status;
411         result.s.full_duplex = inband_status.s.duplex;
412         switch (inband_status.s.speed)
413         {
414             case 0: /* 10 Mbps */
415                 result.s.speed = 10;
416                 break;
417             case 1: /* 100 Mbps */
418                 result.s.speed = 100;
419                 break;
420             case 2: /* 1 Gbps */
421                 result.s.speed = 1000;
422                 break;
423             case 3: /* Illegal */
424                 result.u64 = 0;
425                 break;
426         }
427     }
428     else
429     {
430         /* We don't have a PHY address and we don't have in-band status. There
431             is no way to determine the link speed. Return down assuming this
432             port isn't wired */
433         result.u64 = 0;
434     }
435
436     /* If link is down, return all fields as zero. */
437     if (!result.s.link_up)
438         result.u64 = 0;
439
440     return result;
441 }
442
443
444 /**
445  * This function as a board specific method of changing the PHY
446  * speed, duplex, and auto-negotiation. This programs the PHY and
447  * not Octeon. This can be used to force Octeon's links to
448  * specific settings.
449  *
450  * @param phy_addr  The address of the PHY to program
451  * @param enable_autoneg
452  *                  Non zero if you want to enable auto-negotiation.
453  * @param link_info Link speed to program. If the speed is zero and auto-negotiation
454  *                  is enabled, all possible negotiation speeds are advertised.
455  *
456  * @return Zero on success, negative on failure
457  */
458 int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags,
459                                    cvmx_helper_link_info_t link_info)
460 {
461
462     /* Set the flow control settings based on link_flags */
463     if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch)
464     {
465         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
466         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
467         reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
468         reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
469         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
470     }
471
472     /* If speed isn't set and autoneg is on advertise all supported modes */
473     if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0))
474     {
475         cvmx_mdio_phy_reg_control_t reg_control;
476         cvmx_mdio_phy_reg_status_t reg_status;
477         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
478         cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
479         cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
480
481         reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
482         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
483         reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4;
484         reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full;
485         reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half;
486         reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full;
487         reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half;
488         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
489         if (reg_status.s.capable_extended_status)
490         {
491             reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
492             reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
493             reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full;
494             reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half;
495             cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
496         }
497         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
498         reg_control.s.autoneg_enable = 1;
499         reg_control.s.restart_autoneg = 1;
500         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
501     }
502     else if ((link_flags & set_phy_link_flags_autoneg))
503     {
504         cvmx_mdio_phy_reg_control_t reg_control;
505         cvmx_mdio_phy_reg_status_t reg_status;
506         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
507         cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
508         cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
509
510         reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
511         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
512         reg_autoneg_adver.s.advert_100base_t4 = 0;
513         reg_autoneg_adver.s.advert_10base_tx_full = 0;
514         reg_autoneg_adver.s.advert_10base_tx_half = 0;
515         reg_autoneg_adver.s.advert_100base_tx_full = 0;
516         reg_autoneg_adver.s.advert_100base_tx_half = 0;
517         if (reg_status.s.capable_extended_status)
518         {
519             reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
520             reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
521             reg_control_1000.s.advert_1000base_t_full = 0;
522             reg_control_1000.s.advert_1000base_t_half = 0;
523         }
524         switch (link_info.s.speed)
525         {
526             case 10:
527                 reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex;
528                 reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex;
529                 break;
530             case 100:
531                 reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex;
532                 reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex;
533                 break;
534             case 1000:
535                 reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex;
536                 reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex;
537                 break;
538         }
539         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
540         if (reg_status.s.capable_extended_status)
541             cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
542         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
543         reg_control.s.autoneg_enable = 1;
544         reg_control.s.restart_autoneg = 1;
545         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
546     }
547     else
548     {
549         cvmx_mdio_phy_reg_control_t reg_control;
550         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
551         reg_control.s.autoneg_enable = 0;
552         reg_control.s.restart_autoneg = 1;
553         reg_control.s.duplex = link_info.s.full_duplex;
554         if (link_info.s.speed == 1000)
555         {
556             reg_control.s.speed_msb = 1;
557             reg_control.s.speed_lsb = 0;
558         }
559         else if (link_info.s.speed == 100)
560         {
561             reg_control.s.speed_msb = 0;
562             reg_control.s.speed_lsb = 1;
563         }
564         else if (link_info.s.speed == 10)
565         {
566             reg_control.s.speed_msb = 0;
567             reg_control.s.speed_lsb = 0;
568         }
569         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
570     }
571     return 0;
572 }
573
574
575 /**
576  * @INTERNAL
577  * This function is called by cvmx_helper_interface_probe() after it
578  * determines the number of ports Octeon can support on a specific
579  * interface. This function is the per board location to override
580  * this value. It is called with the number of ports Octeon might
581  * support and should return the number of actual ports on the
582  * board.
583  *
584  * This function must be modifed for every new Octeon board.
585  * Internally it uses switch statements based on the cvmx_sysinfo
586  * data to determine board types and revisions. It relys on the
587  * fact that every Octeon board receives a unique board type
588  * enumeration from the bootloader.
589  *
590  * @param interface Interface to probe
591  * @param supported_ports
592  *                  Number of ports Octeon supports.
593  *
594  * @return Number of ports the actual board supports. Many times this will
595  *         simple be "support_ports".
596  */
597 int __cvmx_helper_board_interface_probe(int interface, int supported_ports)
598 {
599     switch (cvmx_sysinfo_get()->board_type)
600     {
601         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
602             if (interface == 0)
603                 return 2;
604             break;
605         case CVMX_BOARD_TYPE_BBGW_REF:
606             if (interface == 0)
607                 return 2;
608             break;
609         case CVMX_BOARD_TYPE_NIC_XLE_4G:
610             if (interface == 0)
611                 return 0;
612             break;
613         /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
614             which we don't support. Disable ports connected to it */
615         case CVMX_BOARD_TYPE_EBH5600:
616             if (interface == 1)
617                 return 0;
618             break;
619     }
620 #ifdef CVMX_BUILD_FOR_UBOOT
621     if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi"))
622         return 0;
623 #endif
624     return supported_ports;
625 }
626
627
628 /**
629  * @INTERNAL
630  * Enable packet input/output from the hardware. This function is
631  * called after by cvmx_helper_packet_hardware_enable() to
632  * perform board specific initialization. For most boards
633  * nothing is needed.
634  *
635  * @param interface Interface to enable
636  *
637  * @return Zero on success, negative on failure
638  */
639 int __cvmx_helper_board_hardware_enable(int interface)
640 {
641     if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5)
642     {
643         if (interface == 0)
644         {
645             /* Different config for switch port */
646             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
647             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
648             /* Boards with gigabit WAN ports need a different setting that is
649                 compatible with 100 Mbit settings */
650             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc);
651             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc);
652         }
653     }
654     else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5)
655     {
656         /* Broadcom PHYs require differnet ASX clocks. Unfortunately
657             many customer don't define a new board Id and simply
658             mangle the CN3010_EVB_HS5 */
659         if (interface == 0)
660         {
661             /* Some customers boards use a hacked up bootloader that identifies them as
662             ** CN3010_EVB_HS5 evaluation boards.  This leads to all kinds of configuration
663             ** problems.  Detect one case, and print warning, while trying to do the right thing.
664             */
665             int phy_addr = cvmx_helper_board_get_mii_address(0);
666             if (phy_addr != -1)
667             {
668                 int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2);
669                 /* Is it a Broadcom PHY? */
670                 if (phy_identifier == 0x0143)
671                 {
672                     cvmx_dprintf("\n");
673                     cvmx_dprintf("ERROR:\n");
674                     cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
675                     cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
676                     cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n");
677                     cvmx_dprintf("ERROR:\n");
678                     cvmx_dprintf("\n");
679                     cvmx_wait(1000000000);
680                     cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5);
681                     cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5);
682                 }
683             }
684         }
685     }
686     return 0;
687 }
688
689 cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void)
690 {
691     switch (cvmx_sysinfo_get()->board_type) {
692     case CVMX_BOARD_TYPE_BBGW_REF:
693 #if defined(OCTEON_VENDOR_LANNER)
694     case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
695 #endif
696             return USB_CLOCK_TYPE_CRYSTAL_12;
697     }
698     return USB_CLOCK_TYPE_REF_48;
699 }
700
701 int __cvmx_helper_board_usb_get_num_ports(int supported_ports)
702 {
703     switch (cvmx_sysinfo_get()->board_type) {
704         case CVMX_BOARD_TYPE_NIC_XLE_4G:
705             return 0;
706     }
707
708     return supported_ports;
709 }
710
711