cvmx-helper-board.c revision 210311
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 */
68CVMX_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 */
86int 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 */
221cvmx_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 */
458int 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 */
597int __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 */
639int __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
689cvmx_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
701int __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
712