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