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