cvmx-helper-board.c revision 229070
1/***********************license start***************
2 * Copyright (c) 2003-2010  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 * This Software, including technical data, may be subject to U.S. export  control
24 * laws, including the U.S. Export Administration Act and its  associated
25 * regulations, and may be subject to export or import  regulations in other
26 * countries.
27
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM  NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
39
40
41
42
43
44
45
46/**
47 * @file
48 *
49 * Helper functions to abstract board specific data about
50 * network ports from the rest of the cvmx-helper files.
51 *
52 * <hr>$Revision: 49627 $<hr>
53 */
54#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
55#include <linux/module.h>
56#include <asm/octeon/cvmx.h>
57#include <asm/octeon/cvmx-bootinfo.h>
58#include <asm/octeon/cvmx-smix-defs.h>
59#include <asm/octeon/cvmx-gmxx-defs.h>
60#include <asm/octeon/cvmx-asxx-defs.h>
61#include <asm/octeon/cvmx-mdio.h>
62#include <asm/octeon/cvmx-helper.h>
63#include <asm/octeon/cvmx-helper-util.h>
64#include <asm/octeon/cvmx-helper-board.h>
65#include <asm/octeon/cvmx-twsi.h>
66#else
67#include "cvmx.h"
68#include "cvmx-app-init.h"
69#include "cvmx-sysinfo.h"
70#include "cvmx-twsi.h"
71#include "cvmx-mdio.h"
72#include "cvmx-helper.h"
73#include "cvmx-helper-util.h"
74#include "cvmx-helper-board.h"
75#endif
76
77/**
78 * cvmx_override_board_link_get(int ipd_port) is a function
79 * pointer. It is meant to allow customization of the process of
80 * talking to a PHY to determine link speed. It is called every
81 * time a PHY must be polled for link status. Users should set
82 * this pointer to a function before calling any cvmx-helper
83 * operations.
84 */
85CVMX_SHARED cvmx_helper_link_info_t (*cvmx_override_board_link_get)(int ipd_port) = NULL;
86
87/**
88 * Return the MII PHY address associated with the given IPD
89 * port. A result of -1 means there isn't a MII capable PHY
90 * connected to this port. On chips supporting multiple MII
91 * busses the bus number is encoded in bits <15:8>.
92 *
93 * This function must be modified for every new Octeon board.
94 * Internally it uses switch statements based on the cvmx_sysinfo
95 * data to determine board types and revisions. It replies on the
96 * fact that every Octeon board receives a unique board type
97 * enumeration from the bootloader.
98 *
99 * @param ipd_port Octeon IPD port to get the MII address for.
100 *
101 * @return MII PHY address and bus number or -1.
102 */
103int cvmx_helper_board_get_mii_address(int ipd_port)
104{
105    /*
106     * Board types we have to know at compile-time.
107     */
108#ifdef OCTEON_BOARD_CAPK_0100ND
109    switch (ipd_port) {
110    case 0:
111	return 2;
112    case 1:
113	return 3;
114    case 2:
115	/* XXX Switch PHY?  */
116	return -1;
117    default:
118	return -1;
119    }
120#endif
121
122    /*
123     * For board types we can determine at runtime.
124     */
125    switch (cvmx_sysinfo_get()->board_type)
126    {
127        case CVMX_BOARD_TYPE_SIM:
128            /* Simulator doesn't have MII */
129            return -1;
130        case CVMX_BOARD_TYPE_EBT3000:
131        case CVMX_BOARD_TYPE_EBT5800:
132        case CVMX_BOARD_TYPE_THUNDER:
133        case CVMX_BOARD_TYPE_NICPRO2:
134            /* Interface 0 is SPI4, interface 1 is RGMII */
135            if ((ipd_port >= 16) && (ipd_port < 20))
136                return ipd_port - 16;
137            else
138                return -1;
139        case CVMX_BOARD_TYPE_LANAI2_A:
140            if (ipd_port == 0)
141                return 0;
142            else
143                return -1;
144        case CVMX_BOARD_TYPE_LANAI2_U:
145        case CVMX_BOARD_TYPE_LANAI2_G:
146            if (ipd_port == 0)
147                return 0x1c;
148            else
149                return -1;
150        case CVMX_BOARD_TYPE_KODAMA:
151        case CVMX_BOARD_TYPE_EBH3100:
152        case CVMX_BOARD_TYPE_HIKARI:
153        case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
154        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
155        case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
156            /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a
157                switch */
158            if (ipd_port == 0)
159                return 4;
160            else if (ipd_port == 1)
161                return 9;
162            else
163                return -1;
164        case CVMX_BOARD_TYPE_NAC38:
165            /* Board has 8 RGMII ports PHYs are 0-7 */
166            if ((ipd_port >= 0) && (ipd_port < 4))
167                return ipd_port;
168            else if ((ipd_port >= 16) && (ipd_port < 20))
169                return ipd_port - 16 + 4;
170            else
171                return -1;
172        case CVMX_BOARD_TYPE_EBH3000:
173            /* Board has dual SPI4 and no PHYs */
174            return -1;
175        case CVMX_BOARD_TYPE_EBT5810:
176            /* Board has 10g PHYs hooked up to the MII controller on the
177            ** IXF18201 MAC.  The 10G PHYS use clause 45 MDIO which the CN58XX
178            ** does not support. All MII accesses go through the IXF part. */
179            return -1;
180        case CVMX_BOARD_TYPE_EBH5200:
181        case CVMX_BOARD_TYPE_EBH5201:
182        case CVMX_BOARD_TYPE_EBT5200:
183            /* Board has 2 management ports */
184            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
185                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
186            /* Board has 4 SGMII ports. The PHYs start right after the MII
187                ports MII0 = 0, MII1 = 1, SGMII = 2-5 */
188            if ((ipd_port >= 0) && (ipd_port < 4))
189                return ipd_port+2;
190            else
191                return -1;
192        case CVMX_BOARD_TYPE_EBH5600:
193        case CVMX_BOARD_TYPE_EBH5601:
194        case CVMX_BOARD_TYPE_EBH5610:
195            /* Board has 1 management port */
196            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
197                return 0;
198            /* Board has 8 SGMII ports. 4 connect out, two connect to a switch,
199                and 2 loop to each other */
200            if ((ipd_port >= 0) && (ipd_port < 4))
201                return ipd_port+1;
202            else
203                return -1;
204        case CVMX_BOARD_TYPE_EBB5600:
205            {
206                static unsigned char qlm_switch_addr = 0;
207
208                /* Board has 1 management port */
209                if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
210                    return 0;
211
212                /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */
213                if ((ipd_port >= 0) && (ipd_port < 4))
214                {
215                    if (qlm_switch_addr != 0x3)
216                    {
217                        qlm_switch_addr = 0x3;  /* QLM1 */
218                        cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
219                        cvmx_wait_usec(11000); /* Let the write complete */
220                    }
221                    return ipd_port+1 + (1<<8);
222                }
223                else if ((ipd_port >= 16) && (ipd_port < 20))
224                {
225                    if (qlm_switch_addr != 0xC)
226                    {
227                        qlm_switch_addr = 0xC;  /* QLM3 */
228                        cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
229                        cvmx_wait_usec(11000); /* Let the write complete */
230                    }
231                    return ipd_port-16+1 + (1<<8);
232                }
233                else
234                    return -1;
235            }
236        case CVMX_BOARD_TYPE_EBB6300:
237            /* Board has 2 management ports */
238            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
239                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
240            if ((ipd_port >= 0) && (ipd_port < 4))
241                return ipd_port + 1 + (1<<8);
242            else
243                return -1;
244        case CVMX_BOARD_TYPE_CUST_NB5:
245            if (ipd_port == 2)
246                return 4;
247            else
248                return -1;
249        case CVMX_BOARD_TYPE_NIC_XLE_4G:
250            /* Board has 4 SGMII ports. connected QLM3(interface 1) */
251            if ((ipd_port >= 16) && (ipd_port < 20))
252                return ipd_port - 16 + 1;
253            else
254                return -1;
255        case CVMX_BOARD_TYPE_NIC_XLE_10G:
256            return -1;  /* We don't use clause 45 MDIO for anything */
257        case CVMX_BOARD_TYPE_BBGW_REF:
258            return -1;  /* No PHYs are connected to Octeon, everything is through switch */
259	case CVMX_BOARD_TYPE_CUST_WSX16:
260		if (ipd_port >= 0 && ipd_port <= 3)
261			return ipd_port;
262		else if (ipd_port >= 16 && ipd_port <= 19)
263			return ipd_port - 16 + 4;
264		else
265			return -1;
266
267	/* Private vendor-defined boards.  */
268#if defined(OCTEON_VENDOR_LANNER)
269	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
270	    /* Interface 1 is 12 BCM5482S PHYs.  */
271            if ((ipd_port >= 16) && (ipd_port < 28))
272                return ipd_port - 16;
273	    return -1;
274	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
275            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
276		return (ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT) + 0x81;
277            if ((ipd_port >= 0) && (ipd_port < 4))
278                return ipd_port;
279	    return -1;
280	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
281	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
282	    /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell
283	       88E1111 interfaces.  */
284	    switch (ipd_port) {
285	    case 0:
286		return 16;
287	    case 1:
288		return 1;
289	    case 2:
290		return 2;
291	    default:
292		return -1;
293	    }
294#endif
295    }
296
297    /* Some unknown board. Somebody forgot to update this function... */
298    cvmx_dprintf("%s: Unknown board type %d\n",
299                 __FUNCTION__, cvmx_sysinfo_get()->board_type);
300    return -1;
301}
302#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
303EXPORT_SYMBOL(cvmx_helper_board_get_mii_address);
304#endif
305
306
307/**
308 * @INTERNAL
309 * This function is the board specific method of determining an
310 * ethernet ports link speed. Most Octeon boards have Marvell PHYs
311 * and are handled by the fall through case. This function must be
312 * updated for boards that don't have the normal Marvell PHYs.
313 *
314 * This function must be modified for every new Octeon board.
315 * Internally it uses switch statements based on the cvmx_sysinfo
316 * data to determine board types and revisions. It relies on the
317 * fact that every Octeon board receives a unique board type
318 * enumeration from the bootloader.
319 *
320 * @param ipd_port IPD input port associated with the port we want to get link
321 *                 status for.
322 *
323 * @return The ports link status. If the link isn't fully resolved, this must
324 *         return zero.
325 */
326cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
327{
328    cvmx_helper_link_info_t result;
329    int phy_addr;
330    int is_broadcom_phy = 0;
331
332    /* Give the user a chance to override the processing of this function */
333    if (cvmx_override_board_link_get)
334        return cvmx_override_board_link_get(ipd_port);
335
336    /* Unless we fix it later, all links are defaulted to down */
337    result.u64 = 0;
338
339#if !defined(OCTEON_BOARD_CAPK_0100ND)
340    /* This switch statement should handle all ports that either don't use
341        Marvell PHYS, or don't support in-band status */
342    switch (cvmx_sysinfo_get()->board_type)
343    {
344        case CVMX_BOARD_TYPE_SIM:
345            /* The simulator gives you a simulated 1Gbps full duplex link */
346            result.s.link_up = 1;
347            result.s.full_duplex = 1;
348            result.s.speed = 1000;
349            return result;
350        case CVMX_BOARD_TYPE_LANAI2_A:
351        case CVMX_BOARD_TYPE_LANAI2_U:
352        case CVMX_BOARD_TYPE_LANAI2_G:
353            break;
354        case CVMX_BOARD_TYPE_EBH3100:
355        case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
356        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
357        case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
358            /* Port 1 on these boards is always Gigabit */
359            if (ipd_port == 1)
360            {
361                result.s.link_up = 1;
362                result.s.full_duplex = 1;
363                result.s.speed = 1000;
364                return result;
365            }
366            /* Fall through to the generic code below */
367            break;
368        case CVMX_BOARD_TYPE_EBH5600:
369        case CVMX_BOARD_TYPE_EBH5601:
370        case CVMX_BOARD_TYPE_EBH5610:
371            /* Board has 1 management ports */
372            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
373                is_broadcom_phy = 1;
374            break;
375        case CVMX_BOARD_TYPE_EBH5200:
376        case CVMX_BOARD_TYPE_EBH5201:
377        case CVMX_BOARD_TYPE_EBT5200:
378            /* Board has 2 management ports */
379            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
380                is_broadcom_phy = 1;
381            break;
382        case CVMX_BOARD_TYPE_EBB6300:   /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/
383            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))
384                && cvmx_helper_board_get_mii_address(ipd_port) >= 0 && cvmx_helper_board_get_mii_address(ipd_port) <= 1)
385                is_broadcom_phy = 1;
386            break;
387        case CVMX_BOARD_TYPE_CUST_NB5:
388            /* Port 1 on these boards is always Gigabit */
389            if (ipd_port == 1)
390            {
391                result.s.link_up = 1;
392                result.s.full_duplex = 1;
393                result.s.speed = 1000;
394                return result;
395            }
396            else /* The other port uses a broadcom PHY */
397                is_broadcom_phy = 1;
398            break;
399        case CVMX_BOARD_TYPE_BBGW_REF:
400            /* Port 1 on these boards is always Gigabit */
401            if (ipd_port == 2)
402            {
403                /* Port 2 is not hooked up */
404                result.u64 = 0;
405                return result;
406            }
407            else
408            {
409                /* Ports 0 and 1 connect to the switch */
410                result.s.link_up = 1;
411                result.s.full_duplex = 1;
412                result.s.speed = 1000;
413                return result;
414            }
415            break;
416	/* Private vendor-defined boards.  */
417#if defined(OCTEON_VENDOR_LANNER)
418	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
419	    /* Ports are BCM5482S */
420	    is_broadcom_phy = 1;
421	    break;
422	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
423	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
424	    /* Port 0 connects to the switch */
425	    if (ipd_port == 0)
426	    {
427                result.s.link_up = 1;
428                result.s.full_duplex = 1;
429                result.s.speed = 1000;
430		return result;
431	    }
432	    break;
433#endif
434    }
435#endif
436
437    phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
438    if (phy_addr != -1)
439    {
440        if (is_broadcom_phy)
441        {
442            /* Below we are going to read SMI/MDIO register 0x19 which works
443                on Broadcom parts */
444            int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19);
445            switch ((phy_status>>8) & 0x7)
446            {
447                case 0:
448                    result.u64 = 0;
449                    break;
450                case 1:
451                    result.s.link_up = 1;
452                    result.s.full_duplex = 0;
453                    result.s.speed = 10;
454                    break;
455                case 2:
456                    result.s.link_up = 1;
457                    result.s.full_duplex = 1;
458                    result.s.speed = 10;
459                    break;
460                case 3:
461                    result.s.link_up = 1;
462                    result.s.full_duplex = 0;
463                    result.s.speed = 100;
464                    break;
465                case 4:
466                    result.s.link_up = 1;
467                    result.s.full_duplex = 1;
468                    result.s.speed = 100;
469                    break;
470                case 5:
471                    result.s.link_up = 1;
472                    result.s.full_duplex = 1;
473                    result.s.speed = 100;
474                    break;
475                case 6:
476                    result.s.link_up = 1;
477                    result.s.full_duplex = 0;
478                    result.s.speed = 1000;
479                    break;
480                case 7:
481                    result.s.link_up = 1;
482                    result.s.full_duplex = 1;
483                    result.s.speed = 1000;
484                    break;
485            }
486        }
487        else
488        {
489            /* This code assumes we are using a Marvell Gigabit PHY. All the
490                speed information can be read from register 17 in one go. Somebody
491                using a different PHY will need to handle it above in the board
492                specific area */
493            int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
494
495            /* If the resolve bit 11 isn't set, see if autoneg is turned off
496                (bit 12, reg 0). The resolve bit doesn't get set properly when
497                autoneg is off, so force it */
498            if ((phy_status & (1<<11)) == 0)
499            {
500                int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
501                if ((auto_status & (1<<12)) == 0)
502                    phy_status |= 1<<11;
503            }
504
505            /* Only return a link if the PHY has finished auto negotiation
506                and set the resolved bit (bit 11) */
507            if (phy_status & (1<<11))
508            {
509#if defined(OCTEON_BOARD_CAPK_0100ND)
510                result.s.link_up = (phy_status>>10)&1;
511#else
512                result.s.link_up = 1;
513#endif
514                result.s.full_duplex = ((phy_status>>13)&1);
515                switch ((phy_status>>14)&3)
516                {
517                    case 0: /* 10 Mbps */
518                        result.s.speed = 10;
519                        break;
520                    case 1: /* 100 Mbps */
521                        result.s.speed = 100;
522                        break;
523                    case 2: /* 1 Gbps */
524                        result.s.speed = 1000;
525                        break;
526                    case 3: /* Illegal */
527                        result.u64 = 0;
528                        break;
529                }
530            }
531        }
532    }
533    else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
534    {
535        /* We don't have a PHY address, so attempt to use in-band status. It is
536            really important that boards not supporting in-band status never get
537            here. Reading broken in-band status tends to do bad things */
538        cvmx_gmxx_rxx_rx_inbnd_t inband_status;
539        int interface = cvmx_helper_get_interface_num(ipd_port);
540        int index = cvmx_helper_get_interface_index_num(ipd_port);
541        inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
542
543        result.s.link_up = inband_status.s.status;
544        result.s.full_duplex = inband_status.s.duplex;
545        switch (inband_status.s.speed)
546        {
547            case 0: /* 10 Mbps */
548                result.s.speed = 10;
549                break;
550            case 1: /* 100 Mbps */
551                result.s.speed = 100;
552                break;
553            case 2: /* 1 Gbps */
554                result.s.speed = 1000;
555                break;
556            case 3: /* Illegal */
557                result.u64 = 0;
558                break;
559        }
560    }
561    else
562    {
563        /* We don't have a PHY address and we don't have in-band status. There
564            is no way to determine the link speed. Return down assuming this
565            port isn't wired */
566        result.u64 = 0;
567    }
568
569    /* If link is down, return all fields as zero. */
570    if (!result.s.link_up)
571        result.u64 = 0;
572
573    return result;
574}
575
576
577/**
578 * This function as a board specific method of changing the PHY
579 * speed, duplex, and autonegotiation. This programs the PHY and
580 * not Octeon. This can be used to force Octeon's links to
581 * specific settings.
582 *
583 * @param phy_addr  The address of the PHY to program
584 * @param link_flags
585 *                  Flags to control autonegotiation.  Bit 0 is autonegotiation
586 *                  enable/disable to maintain backward compatibility.
587 * @param link_info Link speed to program. If the speed is zero and autonegotiation
588 *                  is enabled, all possible negotiation speeds are advertised.
589 *
590 * @return Zero on success, negative on failure
591 */
592int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags,
593                                   cvmx_helper_link_info_t link_info)
594{
595
596    /* Set the flow control settings based on link_flags */
597    if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch)
598    {
599        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
600        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
601        reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
602        reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
603        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
604    }
605
606    /* If speed isn't set and autoneg is on advertise all supported modes */
607    if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0))
608    {
609        cvmx_mdio_phy_reg_control_t reg_control;
610        cvmx_mdio_phy_reg_status_t reg_status;
611        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
612        cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
613        cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
614
615        reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
616        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
617        reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4;
618        reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full;
619        reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half;
620        reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full;
621        reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half;
622        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
623        if (reg_status.s.capable_extended_status)
624        {
625            reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
626            reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
627            reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full;
628            reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half;
629            cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
630        }
631        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
632        reg_control.s.autoneg_enable = 1;
633        reg_control.s.restart_autoneg = 1;
634        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
635    }
636    else if ((link_flags & set_phy_link_flags_autoneg))
637    {
638        cvmx_mdio_phy_reg_control_t reg_control;
639        cvmx_mdio_phy_reg_status_t reg_status;
640        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
641        cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
642        cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
643
644        reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
645        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
646        reg_autoneg_adver.s.advert_100base_t4 = 0;
647        reg_autoneg_adver.s.advert_10base_tx_full = 0;
648        reg_autoneg_adver.s.advert_10base_tx_half = 0;
649        reg_autoneg_adver.s.advert_100base_tx_full = 0;
650        reg_autoneg_adver.s.advert_100base_tx_half = 0;
651        if (reg_status.s.capable_extended_status)
652        {
653            reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
654            reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
655            reg_control_1000.s.advert_1000base_t_full = 0;
656            reg_control_1000.s.advert_1000base_t_half = 0;
657        }
658        switch (link_info.s.speed)
659        {
660            case 10:
661                reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex;
662                reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex;
663                break;
664            case 100:
665                reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex;
666                reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex;
667                break;
668            case 1000:
669                reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex;
670                reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex;
671                break;
672        }
673        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
674        if (reg_status.s.capable_extended_status)
675            cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
676        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
677        reg_control.s.autoneg_enable = 1;
678        reg_control.s.restart_autoneg = 1;
679        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
680    }
681    else
682    {
683        cvmx_mdio_phy_reg_control_t reg_control;
684        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
685        reg_control.s.autoneg_enable = 0;
686        reg_control.s.restart_autoneg = 1;
687        reg_control.s.duplex = link_info.s.full_duplex;
688        if (link_info.s.speed == 1000)
689        {
690            reg_control.s.speed_msb = 1;
691            reg_control.s.speed_lsb = 0;
692        }
693        else if (link_info.s.speed == 100)
694        {
695            reg_control.s.speed_msb = 0;
696            reg_control.s.speed_lsb = 1;
697        }
698        else if (link_info.s.speed == 10)
699        {
700            reg_control.s.speed_msb = 0;
701            reg_control.s.speed_lsb = 0;
702        }
703        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
704    }
705    return 0;
706}
707
708
709/**
710 * @INTERNAL
711 * This function is called by cvmx_helper_interface_probe() after it
712 * determines the number of ports Octeon can support on a specific
713 * interface. This function is the per board location to override
714 * this value. It is called with the number of ports Octeon might
715 * support and should return the number of actual ports on the
716 * board.
717 *
718 * This function must be modified for every new Octeon board.
719 * Internally it uses switch statements based on the cvmx_sysinfo
720 * data to determine board types and revisions. It relies on the
721 * fact that every Octeon board receives a unique board type
722 * enumeration from the bootloader.
723 *
724 * @param interface Interface to probe
725 * @param supported_ports
726 *                  Number of ports Octeon supports.
727 *
728 * @return Number of ports the actual board supports. Many times this will
729 *         simple be "support_ports".
730 */
731int __cvmx_helper_board_interface_probe(int interface, int supported_ports)
732{
733    switch (cvmx_sysinfo_get()->board_type)
734    {
735        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
736        case CVMX_BOARD_TYPE_LANAI2_A:
737        case CVMX_BOARD_TYPE_LANAI2_U:
738        case CVMX_BOARD_TYPE_LANAI2_G:
739            if (interface == 0)
740                return 2;
741	    break;
742        case CVMX_BOARD_TYPE_BBGW_REF:
743            if (interface == 0)
744                return 2;
745	    break;
746        case CVMX_BOARD_TYPE_NIC_XLE_4G:
747            if (interface == 0)
748                return 0;
749	    break;
750        /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
751            which we don't support. Disable ports connected to it */
752        case CVMX_BOARD_TYPE_EBH5600:
753            if (interface == 1)
754                return 0;
755	    break;
756        case CVMX_BOARD_TYPE_EBB5600:
757#ifdef CVMX_ENABLE_PKO_FUNCTIONS
758            if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_PICMG)
759                return 0;
760#endif
761	    break;
762        case CVMX_BOARD_TYPE_EBT5810:
763            return 1;  /* Two ports on each SPI: 1 hooked to MAC, 1 loopback
764                       ** Loopback disabled by default. */
765#if defined(OCTEON_VENDOR_LANNER)
766	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
767	    if (interface == 1)
768	        return 12;
769	    break;
770#endif
771    }
772#ifdef CVMX_BUILD_FOR_UBOOT
773    if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi"))
774        return 0;
775#endif
776    return supported_ports;
777}
778
779
780/**
781 * @INTERNAL
782 * Enable packet input/output from the hardware. This function is
783 * called after by cvmx_helper_packet_hardware_enable() to
784 * perform board specific initialization. For most boards
785 * nothing is needed.
786 *
787 * @param interface Interface to enable
788 *
789 * @return Zero on success, negative on failure
790 */
791int __cvmx_helper_board_hardware_enable(int interface)
792{
793    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5)
794    {
795        if (interface == 0)
796        {
797            /* Different config for switch port */
798            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
799            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
800            /* Boards with gigabit WAN ports need a different setting that is
801                compatible with 100 Mbit settings */
802            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc);
803            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc);
804        }
805    }
806    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_LANAI2_U)
807    {
808        if (interface == 0)
809        {
810            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 16);
811            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 16);
812        }
813    }
814    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5)
815    {
816        /* Broadcom PHYs require different ASX clocks. Unfortunately
817            many customer don't define a new board Id and simply
818            mangle the CN3010_EVB_HS5 */
819        if (interface == 0)
820        {
821            /* Some customers boards use a hacked up bootloader that identifies them as
822            ** CN3010_EVB_HS5 evaluation boards.  This leads to all kinds of configuration
823            ** problems.  Detect one case, and print warning, while trying to do the right thing.
824            */
825            int phy_addr = cvmx_helper_board_get_mii_address(0);
826            if (phy_addr != -1)
827            {
828                int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2);
829                /* Is it a Broadcom PHY? */
830                if (phy_identifier == 0x0143)
831                {
832                    cvmx_dprintf("\n");
833                    cvmx_dprintf("ERROR:\n");
834                    cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
835                    cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
836                    cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n");
837                    cvmx_dprintf("ERROR:\n");
838                    cvmx_dprintf("\n");
839                    cvmx_wait(1000000000);
840                    cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5);
841                    cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5);
842                }
843            }
844        }
845    }
846    return 0;
847}
848
849
850/**
851 * @INTERNAL
852 * Gets the clock type used for the USB block based on board type.
853 * Used by the USB code for auto configuration of clock type.
854 *
855 * @return USB clock type enumeration
856 */
857cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void)
858{
859    switch (cvmx_sysinfo_get()->board_type)
860    {
861        case CVMX_BOARD_TYPE_BBGW_REF:
862        case CVMX_BOARD_TYPE_LANAI2_A:
863        case CVMX_BOARD_TYPE_LANAI2_U:
864        case CVMX_BOARD_TYPE_LANAI2_G:
865#if defined(OCTEON_VENDOR_LANNER)
866    case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
867    case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
868#endif
869#if defined(OCTEON_BOARD_CAPK_0100ND)
870	case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
871#endif
872            return USB_CLOCK_TYPE_CRYSTAL_12;
873    }
874    return USB_CLOCK_TYPE_REF_48;
875}
876
877
878/**
879 * @INTERNAL
880 * Adjusts the number of available USB ports on Octeon based on board
881 * specifics.
882 *
883 * @param supported_ports expected number of ports based on chip type;
884 *
885 *
886 * @return number of available usb ports, based on board specifics.
887 *         Return value is supported_ports if function does not
888 *         override.
889 */
890int __cvmx_helper_board_usb_get_num_ports(int supported_ports)
891{
892    switch (cvmx_sysinfo_get()->board_type)
893    {
894        case CVMX_BOARD_TYPE_NIC_XLE_4G:
895            return 0;
896    }
897
898    return supported_ports;
899}
900
901
902