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