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