1/***********************license start***************
2 * Copyright (c) 2003-2011  Cavium Inc. (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 Inc. 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 INC. 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: 70030 $<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#include "cvmx-gpio.h"
76#if !defined(__FreeBSD__) || !defined(_KERNEL)
77#ifdef __U_BOOT__
78# include <libfdt.h>
79#else
80# include "libfdt/libfdt.h"
81#endif
82#endif
83#include "cvmx-swap.h"
84#endif
85
86/**
87 * cvmx_override_board_link_get(int ipd_port) is a function
88 * pointer. It is meant to allow customization of the process of
89 * talking to a PHY to determine link speed. It is called every
90 * time a PHY must be polled for link status. Users should set
91 * this pointer to a function before calling any cvmx-helper
92 * operations.
93 */
94CVMX_SHARED cvmx_helper_link_info_t (*cvmx_override_board_link_get)(int ipd_port) = NULL;
95
96#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
97
98static void cvmx_retry_i2c_write(int twsi_id, uint8_t dev_addr, uint16_t internal_addr, int num_bytes, int ia_width_bytes, uint64_t data)
99{
100    int tries = 3;
101    int r;
102    do {
103        r = cvmx_twsix_write_ia(twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes, data);
104    } while (tries-- > 0 && r < 0);
105}
106
107static int __pip_eth_node(const void *fdt_addr, int aliases, int ipd_port)
108{
109    char name_buffer[20];
110    const char*pip_path;
111    int pip, iface, eth;
112    int interface_num    = cvmx_helper_get_interface_num(ipd_port);
113    int interface_index  = cvmx_helper_get_interface_index_num(ipd_port);
114
115    pip_path = fdt_getprop(fdt_addr, aliases, "pip", NULL);
116    if (!pip_path)
117    {
118        cvmx_dprintf("ERROR: pip path not found in device tree\n");
119        return -1;
120    }
121    pip = fdt_path_offset(fdt_addr, pip_path);
122    if (pip < 0)
123    {
124        cvmx_dprintf("ERROR: pip not found in device tree\n");
125        return -1;
126    }
127#ifdef __U_BOOT__
128    sprintf(name_buffer, "interface@%d", interface_num);
129#else
130    snprintf(name_buffer, sizeof(name_buffer), "interface@%d", interface_num);
131#endif
132    iface =  fdt_subnode_offset(fdt_addr, pip, name_buffer);
133    if (iface < 0)
134    {
135        cvmx_dprintf("ERROR : pip intf %d not found in device tree \n",
136                     interface_num);
137        return -1;
138    }
139#ifdef __U_BOOT__
140    sprintf(name_buffer, "ethernet@%x", interface_index);
141#else
142    snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", interface_index);
143#endif
144    eth = fdt_subnode_offset(fdt_addr, iface, name_buffer);
145    if (eth < 0)
146    {
147        cvmx_dprintf("ERROR : pip interface@%d ethernet@%d not found in device "
148                     "tree\n", interface_num, interface_index);
149        return -1;
150    }
151    return eth;
152}
153
154static int __mix_eth_node(const void *fdt_addr, int aliases, int interface_index)
155{
156    char name_buffer[20];
157    const char*mix_path;
158    int mix;
159
160#ifdef __U_BOOT__
161    sprintf(name_buffer, "mix%d", interface_index);
162#else
163    snprintf(name_buffer, sizeof(name_buffer), "mix%d", interface_index);
164#endif
165    mix_path = fdt_getprop(fdt_addr, aliases, name_buffer, NULL);
166    if (!mix_path)
167    {
168        cvmx_dprintf("ERROR: mix%d path not found in device tree\n",interface_index);
169    }
170    mix = fdt_path_offset(fdt_addr, mix_path);
171    if (mix < 0)
172    {
173        cvmx_dprintf("ERROR: %s not found in device tree\n", mix_path);
174        return -1;
175    }
176    return mix;
177}
178
179typedef struct cvmx_phy_info
180{
181    int phy_addr;
182    int direct_connect;
183    cvmx_phy_type_t phy_type;
184}cvmx_phy_info_t;
185
186
187static int __mdiobus_addr_to_unit(uint32_t addr)
188{
189    int unit = (addr >> 7) & 3;
190    if (!OCTEON_IS_MODEL(OCTEON_CN68XX))
191        unit >>= 1;
192    return unit;
193}
194/**
195 * Return the MII PHY address associated with the given IPD
196 * port. The phy address is obtained from the device tree.
197 *
198 * @param ipd_port Octeon IPD port to get the MII address for.
199 *
200 * @return MII PHY address and bus number or -1.
201 */
202
203static cvmx_phy_info_t __get_phy_info_from_dt(int ipd_port)
204{
205    const void *fdt_addr = CASTPTR(const void *, cvmx_sysinfo_get()->fdt_addr);
206    uint32_t *phy_handle;
207    int aliases, eth, phy, phy_parent, phandle, ret;
208    cvmx_phy_info_t phy_info;
209    int mdio_unit=-1;
210    const char *phy_comaptible_str;
211    uint32_t *phy_addr_ptr;
212
213    phy_info.phy_addr = -1;
214    phy_info.direct_connect = -1;
215    phy_info.phy_type = (cvmx_phy_type_t) -1;
216
217    if (!fdt_addr)
218    {
219        cvmx_dprintf("No device tree found.\n");
220        return phy_info;
221    }
222    aliases = fdt_path_offset(fdt_addr, "/aliases");
223    if (aliases < 0) {
224        cvmx_dprintf("Error: No /aliases node in device tree.\n");
225        return phy_info;
226    }
227    if (ipd_port < 0)
228    {
229        int interface_index = ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
230        eth = __mix_eth_node(fdt_addr, aliases, interface_index) ;
231    }
232    else
233    {
234        eth = __pip_eth_node(fdt_addr, aliases, ipd_port);
235    }
236    if (eth < 0 )
237    {
238        cvmx_dprintf("ERROR : cannot find interface for ipd_port=%d\n", ipd_port);
239        return phy_info;
240    }
241    /* Get handle to phy */
242    phy_handle = (uint32_t *) fdt_getprop(fdt_addr, eth, "phy-handle", NULL);
243    if (!phy_handle)
244    {
245        cvmx_dprintf("ERROR : phy handle not found in device tree ipd_port=%d"
246                     "\n", ipd_port);
247        return phy_info;
248    }
249    phandle = cvmx_be32_to_cpu(*phy_handle);
250    phy = fdt_node_offset_by_phandle(fdt_addr, phandle);
251    if (phy < 0)
252    {
253        cvmx_dprintf("ERROR : cannot find phy for ipd_port=%d ret=%d\n",
254                     ipd_port, phy);
255        return phy_info;
256    }
257    phy_comaptible_str = (const char *) fdt_getprop(fdt_addr, phy,
258                                                    "compatible", NULL);
259    if (!phy_comaptible_str)
260    {
261        cvmx_dprintf("ERROR : no compatible prop in phy\n");
262        return phy_info;
263    }
264    if (memcmp("marvell", phy_comaptible_str, strlen("marvell")) == 0)
265    {
266        phy_info.phy_type = MARVELL_GENERIC_PHY;
267    }
268    else if (memcmp("broadcom", phy_comaptible_str, strlen("broadcom")) == 0)
269    {
270        phy_info.phy_type = BROADCOM_GENERIC_PHY;
271    }
272    else
273    {
274        phy_info.phy_type = -1;
275    }
276
277    /* Check if PHY parent is the octeon MDIO bus. Some boards are connected
278       though a MUX and for them direct_connect_to_phy will be 0 */
279    phy_parent = fdt_parent_offset(fdt_addr, phy);
280    if (phy_parent < 0)
281    {
282        cvmx_dprintf("ERROR : cannot find phy parent for ipd_port=%d ret=%d\n",
283                     ipd_port, phy_parent);
284        return phy_info;
285    }
286    ret = fdt_node_check_compatible(fdt_addr, phy_parent,
287                                    "cavium,octeon-3860-mdio");
288    if (ret == 0)
289    {
290        phy_info.direct_connect = 1 ;
291        uint32_t *mdio_reg_base = (uint32_t *) fdt_getprop(fdt_addr, phy_parent,"reg",0);
292        if (mdio_reg_base == 0)
293        {
294            cvmx_dprintf("ERROR : unable to get reg property in phy mdio\n");
295            return phy_info;
296        }
297        mdio_unit = __mdiobus_addr_to_unit(mdio_reg_base[1]);
298        //cvmx_dprintf("phy parent=%s reg_base=%08x unit=%d \n",
299        //             fdt_get_name(fdt_addr,phy_parent, NULL), mdio_reg_base[1], mdio_unit);
300    }
301    else
302    {
303        phy_info.direct_connect = 0;
304        /* The PHY is not directly connected to the Octeon MDIO bus.
305           SE doesn't  have abstractions for MDIO MUX or MDIO MUX drivers and
306           hence for the non direct cases code will be needed which is
307           board specific.
308           For now the the MDIO Unit is defaulted to 1.
309        */
310        mdio_unit = 1;
311    }
312
313    phy_addr_ptr = (uint32_t *) fdt_getprop(fdt_addr, phy, "reg", NULL);
314    phy_info.phy_addr = cvmx_be32_to_cpu(*phy_addr_ptr) | mdio_unit << 8;
315    return phy_info;
316
317}
318
319/**
320 * Return the MII PHY address associated with the given IPD
321 * port. The phy address is obtained from the device tree.
322 *
323 * @param ipd_port Octeon IPD port to get the MII address for.
324 *
325 * @return MII PHY address and bus number or -1.
326 */
327
328int cvmx_helper_board_get_mii_address_from_dt(int ipd_port)
329{
330        cvmx_phy_info_t phy_info = __get_phy_info_from_dt(ipd_port);
331        return phy_info.phy_addr;
332}
333#endif
334
335/**
336 * Return the MII PHY address associated with the given IPD
337 * port. A result of -1 means there isn't a MII capable PHY
338 * connected to this port. On chips supporting multiple MII
339 * busses the bus number is encoded in bits <15:8>.
340 *
341 * This function must be modified for every new Octeon board.
342 * Internally it uses switch statements based on the cvmx_sysinfo
343 * data to determine board types and revisions. It replies on the
344 * fact that every Octeon board receives a unique board type
345 * enumeration from the bootloader.
346 *
347 * @param ipd_port Octeon IPD port to get the MII address for.
348 *
349 * @return MII PHY address and bus number or -1.
350 */
351int cvmx_helper_board_get_mii_address(int ipd_port)
352{
353    /*
354     * Board types we have to know at compile-time.
355     */
356#ifdef OCTEON_BOARD_CAPK_0100ND
357    switch (ipd_port) {
358    case 0:
359	return 2;
360    case 1:
361	return 3;
362    case 2:
363	/* XXX Switch PHY?  */
364	return -1;
365    default:
366	return -1;
367    }
368#endif
369
370    /*
371     * For board types we can determine at runtime.
372     */
373    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
374        return -1;
375#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
376    if (cvmx_sysinfo_get()->fdt_addr)
377    {
378        cvmx_phy_info_t phy_info = __get_phy_info_from_dt(ipd_port);
379        //cvmx_dprintf("ipd_port=%d phy_addr=%d\n", ipd_port, phy_info.phy_addr);
380        if (phy_info.phy_addr >= 0) return phy_info.phy_addr;
381    }
382#endif
383    switch (cvmx_sysinfo_get()->board_type)
384    {
385        case CVMX_BOARD_TYPE_SIM:
386            /* Simulator doesn't have MII */
387            return -1;
388#if !defined(OCTEON_VENDOR_GEFES)
389        case CVMX_BOARD_TYPE_EBT5800:
390        case CVMX_BOARD_TYPE_NICPRO2:
391#endif
392        case CVMX_BOARD_TYPE_EBT3000:
393        case CVMX_BOARD_TYPE_THUNDER:
394            /* Interface 0 is SPI4, interface 1 is RGMII */
395            if ((ipd_port >= 16) && (ipd_port < 20))
396                return ipd_port - 16;
397            else
398                return -1;
399        case CVMX_BOARD_TYPE_LANAI2_A:
400            if (ipd_port == 0)
401                return 0;
402            else
403                return -1;
404        case CVMX_BOARD_TYPE_LANAI2_U:
405        case CVMX_BOARD_TYPE_LANAI2_G:
406            if (ipd_port == 0)
407                return 0x1c;
408            else
409                return -1;
410        case CVMX_BOARD_TYPE_KODAMA:
411        case CVMX_BOARD_TYPE_EBH3100:
412        case CVMX_BOARD_TYPE_HIKARI:
413        case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
414        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
415#if !defined(OCTEON_VENDOR_GEFES)
416        case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
417#endif
418            /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a
419                switch */
420            if (ipd_port == 0)
421                return 4;
422            else if (ipd_port == 1)
423                return 9;
424            else
425                return -1;
426        case CVMX_BOARD_TYPE_EBH3000:
427            /* Board has dual SPI4 and no PHYs */
428            return -1;
429        case CVMX_BOARD_TYPE_EBT5810:
430            /* Board has 10g PHYs hooked up to the MII controller on the
431            ** IXF18201 MAC.  The 10G PHYS use clause 45 MDIO which the CN58XX
432            ** does not support. All MII accesses go through the IXF part. */
433            return -1;
434        case CVMX_BOARD_TYPE_EBH5200:
435        case CVMX_BOARD_TYPE_EBH5201:
436        case CVMX_BOARD_TYPE_EBT5200:
437            /* Board has 2 management ports */
438            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
439                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
440            /* Board has 4 SGMII ports. The PHYs start right after the MII
441                ports MII0 = 0, MII1 = 1, SGMII = 2-5 */
442            if ((ipd_port >= 0) && (ipd_port < 4))
443                return ipd_port+2;
444            else
445                return -1;
446        case CVMX_BOARD_TYPE_EBH5600:
447        case CVMX_BOARD_TYPE_EBH5601:
448        case CVMX_BOARD_TYPE_EBH5610:
449            /* Board has 1 management port */
450            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
451                return 0;
452            /* Board has 8 SGMII ports. 4 connect out, two connect to a switch,
453                and 2 loop to each other */
454            if ((ipd_port >= 0) && (ipd_port < 4))
455                return ipd_port+1;
456            else
457                return -1;
458        case CVMX_BOARD_TYPE_EBT5600:
459	    /* Board has 1 management port */
460            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
461                return 0;
462	    /* Board has 1 XAUI port connected to a switch.  */
463	    return -1;
464        case CVMX_BOARD_TYPE_EBB5600:
465            {
466                static unsigned char qlm_switch_addr = 0;
467
468                /* Board has 1 management port */
469                if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
470                    return 0;
471
472                /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */
473                if ((ipd_port >= 0) && (ipd_port < 4))
474                {
475                    if (qlm_switch_addr != 0x3)
476                    {
477                        qlm_switch_addr = 0x3;  /* QLM1 */
478                        cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
479                        cvmx_wait_usec(11000); /* Let the write complete */
480                    }
481                    return ipd_port+1 + (1<<8);
482                }
483                else if ((ipd_port >= 16) && (ipd_port < 20))
484                {
485                    if (qlm_switch_addr != 0xC)
486                    {
487                        qlm_switch_addr = 0xC;  /* QLM3 */
488                        cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
489                        cvmx_wait_usec(11000); /* Let the write complete */
490                    }
491                    return ipd_port-16+1 + (1<<8);
492                }
493                else
494                    return -1;
495            }
496        case CVMX_BOARD_TYPE_EBB6300:
497            /* Board has 2 management ports */
498            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
499                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
500            if ((ipd_port >= 0) && (ipd_port < 4))
501                return ipd_port + 1 + (1<<8);
502            else
503                return -1;
504        case CVMX_BOARD_TYPE_EBB6800:
505            /* Board has 1 management ports */
506            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
507                return 6;
508            if (ipd_port >= 0x800 && ipd_port < 0x900) /* QLM 0*/
509                return 0x101 + ((ipd_port >> 4) & 3); /* SMI 1*/
510            if (ipd_port >= 0xa00 && ipd_port < 0xb00) /* QLM 2*/
511                return 0x201 + ((ipd_port >> 4) & 3); /* SMI 2*/
512            if (ipd_port >= 0xb00 && ipd_port < 0xc00) /* QLM 3*/
513                return 0x301 + ((ipd_port >> 4) & 3); /* SMI 3*/
514            if (ipd_port >= 0xc00 && ipd_port < 0xd00) /* QLM 4*/
515                return 0x001 + ((ipd_port >> 4) & 3); /* SMI 0*/
516            return -1;
517        case CVMX_BOARD_TYPE_EP6300C:
518            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
519                return 0x01;
520            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT+1)
521                return 0x02;
522#ifdef CVMX_ENABLE_PKO_FUNCTIONS
523            {
524                int interface = cvmx_helper_get_interface_num(ipd_port);
525                int mode = cvmx_helper_interface_get_mode(interface);
526                if (mode == CVMX_HELPER_INTERFACE_MODE_XAUI)
527                    return ipd_port;
528                else if ((ipd_port >= 0) && (ipd_port < 4))
529                    return ipd_port + 3;
530                else
531                    return -1;
532            }
533#endif
534            break;
535        case CVMX_BOARD_TYPE_CUST_NB5:
536            if (ipd_port == 2)
537                return 4;
538            else
539                return -1;
540        case CVMX_BOARD_TYPE_NIC_XLE_4G:
541            /* Board has 4 SGMII ports. connected QLM3(interface 1) */
542            if ((ipd_port >= 16) && (ipd_port < 20))
543                return ipd_port - 16 + 1;
544            else
545                return -1;
546        case CVMX_BOARD_TYPE_NIC_XLE_10G:
547        case CVMX_BOARD_TYPE_NIC10E:
548            return -1;  /* We don't use clause 45 MDIO for anything */
549        case CVMX_BOARD_TYPE_NIC4E:
550            if (ipd_port >= 0 && ipd_port <= 3)
551                return (ipd_port + 0x1f) & 0x1f;
552            else
553                return -1;
554        case CVMX_BOARD_TYPE_NIC2E:
555            if (ipd_port >= 0 && ipd_port <= 1)
556                return (ipd_port + 1);
557            else
558                return -1;
559        case CVMX_BOARD_TYPE_REDWING:
560	    return -1;  /* No PHYs connected to Octeon */
561        case CVMX_BOARD_TYPE_BBGW_REF:
562            return -1;  /* No PHYs are connected to Octeon, everything is through switch */
563	case CVMX_BOARD_TYPE_CUST_WSX16:
564		if (ipd_port >= 0 && ipd_port <= 3)
565			return ipd_port;
566		else if (ipd_port >= 16 && ipd_port <= 19)
567			return ipd_port - 16 + 4;
568		else
569			return -1;
570
571	/* Private vendor-defined boards.  */
572#if defined(OCTEON_VENDOR_LANNER)
573	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
574	    /* Interface 1 is 12 BCM5482S PHYs.  */
575            if ((ipd_port >= 16) && (ipd_port < 28))
576                return ipd_port - 16;
577	    return -1;
578	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
579            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
580		return (ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT) + 0x81;
581            if ((ipd_port >= 0) && (ipd_port < 4))
582                return ipd_port;
583	    return -1;
584	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
585	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
586	    /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell
587	       88E1111 interfaces.  */
588	    switch (ipd_port) {
589	    case 0:
590		return 16;
591	    case 1:
592		return 1;
593	    case 2:
594		return 2;
595	    default:
596		return -1;
597	    }
598#endif
599#if defined(OCTEON_VENDOR_UBIQUITI)
600	case CVMX_BOARD_TYPE_CUST_UBIQUITI_E100:
601	case CVMX_BOARD_TYPE_CUST_UBIQUITI_USG:
602	    if (ipd_port > 2)
603		return -1;
604	    return (7 - ipd_port);
605#endif
606#if defined(OCTEON_VENDOR_RADISYS)
607	case CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE:
608	    /* No MII.  */
609	    return -1;
610#endif
611#if defined(OCTEON_VENDOR_GEFES)
612        case CVMX_BOARD_TYPE_AT5810:
613		return -1;
614        case CVMX_BOARD_TYPE_TNPA3804:
615    	case CVMX_BOARD_TYPE_CUST_TNPA5804:
616	case CVMX_BOARD_TYPE_CUST_W5800:
617	case CVMX_BOARD_TYPE_WNPA3850:
618	case CVMX_BOARD_TYPE_W3860:
619		return -1;// RGMII boards should use inbad status
620	case CVMX_BOARD_TYPE_CUST_W5651X:
621	case CVMX_BOARD_TYPE_CUST_W5650:
622	case CVMX_BOARD_TYPE_CUST_TNPA56X4:
623	case CVMX_BOARD_TYPE_CUST_TNPA5651X:
624        case CVMX_BOARD_TYPE_CUST_W63XX:
625		return -1; /* No PHYs are connected to Octeon, PHYs inside of SFPs which is accessed over TWSI */
626	case CVMX_BOARD_TYPE_CUST_W5434:
627		/* Board has 4 SGMII ports. 4 connect out
628		 * must return the MII address of the PHY connected to each IPD port
629		 */
630		if ((ipd_port >= 16) && (ipd_port < 20))
631			return ipd_port - 16 + 0x40;
632		else
633			return -1;
634#endif
635    }
636
637    /* Some unknown board. Somebody forgot to update this function... */
638    cvmx_dprintf("%s: Unknown board type %d\n",
639                 __FUNCTION__, cvmx_sysinfo_get()->board_type);
640    return -1;
641}
642#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
643EXPORT_SYMBOL(cvmx_helper_board_get_mii_address);
644#endif
645
646/**
647 * @INTERNAL
648 * Get link state of marvell PHY
649 */
650static cvmx_helper_link_info_t __get_marvell_phy_link_state(int phy_addr)
651{
652    cvmx_helper_link_info_t  result;
653    int phy_status;
654
655    result.u64 = 0;
656    /*All the speed information can be read from register 17 in one go.*/
657    phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
658
659    /* If the resolve bit 11 isn't set, see if autoneg is turned off
660       (bit 12, reg 0). The resolve bit doesn't get set properly when
661       autoneg is off, so force it */
662    if ((phy_status & (1<<11)) == 0)
663    {
664        int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
665        if ((auto_status & (1<<12)) == 0)
666            phy_status |= 1<<11;
667    }
668
669    /* Only return a link if the PHY has finished auto negotiation
670       and set the resolved bit (bit 11) */
671    if (phy_status & (1<<11))
672    {
673        result.s.link_up = 1;
674        result.s.full_duplex = ((phy_status>>13)&1);
675        switch ((phy_status>>14)&3)
676        {
677            case 0: /* 10 Mbps */
678                result.s.speed = 10;
679                break;
680            case 1: /* 100 Mbps */
681                result.s.speed = 100;
682                break;
683            case 2: /* 1 Gbps */
684                result.s.speed = 1000;
685                break;
686            case 3: /* Illegal */
687                result.u64 = 0;
688                break;
689        }
690    }
691    return result;
692}
693
694/**
695 * @INTERNAL
696 * Get link state of broadcom PHY
697 */
698static cvmx_helper_link_info_t __get_broadcom_phy_link_state(int phy_addr)
699{
700    cvmx_helper_link_info_t  result;
701    int phy_status;
702
703    result.u64 = 0;
704    /* Below we are going to read SMI/MDIO register 0x19 which works
705       on Broadcom parts */
706    phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19);
707    switch ((phy_status>>8) & 0x7)
708    {
709        case 0:
710            result.u64 = 0;
711            break;
712        case 1:
713            result.s.link_up = 1;
714            result.s.full_duplex = 0;
715            result.s.speed = 10;
716            break;
717        case 2:
718            result.s.link_up = 1;
719            result.s.full_duplex = 1;
720            result.s.speed = 10;
721            break;
722        case 3:
723            result.s.link_up = 1;
724            result.s.full_duplex = 0;
725            result.s.speed = 100;
726            break;
727        case 4:
728            result.s.link_up = 1;
729            result.s.full_duplex = 1;
730            result.s.speed = 100;
731            break;
732        case 5:
733            result.s.link_up = 1;
734            result.s.full_duplex = 1;
735            result.s.speed = 100;
736            break;
737        case 6:
738            result.s.link_up = 1;
739            result.s.full_duplex = 0;
740            result.s.speed = 1000;
741            break;
742        case 7:
743            result.s.link_up = 1;
744            result.s.full_duplex = 1;
745            result.s.speed = 1000;
746            break;
747    }
748    return result;
749}
750
751
752/**
753 * @INTERNAL
754 * Get link state using inband status
755 */
756static cvmx_helper_link_info_t __get_inband_link_state(int ipd_port)
757{
758    cvmx_helper_link_info_t  result;
759    cvmx_gmxx_rxx_rx_inbnd_t inband_status;
760    int interface = cvmx_helper_get_interface_num(ipd_port);
761    int index = cvmx_helper_get_interface_index_num(ipd_port);
762
763    result.u64 = 0;
764    inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
765    result.s.link_up = inband_status.s.status;
766    result.s.full_duplex = inband_status.s.duplex;
767    switch (inband_status.s.speed)
768    {
769        case 0: /* 10 Mbps */
770            result.s.speed = 10;
771            break;
772        case 1: /* 100 Mbps */
773            result.s.speed = 100;
774            break;
775        case 2: /* 1 Gbps */
776            result.s.speed = 1000;
777            break;
778        case 3: /* Illegal */
779            result.u64 = 0;
780            break;
781    }
782    return result;
783}
784
785#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
786/**
787 * @INTERNAL
788 * Switch MDIO mux to the specified port.
789 */
790static int __switch_mdio_mux(int ipd_port)
791{
792    /* This method is board specific and doesn't use the device tree
793       information as SE doesn't implement MDIO MUX abstration */
794    switch (cvmx_sysinfo_get()->board_type)
795    {
796        case CVMX_BOARD_TYPE_EBB5600:
797        {
798            static unsigned char qlm_switch_addr = 0;
799            /* Board has 1 management port */
800            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
801                return 0;
802            /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */
803            if ((ipd_port >= 0) && (ipd_port < 4))
804            {
805                if (qlm_switch_addr != 0x3)
806                {
807                    qlm_switch_addr = 0x3;  /* QLM1 */
808                    cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
809                    cvmx_wait_usec(11000); /* Let the write complete */
810                }
811                return ipd_port+1 + (1<<8);
812            }
813            else if ((ipd_port >= 16) && (ipd_port < 20))
814            {
815                if (qlm_switch_addr != 0xC)
816                {
817                    qlm_switch_addr = 0xC;  /* QLM3 */
818                    cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
819                    cvmx_wait_usec(11000); /* Let the write complete */
820                }
821                return ipd_port-16+1 + (1<<8);
822            }
823            else
824                return -1;
825        }
826        case CVMX_BOARD_TYPE_EBB6600:
827        {
828            static unsigned char qlm_switch_addr = 0;
829            int old_twsi_switch_reg;
830            /* Board has 2 management ports */
831            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) &&
832                (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
833                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
834            if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */
835            {
836                if (qlm_switch_addr != 2)
837                {
838                    int tries;
839                    qlm_switch_addr = 2;
840                    tries = 3;
841                    do {
842                        old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0);
843                    } while (tries-- > 0 && old_twsi_switch_reg < 0);
844                    /* Set I2C MUX to enable port expander */
845                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8);
846                    /* Set selecter to QLM 1 */
847                    cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xff);
848                    /* disable port expander */
849                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg);
850                }
851                return 0x101 + ipd_port;
852            }
853            else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 1 */
854            {
855                if (qlm_switch_addr != 1)
856                {
857                    int tries;
858                    qlm_switch_addr = 1;
859                    tries = 3;
860                    do {
861                            old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0);
862                    } while (tries-- > 0 && old_twsi_switch_reg < 0);
863                    /* Set I2C MUX to enable port expander */
864                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8);
865                    /* Set selecter to QLM 2 */
866                    cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xf7);
867                    /* disable port expander */
868                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg);
869                }
870                return 0x101 + (ipd_port - 16);
871            } else
872                return -1;
873        }
874        case CVMX_BOARD_TYPE_EBB6100:
875        {
876            static char gpio_configured = 0;
877
878            if (!gpio_configured)
879            {
880                cvmx_gpio_cfg(3, 1);
881                gpio_configured = 1;
882            }
883            /* Board has 2 management ports */
884            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) &&
885                (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
886                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
887            if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */
888            {
889                cvmx_gpio_set(1ull << 3);
890                return 0x101 + ipd_port;
891            }
892            else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 0 */
893            {
894                cvmx_gpio_clear(1ull << 3);
895                return 0x101 + (ipd_port - 16);
896            }
897            else
898            {
899                printf("%s: Unknown ipd port 0x%x\n", __func__, ipd_port);
900                return -1;
901            }
902        }
903        default:
904        {
905            cvmx_dprintf("ERROR : unexpected mdio switch for board=%08x\n",
906                         cvmx_sysinfo_get()->board_type);
907            return -1;
908        }
909    }
910    /* should never get here */
911    return -1;
912}
913
914/**
915 * @INTERNAL
916 * This function is used ethernet ports link speed. This functions uses the
917 * device tree information to determine the phy address and type of PHY.
918 * The only supproted PHYs are Marvell and Broadcom.
919 *
920 * @param ipd_port IPD input port associated with the port we want to get link
921 *                 status for.
922 *
923 * @return The ports link status. If the link isn't fully resolved, this must
924 *         return zero.
925 */
926
927cvmx_helper_link_info_t __cvmx_helper_board_link_get_from_dt(int ipd_port)
928{
929    cvmx_helper_link_info_t  result;
930    cvmx_phy_info_t phy_info;
931
932    result.u64 = 0;
933    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
934    {
935        /* The simulator gives you a simulated 1Gbps full duplex link */
936        result.s.link_up = 1;
937        result.s.full_duplex = 1;
938        result.s.speed = 1000;
939        return result;
940    }
941    phy_info = __get_phy_info_from_dt(ipd_port);
942    //cvmx_dprintf("ipd_port=%d phy_addr=%d dc=%d type=%d \n", ipd_port,
943    //             phy_info.phy_addr, phy_info.direct_connect, phy_info.phy_type);
944    if (phy_info.phy_addr < 0) return result;
945
946    if (phy_info.direct_connect == 0)
947        __switch_mdio_mux(ipd_port);
948    switch(phy_info.phy_type)
949    {
950        case BROADCOM_GENERIC_PHY:
951            result = __get_broadcom_phy_link_state(phy_info.phy_addr);
952            break;
953        case MARVELL_GENERIC_PHY:
954            result = __get_marvell_phy_link_state(phy_info.phy_addr);
955            break;
956        default:
957            result = __get_inband_link_state(ipd_port);
958    }
959    return result;
960
961}
962#endif
963
964/**
965 * @INTERNAL
966 * This function invokes  __cvmx_helper_board_link_get_from_dt when device tree
967 * info is available. When the device tree information is not available then
968 * this function is the board specific method of determining an
969 * ethernet ports link speed. Most Octeon boards have Marvell PHYs
970 * and are handled by the fall through case. This function must be
971 * updated for boards that don't have the normal Marvell PHYs.
972 *
973 * This function must be modified for every new Octeon board.
974 * Internally it uses switch statements based on the cvmx_sysinfo
975 * data to determine board types and revisions. It relies on the
976 * fact that every Octeon board receives a unique board type
977 * enumeration from the bootloader.
978 *
979 * @param ipd_port IPD input port associated with the port we want to get link
980 *                 status for.
981 *
982 * @return The ports link status. If the link isn't fully resolved, this must
983 *         return zero.
984 */
985cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
986{
987    cvmx_helper_link_info_t result;
988    int phy_addr;
989    int is_broadcom_phy = 0;
990
991#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
992    if (cvmx_sysinfo_get()->fdt_addr)
993    {
994        return __cvmx_helper_board_link_get_from_dt(ipd_port);
995    }
996#endif
997
998    /* Give the user a chance to override the processing of this function */
999    if (cvmx_override_board_link_get)
1000        return cvmx_override_board_link_get(ipd_port);
1001
1002    /* Unless we fix it later, all links are defaulted to down */
1003    result.u64 = 0;
1004
1005#if !defined(OCTEON_BOARD_CAPK_0100ND)
1006    /* This switch statement should handle all ports that either don't use
1007        Marvell PHYS, or don't support in-band status */
1008    switch (cvmx_sysinfo_get()->board_type)
1009    {
1010        case CVMX_BOARD_TYPE_SIM:
1011            /* The simulator gives you a simulated 1Gbps full duplex link */
1012            result.s.link_up = 1;
1013            result.s.full_duplex = 1;
1014            result.s.speed = 1000;
1015            return result;
1016        case CVMX_BOARD_TYPE_LANAI2_A:
1017        case CVMX_BOARD_TYPE_LANAI2_U:
1018        case CVMX_BOARD_TYPE_LANAI2_G:
1019            break;
1020        case CVMX_BOARD_TYPE_EBH3100:
1021        case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
1022        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
1023#if !defined(OCTEON_VENDOR_GEFES)
1024        case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
1025#endif
1026            /* Port 1 on these boards is always Gigabit */
1027            if (ipd_port == 1)
1028            {
1029                result.s.link_up = 1;
1030                result.s.full_duplex = 1;
1031                result.s.speed = 1000;
1032                return result;
1033            }
1034            /* Fall through to the generic code below */
1035            break;
1036        case CVMX_BOARD_TYPE_EBT5600:
1037        case CVMX_BOARD_TYPE_EBH5600:
1038        case CVMX_BOARD_TYPE_EBH5601:
1039        case CVMX_BOARD_TYPE_EBH5610:
1040            /* Board has 1 management ports */
1041            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
1042                is_broadcom_phy = 1;
1043            break;
1044        case CVMX_BOARD_TYPE_EBH5200:
1045        case CVMX_BOARD_TYPE_EBH5201:
1046        case CVMX_BOARD_TYPE_EBT5200:
1047            /* Board has 2 management ports */
1048            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
1049                is_broadcom_phy = 1;
1050            break;
1051        case CVMX_BOARD_TYPE_EBB6100:
1052        case CVMX_BOARD_TYPE_EBB6300:   /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/
1053        case CVMX_BOARD_TYPE_EBB6600:   /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/
1054            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))
1055                && cvmx_helper_board_get_mii_address(ipd_port) >= 0 && cvmx_helper_board_get_mii_address(ipd_port) <= 1)
1056                is_broadcom_phy = 1;
1057            break;
1058        case CVMX_BOARD_TYPE_EP6300C:
1059            is_broadcom_phy = 1;
1060            break;
1061        case CVMX_BOARD_TYPE_CUST_NB5:
1062            /* Port 1 on these boards is always Gigabit */
1063            if (ipd_port == 1)
1064            {
1065                result.s.link_up = 1;
1066                result.s.full_duplex = 1;
1067                result.s.speed = 1000;
1068                return result;
1069            }
1070            else /* The other port uses a broadcom PHY */
1071                is_broadcom_phy = 1;
1072            break;
1073        case CVMX_BOARD_TYPE_BBGW_REF:
1074            /* Port 1 on these boards is always Gigabit */
1075            if (ipd_port == 2)
1076            {
1077                /* Port 2 is not hooked up */
1078                result.u64 = 0;
1079                return result;
1080            }
1081            else
1082            {
1083                /* Ports 0 and 1 connect to the switch */
1084                result.s.link_up = 1;
1085                result.s.full_duplex = 1;
1086                result.s.speed = 1000;
1087                return result;
1088            }
1089        case CVMX_BOARD_TYPE_NIC4E:
1090        case CVMX_BOARD_TYPE_NIC2E:
1091            is_broadcom_phy = 1;
1092            break;
1093	/* Private vendor-defined boards.  */
1094#if defined(OCTEON_VENDOR_LANNER)
1095	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
1096	    /* Ports are BCM5482S */
1097	    is_broadcom_phy = 1;
1098	    break;
1099	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
1100	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
1101	    /* Port 0 connects to the switch */
1102	    if (ipd_port == 0)
1103	    {
1104                result.s.link_up = 1;
1105                result.s.full_duplex = 1;
1106                result.s.speed = 1000;
1107		return result;
1108	    }
1109	    break;
1110#endif
1111#if defined(OCTEON_VENDOR_GEFES)
1112	case CVMX_BOARD_TYPE_CUST_TNPA5651X:
1113	   /* Since we don't auto-negotiate... 1Gbps full duplex link */
1114	   result.s.link_up = 1;
1115	   result.s.full_duplex = 1;
1116	   result.s.speed = 1000;
1117	   return result;
1118	   break;
1119#endif
1120    }
1121#endif
1122
1123    phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
1124    //cvmx_dprintf("ipd_port=%d phy_addr=%d broadcom=%d\n",
1125    //             ipd_port, phy_addr, is_broadcom_phy);
1126    if (phy_addr != -1)
1127    {
1128        if (is_broadcom_phy)
1129        {
1130            result =  __get_broadcom_phy_link_state(phy_addr);
1131        }
1132        else
1133        {
1134            /* This code assumes we are using a Marvell Gigabit PHY. */
1135            result = __get_marvell_phy_link_state(phy_addr);
1136        }
1137    }
1138    else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX)
1139             || OCTEON_IS_MODEL(OCTEON_CN50XX))
1140    {
1141        /* We don't have a PHY address, so attempt to use in-band status. It is
1142            really important that boards not supporting in-band status never get
1143            here. Reading broken in-band status tends to do bad things */
1144        result = __get_inband_link_state(ipd_port);
1145    }
1146#if defined(OCTEON_VENDOR_GEFES)
1147    else if( (OCTEON_IS_MODEL(OCTEON_CN56XX)) || (OCTEON_IS_MODEL(OCTEON_CN63XX)) )
1148    {
1149        int interface = cvmx_helper_get_interface_num(ipd_port);
1150        int index = cvmx_helper_get_interface_index_num(ipd_port);
1151        cvmx_pcsx_miscx_ctl_reg_t mode_type;
1152        cvmx_pcsx_mrx_status_reg_t mrx_status;
1153        cvmx_pcsx_anx_adv_reg_t anxx_adv;
1154        cvmx_pcsx_sgmx_lp_adv_reg_t sgmii_inband_status;
1155
1156        anxx_adv.u64 = cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface));
1157        mrx_status.u64 = cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG(index, interface));
1158
1159        mode_type.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
1160
1161        /* Read Octeon's inband status */
1162        sgmii_inband_status.u64 = cvmx_read_csr(CVMX_PCSX_SGMX_LP_ADV_REG(index, interface));
1163
1164        result.s.link_up = sgmii_inband_status.s.link;
1165        result.s.full_duplex = sgmii_inband_status.s.dup;
1166        switch (sgmii_inband_status.s.speed)
1167        {
1168        case 0: /* 10 Mbps */
1169            result.s.speed = 10;
1170            break;
1171        case 1: /* 100 Mbps */
1172            result.s.speed = 100;
1173            break;
1174        case 2: /* 1 Gbps */
1175            result.s.speed = 1000;
1176            break;
1177        case 3: /* Illegal */
1178            result.s.speed = 0;
1179            result.s.link_up = 0;
1180            break;
1181        }
1182    }
1183#endif
1184    else
1185    {
1186        /* We don't have a PHY address and we don't have in-band status. There
1187            is no way to determine the link speed. Return down assuming this
1188            port isn't wired */
1189        result.u64 = 0;
1190    }
1191
1192    /* If link is down, return all fields as zero. */
1193    if (!result.s.link_up)
1194        result.u64 = 0;
1195
1196    return result;
1197}
1198
1199
1200/**
1201 * This function as a board specific method of changing the PHY
1202 * speed, duplex, and autonegotiation. This programs the PHY and
1203 * not Octeon. This can be used to force Octeon's links to
1204 * specific settings.
1205 *
1206 * @param phy_addr  The address of the PHY to program
1207 * @param link_flags
1208 *                  Flags to control autonegotiation.  Bit 0 is autonegotiation
1209 *                  enable/disable to maintain backward compatibility.
1210 * @param link_info Link speed to program. If the speed is zero and autonegotiation
1211 *                  is enabled, all possible negotiation speeds are advertised.
1212 *
1213 * @return Zero on success, negative on failure
1214 */
1215int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags,
1216                                   cvmx_helper_link_info_t link_info)
1217{
1218
1219    /* Set the flow control settings based on link_flags */
1220    if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch)
1221    {
1222        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1223        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1224        reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
1225        reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
1226        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1227    }
1228
1229    /* If speed isn't set and autoneg is on advertise all supported modes */
1230    if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0))
1231    {
1232        cvmx_mdio_phy_reg_control_t reg_control;
1233        cvmx_mdio_phy_reg_status_t reg_status;
1234        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1235        cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
1236        cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
1237
1238        reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
1239        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1240        reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4;
1241        reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full;
1242        reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half;
1243        reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full;
1244        reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half;
1245        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1246        if (reg_status.s.capable_extended_status)
1247        {
1248            reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
1249            reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
1250            reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full;
1251            reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half;
1252            cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
1253        }
1254        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1255        reg_control.s.autoneg_enable = 1;
1256        reg_control.s.restart_autoneg = 1;
1257        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1258    }
1259    else if ((link_flags & set_phy_link_flags_autoneg))
1260    {
1261        cvmx_mdio_phy_reg_control_t reg_control;
1262        cvmx_mdio_phy_reg_status_t reg_status;
1263        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1264        cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
1265
1266        reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
1267        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1268        reg_autoneg_adver.s.advert_100base_t4 = 0;
1269        reg_autoneg_adver.s.advert_10base_tx_full = 0;
1270        reg_autoneg_adver.s.advert_10base_tx_half = 0;
1271        reg_autoneg_adver.s.advert_100base_tx_full = 0;
1272        reg_autoneg_adver.s.advert_100base_tx_half = 0;
1273        if (reg_status.s.capable_extended_status)
1274        {
1275            reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
1276            reg_control_1000.s.advert_1000base_t_full = 0;
1277            reg_control_1000.s.advert_1000base_t_half = 0;
1278        }
1279        switch (link_info.s.speed)
1280        {
1281            case 10:
1282                reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex;
1283                reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex;
1284                break;
1285            case 100:
1286                reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex;
1287                reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex;
1288                break;
1289            case 1000:
1290                reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex;
1291                reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex;
1292                break;
1293        }
1294        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1295        if (reg_status.s.capable_extended_status)
1296            cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
1297        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1298        reg_control.s.autoneg_enable = 1;
1299        reg_control.s.restart_autoneg = 1;
1300        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1301    }
1302    else
1303    {
1304        cvmx_mdio_phy_reg_control_t reg_control;
1305        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1306        reg_control.s.autoneg_enable = 0;
1307        reg_control.s.restart_autoneg = 1;
1308        reg_control.s.duplex = link_info.s.full_duplex;
1309        if (link_info.s.speed == 1000)
1310        {
1311            reg_control.s.speed_msb = 1;
1312            reg_control.s.speed_lsb = 0;
1313        }
1314        else if (link_info.s.speed == 100)
1315        {
1316            reg_control.s.speed_msb = 0;
1317            reg_control.s.speed_lsb = 1;
1318        }
1319        else if (link_info.s.speed == 10)
1320        {
1321            reg_control.s.speed_msb = 0;
1322            reg_control.s.speed_lsb = 0;
1323        }
1324        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1325    }
1326    return 0;
1327}
1328
1329
1330/**
1331 * @INTERNAL
1332 * This function is called by cvmx_helper_interface_probe() after it
1333 * determines the number of ports Octeon can support on a specific
1334 * interface. This function is the per board location to override
1335 * this value. It is called with the number of ports Octeon might
1336 * support and should return the number of actual ports on the
1337 * board.
1338 *
1339 * This function must be modified for every new Octeon board.
1340 * Internally it uses switch statements based on the cvmx_sysinfo
1341 * data to determine board types and revisions. It relies on the
1342 * fact that every Octeon board receives a unique board type
1343 * enumeration from the bootloader.
1344 *
1345 * @param interface Interface to probe
1346 * @param supported_ports
1347 *                  Number of ports Octeon supports.
1348 *
1349 * @return Number of ports the actual board supports. Many times this will
1350 *         simple be "support_ports".
1351 */
1352int __cvmx_helper_board_interface_probe(int interface, int supported_ports)
1353{
1354    switch (cvmx_sysinfo_get()->board_type)
1355    {
1356        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
1357        case CVMX_BOARD_TYPE_LANAI2_A:
1358        case CVMX_BOARD_TYPE_LANAI2_U:
1359        case CVMX_BOARD_TYPE_LANAI2_G:
1360            if (interface == 0)
1361                return 2;
1362	    break;
1363        case CVMX_BOARD_TYPE_BBGW_REF:
1364            if (interface == 0)
1365                return 2;
1366	    break;
1367        case CVMX_BOARD_TYPE_NIC_XLE_4G:
1368            if (interface == 0)
1369                return 0;
1370	    break;
1371        /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
1372            which we don't support. Disable ports connected to it */
1373        case CVMX_BOARD_TYPE_EBH5600:
1374            if (interface == 1)
1375                return 0;
1376	    break;
1377        case CVMX_BOARD_TYPE_EBB5600:
1378#ifdef CVMX_ENABLE_PKO_FUNCTIONS
1379            if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_PICMG)
1380                return 0;
1381#endif
1382	    break;
1383        case CVMX_BOARD_TYPE_EBT5600:
1384	    /* Disable loopback.  */
1385	    if (interface == 3)
1386		return 0;
1387	    break;
1388        case CVMX_BOARD_TYPE_EBT5810:
1389            return 1;  /* Two ports on each SPI: 1 hooked to MAC, 1 loopback
1390                       ** Loopback disabled by default. */
1391        case CVMX_BOARD_TYPE_NIC2E:
1392            if (interface == 0)
1393                return 2;
1394#if defined(OCTEON_VENDOR_LANNER)
1395	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
1396	    if (interface == 1)
1397	        return 12;
1398	    break;
1399#endif
1400#if defined(OCTEON_VENDOR_GEFES)
1401        case CVMX_BOARD_TYPE_CUST_TNPA5651X:
1402                if (interface < 2) /* interface can be EITHER 0 or 1 */
1403			return 1;//always return 1 for XAUI and SGMII mode.
1404		break;
1405        case CVMX_BOARD_TYPE_CUST_TNPA56X4:
1406		if ((interface == 0) &&
1407			(cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_SGMII))
1408		{
1409			cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
1410
1411			/* For this port we need to set the mode to 1000BaseX */
1412			pcsx_miscx_ctl_reg.u64 =
1413				cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(0, interface));
1414			pcsx_miscx_ctl_reg.cn56xx.mode = 1;
1415			cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(0, interface),
1416						   pcsx_miscx_ctl_reg.u64);
1417			pcsx_miscx_ctl_reg.u64 =
1418				cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(1, interface));
1419			pcsx_miscx_ctl_reg.cn56xx.mode = 1;
1420			cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(1, interface),
1421						   pcsx_miscx_ctl_reg.u64);
1422
1423			return 2;
1424		}
1425		break;
1426#endif
1427    }
1428#ifdef CVMX_BUILD_FOR_UBOOT
1429    if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi"))
1430        return 0;
1431#endif
1432    return supported_ports;
1433}
1434
1435
1436/**
1437 * @INTERNAL
1438 * Enable packet input/output from the hardware. This function is
1439 * called after by cvmx_helper_packet_hardware_enable() to
1440 * perform board specific initialization. For most boards
1441 * nothing is needed.
1442 *
1443 * @param interface Interface to enable
1444 *
1445 * @return Zero on success, negative on failure
1446 */
1447int __cvmx_helper_board_hardware_enable(int interface)
1448{
1449    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5)
1450    {
1451        if (interface == 0)
1452        {
1453            /* Different config for switch port */
1454            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
1455            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
1456            /* Boards with gigabit WAN ports need a different setting that is
1457                compatible with 100 Mbit settings */
1458            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc);
1459            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc);
1460        }
1461    }
1462    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_LANAI2_U)
1463    {
1464        if (interface == 0)
1465        {
1466            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 16);
1467            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 16);
1468        }
1469    }
1470    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5)
1471    {
1472        /* Broadcom PHYs require different ASX clocks. Unfortunately
1473            many customer don't define a new board Id and simply
1474            mangle the CN3010_EVB_HS5 */
1475        if (interface == 0)
1476        {
1477            /* Some customers boards use a hacked up bootloader that identifies them as
1478            ** CN3010_EVB_HS5 evaluation boards.  This leads to all kinds of configuration
1479            ** problems.  Detect one case, and print warning, while trying to do the right thing.
1480            */
1481            int phy_addr = cvmx_helper_board_get_mii_address(0);
1482            if (phy_addr != -1)
1483            {
1484                int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2);
1485                /* Is it a Broadcom PHY? */
1486                if (phy_identifier == 0x0143)
1487                {
1488                    cvmx_dprintf("\n");
1489                    cvmx_dprintf("ERROR:\n");
1490                    cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
1491                    cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
1492                    cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n");
1493                    cvmx_dprintf("ERROR:\n");
1494                    cvmx_dprintf("\n");
1495                    cvmx_wait(1000000000);
1496                    cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5);
1497                    cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5);
1498                }
1499            }
1500        }
1501    }
1502#if defined(OCTEON_VENDOR_UBIQUITI)
1503    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_UBIQUITI_E100 ||
1504        cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_UBIQUITI_USG)
1505    {
1506	/* Configure ASX cloks for all ports on interface 0.  */
1507	if (interface == 0)
1508	{
1509	    int port;
1510
1511	    for (port = 0; port < 3; port++) {
1512                cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 16);
1513                cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 0);
1514	    }
1515	}
1516    }
1517#endif
1518    return 0;
1519}
1520
1521
1522/**
1523 * @INTERNAL
1524 * Gets the clock type used for the USB block based on board type.
1525 * Used by the USB code for auto configuration of clock type.
1526 *
1527 * @return USB clock type enumeration
1528 */
1529cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void)
1530{
1531#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
1532    const void *fdt_addr = CASTPTR(const void *, cvmx_sysinfo_get()->fdt_addr);
1533    int nodeoffset;
1534    const void *nodep;
1535    int len;
1536    uint32_t speed = 0;
1537    const char *type = NULL;
1538
1539    if (fdt_addr)
1540    {
1541        nodeoffset = fdt_path_offset(fdt_addr, "/soc/uctl");
1542        if (nodeoffset < 0)
1543            nodeoffset = fdt_path_offset(fdt_addr, "/soc/usbn");
1544
1545        if (nodeoffset >= 0)
1546        {
1547            nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-type", &len);
1548            if (nodep != NULL && len > 0)
1549                type = (const char *)nodep;
1550            else
1551                type = "unknown";
1552            nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-frequency", &len);
1553            if (nodep != NULL && len == sizeof(uint32_t))
1554                speed = fdt32_to_cpu(*(int *)nodep);
1555            else
1556                speed = 0;
1557            if (!strcmp(type, "crystal"))
1558            {
1559                if (speed == 0 || speed == 12000000)
1560                    return USB_CLOCK_TYPE_CRYSTAL_12;
1561                else
1562                    printf("Warning: invalid crystal speed for USB clock type in FDT\n");
1563            }
1564            else if (!strcmp(type, "external"))
1565            {
1566                switch (speed) {
1567                case 12000000:
1568                    return USB_CLOCK_TYPE_REF_12;
1569                case 24000000:
1570                    return USB_CLOCK_TYPE_REF_24;
1571                case 0:
1572                case 48000000:
1573                    return USB_CLOCK_TYPE_REF_48;
1574                default:
1575                    printf("Warning: invalid USB clock speed of %u hz in FDT\n", speed);
1576                }
1577            }
1578            else
1579                printf("Warning: invalid USB reference clock type \"%s\" in FDT\n", type ? type : "NULL");
1580        }
1581    }
1582#endif
1583    switch (cvmx_sysinfo_get()->board_type)
1584    {
1585        case CVMX_BOARD_TYPE_BBGW_REF:
1586        case CVMX_BOARD_TYPE_LANAI2_A:
1587        case CVMX_BOARD_TYPE_LANAI2_U:
1588        case CVMX_BOARD_TYPE_LANAI2_G:
1589#if defined(OCTEON_VENDOR_LANNER)
1590        case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
1591        case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
1592#endif
1593#if defined(OCTEON_VENDOR_UBIQUITI)
1594        case CVMX_BOARD_TYPE_CUST_UBIQUITI_E100:
1595        case CVMX_BOARD_TYPE_CUST_UBIQUITI_USG:
1596#endif
1597#if defined(OCTEON_BOARD_CAPK_0100ND)
1598	case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
1599#endif
1600#if defined(OCTEON_VENDOR_GEFES) /* All GEFES' boards use same xtal type */
1601        case CVMX_BOARD_TYPE_TNPA3804:
1602        case CVMX_BOARD_TYPE_AT5810:
1603        case CVMX_BOARD_TYPE_WNPA3850:
1604        case CVMX_BOARD_TYPE_W3860:
1605        case CVMX_BOARD_TYPE_CUST_TNPA5804:
1606        case CVMX_BOARD_TYPE_CUST_W5434:
1607        case CVMX_BOARD_TYPE_CUST_W5650:
1608        case CVMX_BOARD_TYPE_CUST_W5800:
1609        case CVMX_BOARD_TYPE_CUST_W5651X:
1610        case CVMX_BOARD_TYPE_CUST_TNPA5651X:
1611        case CVMX_BOARD_TYPE_CUST_TNPA56X4:
1612        case CVMX_BOARD_TYPE_CUST_W63XX:
1613#endif
1614        case CVMX_BOARD_TYPE_NIC10E_66:
1615            return USB_CLOCK_TYPE_CRYSTAL_12;
1616        case CVMX_BOARD_TYPE_NIC10E:
1617            return USB_CLOCK_TYPE_REF_12;
1618        default:
1619            break;
1620    }
1621    if (OCTEON_IS_MODEL(OCTEON_CN6XXX)	/* Most boards except NIC10e use a 12MHz crystal */
1622        || OCTEON_IS_MODEL(OCTEON_CNF7XXX))
1623        return USB_CLOCK_TYPE_CRYSTAL_12;
1624    return USB_CLOCK_TYPE_REF_48;
1625}
1626
1627
1628/**
1629 * @INTERNAL
1630 * Adjusts the number of available USB ports on Octeon based on board
1631 * specifics.
1632 *
1633 * @param supported_ports expected number of ports based on chip type;
1634 *
1635 *
1636 * @return number of available usb ports, based on board specifics.
1637 *         Return value is supported_ports if function does not
1638 *         override.
1639 */
1640int __cvmx_helper_board_usb_get_num_ports(int supported_ports)
1641{
1642    switch (cvmx_sysinfo_get()->board_type)
1643    {
1644        case CVMX_BOARD_TYPE_NIC_XLE_4G:
1645        case CVMX_BOARD_TYPE_NIC2E:
1646            return 0;
1647    }
1648
1649    return supported_ports;
1650}
1651
1652
1653