cvmx-helper-board.c revision 244984
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        case CVMX_BOARD_TYPE_EBT3000:
389        case CVMX_BOARD_TYPE_EBT5800:
390        case CVMX_BOARD_TYPE_THUNDER:
391        case CVMX_BOARD_TYPE_NICPRO2:
392            /* Interface 0 is SPI4, interface 1 is RGMII */
393            if ((ipd_port >= 16) && (ipd_port < 20))
394                return ipd_port - 16;
395            else
396                return -1;
397        case CVMX_BOARD_TYPE_LANAI2_A:
398            if (ipd_port == 0)
399                return 0;
400            else
401                return -1;
402        case CVMX_BOARD_TYPE_LANAI2_U:
403        case CVMX_BOARD_TYPE_LANAI2_G:
404            if (ipd_port == 0)
405                return 0x1c;
406            else
407                return -1;
408        case CVMX_BOARD_TYPE_KODAMA:
409        case CVMX_BOARD_TYPE_EBH3100:
410        case CVMX_BOARD_TYPE_HIKARI:
411        case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
412        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
413        case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
414            /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a
415                switch */
416            if (ipd_port == 0)
417                return 4;
418            else if (ipd_port == 1)
419                return 9;
420            else
421                return -1;
422        case CVMX_BOARD_TYPE_EBH3000:
423            /* Board has dual SPI4 and no PHYs */
424            return -1;
425        case CVMX_BOARD_TYPE_EBT5810:
426            /* Board has 10g PHYs hooked up to the MII controller on the
427            ** IXF18201 MAC.  The 10G PHYS use clause 45 MDIO which the CN58XX
428            ** does not support. All MII accesses go through the IXF part. */
429            return -1;
430        case CVMX_BOARD_TYPE_EBH5200:
431        case CVMX_BOARD_TYPE_EBH5201:
432        case CVMX_BOARD_TYPE_EBT5200:
433            /* Board has 2 management ports */
434            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
435                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
436            /* Board has 4 SGMII ports. The PHYs start right after the MII
437                ports MII0 = 0, MII1 = 1, SGMII = 2-5 */
438            if ((ipd_port >= 0) && (ipd_port < 4))
439                return ipd_port+2;
440            else
441                return -1;
442        case CVMX_BOARD_TYPE_EBH5600:
443        case CVMX_BOARD_TYPE_EBH5601:
444        case CVMX_BOARD_TYPE_EBH5610:
445            /* Board has 1 management port */
446            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
447                return 0;
448            /* Board has 8 SGMII ports. 4 connect out, two connect to a switch,
449                and 2 loop to each other */
450            if ((ipd_port >= 0) && (ipd_port < 4))
451                return ipd_port+1;
452            else
453                return -1;
454        case CVMX_BOARD_TYPE_EBT5600:
455	    /* Board has 1 management port */
456            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
457                return 0;
458	    /* Board has 1 XAUI port connected to a switch.  */
459	    return -1;
460        case CVMX_BOARD_TYPE_EBB5600:
461            {
462                static unsigned char qlm_switch_addr = 0;
463
464                /* Board has 1 management port */
465                if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
466                    return 0;
467
468                /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */
469                if ((ipd_port >= 0) && (ipd_port < 4))
470                {
471                    if (qlm_switch_addr != 0x3)
472                    {
473                        qlm_switch_addr = 0x3;  /* QLM1 */
474                        cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
475                        cvmx_wait_usec(11000); /* Let the write complete */
476                    }
477                    return ipd_port+1 + (1<<8);
478                }
479                else if ((ipd_port >= 16) && (ipd_port < 20))
480                {
481                    if (qlm_switch_addr != 0xC)
482                    {
483                        qlm_switch_addr = 0xC;  /* QLM3 */
484                        cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
485                        cvmx_wait_usec(11000); /* Let the write complete */
486                    }
487                    return ipd_port-16+1 + (1<<8);
488                }
489                else
490                    return -1;
491            }
492        case CVMX_BOARD_TYPE_EBB6300:
493            /* Board has 2 management ports */
494            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
495                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
496            if ((ipd_port >= 0) && (ipd_port < 4))
497                return ipd_port + 1 + (1<<8);
498            else
499                return -1;
500        case CVMX_BOARD_TYPE_EBB6800:
501            /* Board has 1 management ports */
502            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
503                return 6;
504            if (ipd_port >= 0x800 && ipd_port < 0x900) /* QLM 0*/
505                return 0x101 + ((ipd_port >> 4) & 3); /* SMI 1*/
506            if (ipd_port >= 0xa00 && ipd_port < 0xb00) /* QLM 2*/
507                return 0x201 + ((ipd_port >> 4) & 3); /* SMI 2*/
508            if (ipd_port >= 0xb00 && ipd_port < 0xc00) /* QLM 3*/
509                return 0x301 + ((ipd_port >> 4) & 3); /* SMI 3*/
510            if (ipd_port >= 0xc00 && ipd_port < 0xd00) /* QLM 4*/
511                return 0x001 + ((ipd_port >> 4) & 3); /* SMI 0*/
512            return -1;
513        case CVMX_BOARD_TYPE_EP6300C:
514            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
515                return 0x01;
516            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT+1)
517                return 0x02;
518#ifdef CVMX_ENABLE_PKO_FUNCTIONS
519            {
520                int interface = cvmx_helper_get_interface_num(ipd_port);
521                int mode = cvmx_helper_interface_get_mode(interface);
522                if (mode == CVMX_HELPER_INTERFACE_MODE_XAUI)
523                    return ipd_port;
524                else if ((ipd_port >= 0) && (ipd_port < 4))
525                    return ipd_port + 3;
526                else
527                    return -1;
528            }
529#endif
530            break;
531        case CVMX_BOARD_TYPE_CUST_NB5:
532            if (ipd_port == 2)
533                return 4;
534            else
535                return -1;
536        case CVMX_BOARD_TYPE_NIC_XLE_4G:
537            /* Board has 4 SGMII ports. connected QLM3(interface 1) */
538            if ((ipd_port >= 16) && (ipd_port < 20))
539                return ipd_port - 16 + 1;
540            else
541                return -1;
542        case CVMX_BOARD_TYPE_NIC_XLE_10G:
543        case CVMX_BOARD_TYPE_NIC10E:
544            return -1;  /* We don't use clause 45 MDIO for anything */
545        case CVMX_BOARD_TYPE_NIC4E:
546            if (ipd_port >= 0 && ipd_port <= 3)
547                return (ipd_port + 0x1f) & 0x1f;
548            else
549                return -1;
550        case CVMX_BOARD_TYPE_NIC2E:
551            if (ipd_port >= 0 && ipd_port <= 1)
552                return (ipd_port + 1);
553            else
554                return -1;
555        case CVMX_BOARD_TYPE_REDWING:
556	    return -1;  /* No PHYs connected to Octeon */
557        case CVMX_BOARD_TYPE_BBGW_REF:
558            return -1;  /* No PHYs are connected to Octeon, everything is through switch */
559	case CVMX_BOARD_TYPE_CUST_WSX16:
560		if (ipd_port >= 0 && ipd_port <= 3)
561			return ipd_port;
562		else if (ipd_port >= 16 && ipd_port <= 19)
563			return ipd_port - 16 + 4;
564		else
565			return -1;
566
567	/* Private vendor-defined boards.  */
568#if defined(OCTEON_VENDOR_LANNER)
569	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
570	    /* Interface 1 is 12 BCM5482S PHYs.  */
571            if ((ipd_port >= 16) && (ipd_port < 28))
572                return ipd_port - 16;
573	    return -1;
574	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
575            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
576		return (ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT) + 0x81;
577            if ((ipd_port >= 0) && (ipd_port < 4))
578                return ipd_port;
579	    return -1;
580	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
581	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
582	    /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell
583	       88E1111 interfaces.  */
584	    switch (ipd_port) {
585	    case 0:
586		return 16;
587	    case 1:
588		return 1;
589	    case 2:
590		return 2;
591	    default:
592		return -1;
593	    }
594#endif
595#if defined(OCTEON_VENDOR_UBIQUITI)
596	case CVMX_BOARD_TYPE_CUST_UBIQUITI_E100:
597	    if (ipd_port > 2)
598		return -1;
599	    return (7 - ipd_port);
600#endif
601#if defined(OCTEON_VENDOR_RADISYS)
602	case CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE:
603	    /* No MII.  */
604	    return -1;
605#endif
606    }
607
608    /* Some unknown board. Somebody forgot to update this function... */
609    cvmx_dprintf("%s: Unknown board type %d\n",
610                 __FUNCTION__, cvmx_sysinfo_get()->board_type);
611    return -1;
612}
613#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
614EXPORT_SYMBOL(cvmx_helper_board_get_mii_address);
615#endif
616
617/**
618 * @INTERNAL
619 * Get link state of marvell PHY
620 */
621static cvmx_helper_link_info_t __get_marvell_phy_link_state(int phy_addr)
622{
623    cvmx_helper_link_info_t  result;
624    int phy_status;
625
626    result.u64 = 0;
627    /*All the speed information can be read from register 17 in one go.*/
628    phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
629
630    /* If the resolve bit 11 isn't set, see if autoneg is turned off
631       (bit 12, reg 0). The resolve bit doesn't get set properly when
632       autoneg is off, so force it */
633    if ((phy_status & (1<<11)) == 0)
634    {
635        int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
636        if ((auto_status & (1<<12)) == 0)
637            phy_status |= 1<<11;
638    }
639
640    /* Only return a link if the PHY has finished auto negotiation
641       and set the resolved bit (bit 11) */
642    if (phy_status & (1<<11))
643    {
644        result.s.link_up = 1;
645        result.s.full_duplex = ((phy_status>>13)&1);
646        switch ((phy_status>>14)&3)
647        {
648            case 0: /* 10 Mbps */
649                result.s.speed = 10;
650                break;
651            case 1: /* 100 Mbps */
652                result.s.speed = 100;
653                break;
654            case 2: /* 1 Gbps */
655                result.s.speed = 1000;
656                break;
657            case 3: /* Illegal */
658                result.u64 = 0;
659                break;
660        }
661    }
662    return result;
663}
664
665/**
666 * @INTERNAL
667 * Get link state of broadcom PHY
668 */
669static cvmx_helper_link_info_t __get_broadcom_phy_link_state(int phy_addr)
670{
671    cvmx_helper_link_info_t  result;
672    int phy_status;
673
674    result.u64 = 0;
675    /* Below we are going to read SMI/MDIO register 0x19 which works
676       on Broadcom parts */
677    phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19);
678    switch ((phy_status>>8) & 0x7)
679    {
680        case 0:
681            result.u64 = 0;
682            break;
683        case 1:
684            result.s.link_up = 1;
685            result.s.full_duplex = 0;
686            result.s.speed = 10;
687            break;
688        case 2:
689            result.s.link_up = 1;
690            result.s.full_duplex = 1;
691            result.s.speed = 10;
692            break;
693        case 3:
694            result.s.link_up = 1;
695            result.s.full_duplex = 0;
696            result.s.speed = 100;
697            break;
698        case 4:
699            result.s.link_up = 1;
700            result.s.full_duplex = 1;
701            result.s.speed = 100;
702            break;
703        case 5:
704            result.s.link_up = 1;
705            result.s.full_duplex = 1;
706            result.s.speed = 100;
707            break;
708        case 6:
709            result.s.link_up = 1;
710            result.s.full_duplex = 0;
711            result.s.speed = 1000;
712            break;
713        case 7:
714            result.s.link_up = 1;
715            result.s.full_duplex = 1;
716            result.s.speed = 1000;
717            break;
718    }
719    return result;
720}
721
722
723/**
724 * @INTERNAL
725 * Get link state using inband status
726 */
727static cvmx_helper_link_info_t __get_inband_link_state(int ipd_port)
728{
729    cvmx_helper_link_info_t  result;
730    cvmx_gmxx_rxx_rx_inbnd_t inband_status;
731    int interface = cvmx_helper_get_interface_num(ipd_port);
732    int index = cvmx_helper_get_interface_index_num(ipd_port);
733
734    result.u64 = 0;
735    inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
736    result.s.link_up = inband_status.s.status;
737    result.s.full_duplex = inband_status.s.duplex;
738    switch (inband_status.s.speed)
739    {
740        case 0: /* 10 Mbps */
741            result.s.speed = 10;
742            break;
743        case 1: /* 100 Mbps */
744            result.s.speed = 100;
745            break;
746        case 2: /* 1 Gbps */
747            result.s.speed = 1000;
748            break;
749        case 3: /* Illegal */
750            result.u64 = 0;
751            break;
752    }
753    return result;
754}
755
756#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
757/**
758 * @INTERNAL
759 * Switch MDIO mux to the specified port.
760 */
761static int __switch_mdio_mux(int ipd_port)
762{
763    /* This method is board specific and doesn't use the device tree
764       information as SE doesn't implement MDIO MUX abstration */
765    switch (cvmx_sysinfo_get()->board_type)
766    {
767        case CVMX_BOARD_TYPE_EBB5600:
768        {
769            static unsigned char qlm_switch_addr = 0;
770            /* Board has 1 management port */
771            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
772                return 0;
773            /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */
774            if ((ipd_port >= 0) && (ipd_port < 4))
775            {
776                if (qlm_switch_addr != 0x3)
777                {
778                    qlm_switch_addr = 0x3;  /* QLM1 */
779                    cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
780                    cvmx_wait_usec(11000); /* Let the write complete */
781                }
782                return ipd_port+1 + (1<<8);
783            }
784            else if ((ipd_port >= 16) && (ipd_port < 20))
785            {
786                if (qlm_switch_addr != 0xC)
787                {
788                    qlm_switch_addr = 0xC;  /* QLM3 */
789                    cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
790                    cvmx_wait_usec(11000); /* Let the write complete */
791                }
792                return ipd_port-16+1 + (1<<8);
793            }
794            else
795                return -1;
796        }
797        case CVMX_BOARD_TYPE_EBB6600:
798        {
799            static unsigned char qlm_switch_addr = 0;
800            int old_twsi_switch_reg;
801            /* Board has 2 management ports */
802            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) &&
803                (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
804                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
805            if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */
806            {
807                if (qlm_switch_addr != 2)
808                {
809                    int tries;
810                    qlm_switch_addr = 2;
811                    tries = 3;
812                    do {
813                        old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0);
814                    } while (tries-- > 0 && old_twsi_switch_reg < 0);
815                    /* Set I2C MUX to enable port expander */
816                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8);
817                    /* Set selecter to QLM 1 */
818                    cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xff);
819                    /* disable port expander */
820                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg);
821                }
822                return 0x101 + ipd_port;
823            }
824            else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 1 */
825            {
826                if (qlm_switch_addr != 1)
827                {
828                    int tries;
829                    qlm_switch_addr = 1;
830                    tries = 3;
831                    do {
832                            old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0);
833                    } while (tries-- > 0 && old_twsi_switch_reg < 0);
834                    /* Set I2C MUX to enable port expander */
835                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8);
836                    /* Set selecter to QLM 2 */
837                    cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xf7);
838                    /* disable port expander */
839                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg);
840                }
841                return 0x101 + (ipd_port - 16);
842            } else
843                return -1;
844        }
845        case CVMX_BOARD_TYPE_EBB6100:
846        {
847            static char gpio_configured = 0;
848
849            if (!gpio_configured)
850            {
851                cvmx_gpio_cfg(3, 1);
852                gpio_configured = 1;
853            }
854            /* Board has 2 management ports */
855            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) &&
856                (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
857                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
858            if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */
859            {
860                cvmx_gpio_set(1ull << 3);
861                return 0x101 + ipd_port;
862            }
863            else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 0 */
864            {
865                cvmx_gpio_clear(1ull << 3);
866                return 0x101 + (ipd_port - 16);
867            }
868            else
869            {
870                printf("%s: Unknown ipd port 0x%x\n", __func__, ipd_port);
871                return -1;
872            }
873        }
874        default:
875        {
876            cvmx_dprintf("ERROR : unexpected mdio switch for board=%08x\n",
877                         cvmx_sysinfo_get()->board_type);
878            return -1;
879        }
880    }
881    /* should never get here */
882    return -1;
883}
884
885/**
886 * @INTERNAL
887 * This function is used ethernet ports link speed. This functions uses the
888 * device tree information to determine the phy address and type of PHY.
889 * The only supproted PHYs are Marvell and Broadcom.
890 *
891 * @param ipd_port IPD input port associated with the port we want to get link
892 *                 status for.
893 *
894 * @return The ports link status. If the link isn't fully resolved, this must
895 *         return zero.
896 */
897
898cvmx_helper_link_info_t __cvmx_helper_board_link_get_from_dt(int ipd_port)
899{
900    cvmx_helper_link_info_t  result;
901    cvmx_phy_info_t phy_info;
902
903    result.u64 = 0;
904    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
905    {
906        /* The simulator gives you a simulated 1Gbps full duplex link */
907        result.s.link_up = 1;
908        result.s.full_duplex = 1;
909        result.s.speed = 1000;
910        return result;
911    }
912    phy_info = __get_phy_info_from_dt(ipd_port);
913    //cvmx_dprintf("ipd_port=%d phy_addr=%d dc=%d type=%d \n", ipd_port,
914    //             phy_info.phy_addr, phy_info.direct_connect, phy_info.phy_type);
915    if (phy_info.phy_addr < 0) return result;
916
917    if (phy_info.direct_connect == 0)
918        __switch_mdio_mux(ipd_port);
919    switch(phy_info.phy_type)
920    {
921        case BROADCOM_GENERIC_PHY:
922            result = __get_broadcom_phy_link_state(phy_info.phy_addr);
923            break;
924        case MARVELL_GENERIC_PHY:
925            result = __get_marvell_phy_link_state(phy_info.phy_addr);
926            break;
927        default:
928            result = __get_inband_link_state(ipd_port);
929    }
930    return result;
931
932}
933#endif
934
935/**
936 * @INTERNAL
937 * This function invokes  __cvmx_helper_board_link_get_from_dt when device tree
938 * info is available. When the device tree information is not available then
939 * this function is the board specific method of determining an
940 * ethernet ports link speed. Most Octeon boards have Marvell PHYs
941 * and are handled by the fall through case. This function must be
942 * updated for boards that don't have the normal Marvell PHYs.
943 *
944 * This function must be modified for every new Octeon board.
945 * Internally it uses switch statements based on the cvmx_sysinfo
946 * data to determine board types and revisions. It relies on the
947 * fact that every Octeon board receives a unique board type
948 * enumeration from the bootloader.
949 *
950 * @param ipd_port IPD input port associated with the port we want to get link
951 *                 status for.
952 *
953 * @return The ports link status. If the link isn't fully resolved, this must
954 *         return zero.
955 */
956cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
957{
958    cvmx_helper_link_info_t result;
959    int phy_addr;
960    int is_broadcom_phy = 0;
961
962#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
963    if (cvmx_sysinfo_get()->fdt_addr)
964    {
965        return __cvmx_helper_board_link_get_from_dt(ipd_port);
966    }
967#endif
968
969    /* Give the user a chance to override the processing of this function */
970    if (cvmx_override_board_link_get)
971        return cvmx_override_board_link_get(ipd_port);
972
973    /* Unless we fix it later, all links are defaulted to down */
974    result.u64 = 0;
975
976#if !defined(OCTEON_BOARD_CAPK_0100ND)
977    /* This switch statement should handle all ports that either don't use
978        Marvell PHYS, or don't support in-band status */
979    switch (cvmx_sysinfo_get()->board_type)
980    {
981        case CVMX_BOARD_TYPE_SIM:
982            /* The simulator gives you a simulated 1Gbps full duplex link */
983            result.s.link_up = 1;
984            result.s.full_duplex = 1;
985            result.s.speed = 1000;
986            return result;
987        case CVMX_BOARD_TYPE_LANAI2_A:
988        case CVMX_BOARD_TYPE_LANAI2_U:
989        case CVMX_BOARD_TYPE_LANAI2_G:
990            break;
991        case CVMX_BOARD_TYPE_EBH3100:
992        case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
993        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
994        case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
995            /* Port 1 on these boards is always Gigabit */
996            if (ipd_port == 1)
997            {
998                result.s.link_up = 1;
999                result.s.full_duplex = 1;
1000                result.s.speed = 1000;
1001                return result;
1002            }
1003            /* Fall through to the generic code below */
1004            break;
1005        case CVMX_BOARD_TYPE_EBT5600:
1006        case CVMX_BOARD_TYPE_EBH5600:
1007        case CVMX_BOARD_TYPE_EBH5601:
1008        case CVMX_BOARD_TYPE_EBH5610:
1009            /* Board has 1 management ports */
1010            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
1011                is_broadcom_phy = 1;
1012            break;
1013        case CVMX_BOARD_TYPE_EBH5200:
1014        case CVMX_BOARD_TYPE_EBH5201:
1015        case CVMX_BOARD_TYPE_EBT5200:
1016            /* Board has 2 management ports */
1017            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
1018                is_broadcom_phy = 1;
1019            break;
1020        case CVMX_BOARD_TYPE_EBB6100:
1021        case CVMX_BOARD_TYPE_EBB6300:   /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/
1022        case CVMX_BOARD_TYPE_EBB6600:   /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/
1023            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))
1024                && cvmx_helper_board_get_mii_address(ipd_port) >= 0 && cvmx_helper_board_get_mii_address(ipd_port) <= 1)
1025                is_broadcom_phy = 1;
1026            break;
1027        case CVMX_BOARD_TYPE_EP6300C:
1028            is_broadcom_phy = 1;
1029            break;
1030        case CVMX_BOARD_TYPE_CUST_NB5:
1031            /* Port 1 on these boards is always Gigabit */
1032            if (ipd_port == 1)
1033            {
1034                result.s.link_up = 1;
1035                result.s.full_duplex = 1;
1036                result.s.speed = 1000;
1037                return result;
1038            }
1039            else /* The other port uses a broadcom PHY */
1040                is_broadcom_phy = 1;
1041            break;
1042        case CVMX_BOARD_TYPE_BBGW_REF:
1043            /* Port 1 on these boards is always Gigabit */
1044            if (ipd_port == 2)
1045            {
1046                /* Port 2 is not hooked up */
1047                result.u64 = 0;
1048                return result;
1049            }
1050            else
1051            {
1052                /* Ports 0 and 1 connect to the switch */
1053                result.s.link_up = 1;
1054                result.s.full_duplex = 1;
1055                result.s.speed = 1000;
1056                return result;
1057            }
1058        case CVMX_BOARD_TYPE_NIC4E:
1059        case CVMX_BOARD_TYPE_NIC2E:
1060            is_broadcom_phy = 1;
1061            break;
1062	/* Private vendor-defined boards.  */
1063#if defined(OCTEON_VENDOR_LANNER)
1064	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
1065	    /* Ports are BCM5482S */
1066	    is_broadcom_phy = 1;
1067	    break;
1068	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
1069	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
1070	    /* Port 0 connects to the switch */
1071	    if (ipd_port == 0)
1072	    {
1073                result.s.link_up = 1;
1074                result.s.full_duplex = 1;
1075                result.s.speed = 1000;
1076		return result;
1077	    }
1078	    break;
1079#endif
1080    }
1081#endif
1082
1083    phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
1084    //cvmx_dprintf("ipd_port=%d phy_addr=%d broadcom=%d\n",
1085    //             ipd_port, phy_addr, is_broadcom_phy);
1086    if (phy_addr != -1)
1087    {
1088        if (is_broadcom_phy)
1089        {
1090            result =  __get_broadcom_phy_link_state(phy_addr);
1091        }
1092        else
1093        {
1094            /* This code assumes we are using a Marvell Gigabit PHY. */
1095            result = __get_marvell_phy_link_state(phy_addr);
1096        }
1097    }
1098    else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX)
1099             || OCTEON_IS_MODEL(OCTEON_CN50XX))
1100    {
1101        /* We don't have a PHY address, so attempt to use in-band status. It is
1102            really important that boards not supporting in-band status never get
1103            here. Reading broken in-band status tends to do bad things */
1104        result = __get_inband_link_state(ipd_port);
1105    }
1106    else
1107    {
1108        /* We don't have a PHY address and we don't have in-band status. There
1109            is no way to determine the link speed. Return down assuming this
1110            port isn't wired */
1111        result.u64 = 0;
1112    }
1113
1114    /* If link is down, return all fields as zero. */
1115    if (!result.s.link_up)
1116        result.u64 = 0;
1117
1118    return result;
1119}
1120
1121
1122/**
1123 * This function as a board specific method of changing the PHY
1124 * speed, duplex, and autonegotiation. This programs the PHY and
1125 * not Octeon. This can be used to force Octeon's links to
1126 * specific settings.
1127 *
1128 * @param phy_addr  The address of the PHY to program
1129 * @param link_flags
1130 *                  Flags to control autonegotiation.  Bit 0 is autonegotiation
1131 *                  enable/disable to maintain backward compatibility.
1132 * @param link_info Link speed to program. If the speed is zero and autonegotiation
1133 *                  is enabled, all possible negotiation speeds are advertised.
1134 *
1135 * @return Zero on success, negative on failure
1136 */
1137int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags,
1138                                   cvmx_helper_link_info_t link_info)
1139{
1140
1141    /* Set the flow control settings based on link_flags */
1142    if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch)
1143    {
1144        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1145        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1146        reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
1147        reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
1148        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1149    }
1150
1151    /* If speed isn't set and autoneg is on advertise all supported modes */
1152    if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0))
1153    {
1154        cvmx_mdio_phy_reg_control_t reg_control;
1155        cvmx_mdio_phy_reg_status_t reg_status;
1156        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1157        cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
1158        cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
1159
1160        reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
1161        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1162        reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4;
1163        reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full;
1164        reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half;
1165        reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full;
1166        reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half;
1167        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1168        if (reg_status.s.capable_extended_status)
1169        {
1170            reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
1171            reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
1172            reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full;
1173            reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half;
1174            cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
1175        }
1176        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1177        reg_control.s.autoneg_enable = 1;
1178        reg_control.s.restart_autoneg = 1;
1179        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1180    }
1181    else if ((link_flags & set_phy_link_flags_autoneg))
1182    {
1183        cvmx_mdio_phy_reg_control_t reg_control;
1184        cvmx_mdio_phy_reg_status_t reg_status;
1185        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1186        cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
1187
1188        reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
1189        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1190        reg_autoneg_adver.s.advert_100base_t4 = 0;
1191        reg_autoneg_adver.s.advert_10base_tx_full = 0;
1192        reg_autoneg_adver.s.advert_10base_tx_half = 0;
1193        reg_autoneg_adver.s.advert_100base_tx_full = 0;
1194        reg_autoneg_adver.s.advert_100base_tx_half = 0;
1195        if (reg_status.s.capable_extended_status)
1196        {
1197            reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
1198            reg_control_1000.s.advert_1000base_t_full = 0;
1199            reg_control_1000.s.advert_1000base_t_half = 0;
1200        }
1201        switch (link_info.s.speed)
1202        {
1203            case 10:
1204                reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex;
1205                reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex;
1206                break;
1207            case 100:
1208                reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex;
1209                reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex;
1210                break;
1211            case 1000:
1212                reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex;
1213                reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex;
1214                break;
1215        }
1216        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1217        if (reg_status.s.capable_extended_status)
1218            cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
1219        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1220        reg_control.s.autoneg_enable = 1;
1221        reg_control.s.restart_autoneg = 1;
1222        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1223    }
1224    else
1225    {
1226        cvmx_mdio_phy_reg_control_t reg_control;
1227        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1228        reg_control.s.autoneg_enable = 0;
1229        reg_control.s.restart_autoneg = 1;
1230        reg_control.s.duplex = link_info.s.full_duplex;
1231        if (link_info.s.speed == 1000)
1232        {
1233            reg_control.s.speed_msb = 1;
1234            reg_control.s.speed_lsb = 0;
1235        }
1236        else if (link_info.s.speed == 100)
1237        {
1238            reg_control.s.speed_msb = 0;
1239            reg_control.s.speed_lsb = 1;
1240        }
1241        else if (link_info.s.speed == 10)
1242        {
1243            reg_control.s.speed_msb = 0;
1244            reg_control.s.speed_lsb = 0;
1245        }
1246        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1247    }
1248    return 0;
1249}
1250
1251
1252/**
1253 * @INTERNAL
1254 * This function is called by cvmx_helper_interface_probe() after it
1255 * determines the number of ports Octeon can support on a specific
1256 * interface. This function is the per board location to override
1257 * this value. It is called with the number of ports Octeon might
1258 * support and should return the number of actual ports on the
1259 * board.
1260 *
1261 * This function must be modified for every new Octeon board.
1262 * Internally it uses switch statements based on the cvmx_sysinfo
1263 * data to determine board types and revisions. It relies on the
1264 * fact that every Octeon board receives a unique board type
1265 * enumeration from the bootloader.
1266 *
1267 * @param interface Interface to probe
1268 * @param supported_ports
1269 *                  Number of ports Octeon supports.
1270 *
1271 * @return Number of ports the actual board supports. Many times this will
1272 *         simple be "support_ports".
1273 */
1274int __cvmx_helper_board_interface_probe(int interface, int supported_ports)
1275{
1276    switch (cvmx_sysinfo_get()->board_type)
1277    {
1278        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
1279        case CVMX_BOARD_TYPE_LANAI2_A:
1280        case CVMX_BOARD_TYPE_LANAI2_U:
1281        case CVMX_BOARD_TYPE_LANAI2_G:
1282            if (interface == 0)
1283                return 2;
1284	    break;
1285        case CVMX_BOARD_TYPE_BBGW_REF:
1286            if (interface == 0)
1287                return 2;
1288	    break;
1289        case CVMX_BOARD_TYPE_NIC_XLE_4G:
1290            if (interface == 0)
1291                return 0;
1292	    break;
1293        /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
1294            which we don't support. Disable ports connected to it */
1295        case CVMX_BOARD_TYPE_EBH5600:
1296            if (interface == 1)
1297                return 0;
1298	    break;
1299        case CVMX_BOARD_TYPE_EBB5600:
1300#ifdef CVMX_ENABLE_PKO_FUNCTIONS
1301            if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_PICMG)
1302                return 0;
1303#endif
1304	    break;
1305        case CVMX_BOARD_TYPE_EBT5600:
1306	    /* Disable loopback.  */
1307	    if (interface == 3)
1308		return 0;
1309	    break;
1310        case CVMX_BOARD_TYPE_EBT5810:
1311            return 1;  /* Two ports on each SPI: 1 hooked to MAC, 1 loopback
1312                       ** Loopback disabled by default. */
1313        case CVMX_BOARD_TYPE_NIC2E:
1314            if (interface == 0)
1315                return 2;
1316#if defined(OCTEON_VENDOR_LANNER)
1317	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
1318	    if (interface == 1)
1319	        return 12;
1320	    break;
1321#endif
1322    }
1323#ifdef CVMX_BUILD_FOR_UBOOT
1324    if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi"))
1325        return 0;
1326#endif
1327    return supported_ports;
1328}
1329
1330
1331/**
1332 * @INTERNAL
1333 * Enable packet input/output from the hardware. This function is
1334 * called after by cvmx_helper_packet_hardware_enable() to
1335 * perform board specific initialization. For most boards
1336 * nothing is needed.
1337 *
1338 * @param interface Interface to enable
1339 *
1340 * @return Zero on success, negative on failure
1341 */
1342int __cvmx_helper_board_hardware_enable(int interface)
1343{
1344    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5)
1345    {
1346        if (interface == 0)
1347        {
1348            /* Different config for switch port */
1349            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
1350            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
1351            /* Boards with gigabit WAN ports need a different setting that is
1352                compatible with 100 Mbit settings */
1353            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc);
1354            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc);
1355        }
1356    }
1357    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_LANAI2_U)
1358    {
1359        if (interface == 0)
1360        {
1361            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 16);
1362            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 16);
1363        }
1364    }
1365    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5)
1366    {
1367        /* Broadcom PHYs require different ASX clocks. Unfortunately
1368            many customer don't define a new board Id and simply
1369            mangle the CN3010_EVB_HS5 */
1370        if (interface == 0)
1371        {
1372            /* Some customers boards use a hacked up bootloader that identifies them as
1373            ** CN3010_EVB_HS5 evaluation boards.  This leads to all kinds of configuration
1374            ** problems.  Detect one case, and print warning, while trying to do the right thing.
1375            */
1376            int phy_addr = cvmx_helper_board_get_mii_address(0);
1377            if (phy_addr != -1)
1378            {
1379                int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2);
1380                /* Is it a Broadcom PHY? */
1381                if (phy_identifier == 0x0143)
1382                {
1383                    cvmx_dprintf("\n");
1384                    cvmx_dprintf("ERROR:\n");
1385                    cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
1386                    cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
1387                    cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n");
1388                    cvmx_dprintf("ERROR:\n");
1389                    cvmx_dprintf("\n");
1390                    cvmx_wait(1000000000);
1391                    cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5);
1392                    cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5);
1393                }
1394            }
1395        }
1396    }
1397    return 0;
1398}
1399
1400
1401/**
1402 * @INTERNAL
1403 * Gets the clock type used for the USB block based on board type.
1404 * Used by the USB code for auto configuration of clock type.
1405 *
1406 * @return USB clock type enumeration
1407 */
1408cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void)
1409{
1410#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
1411    const void *fdt_addr = CASTPTR(const void *, cvmx_sysinfo_get()->fdt_addr);
1412    int nodeoffset;
1413    const void *nodep;
1414    int len;
1415    uint32_t speed = 0;
1416    const char *type = NULL;
1417
1418    if (fdt_addr)
1419    {
1420        nodeoffset = fdt_path_offset(fdt_addr, "/soc/uctl");
1421        if (nodeoffset < 0)
1422            nodeoffset = fdt_path_offset(fdt_addr, "/soc/usbn");
1423
1424        if (nodeoffset >= 0)
1425        {
1426            nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-type", &len);
1427            if (nodep != NULL && len > 0)
1428                type = (const char *)nodep;
1429            else
1430                type = "unknown";
1431            nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-frequency", &len);
1432            if (nodep != NULL && len == sizeof(uint32_t))
1433                speed = fdt32_to_cpu(*(int *)nodep);
1434            else
1435                speed = 0;
1436            if (!strcmp(type, "crystal"))
1437            {
1438                if (speed == 0 || speed == 12000000)
1439                    return USB_CLOCK_TYPE_CRYSTAL_12;
1440                else
1441                    printf("Warning: invalid crystal speed for USB clock type in FDT\n");
1442            }
1443            else if (!strcmp(type, "external"))
1444            {
1445                switch (speed) {
1446                case 12000000:
1447                    return USB_CLOCK_TYPE_REF_12;
1448                case 24000000:
1449                    return USB_CLOCK_TYPE_REF_24;
1450                case 0:
1451                case 48000000:
1452                    return USB_CLOCK_TYPE_REF_48;
1453                default:
1454                    printf("Warning: invalid USB clock speed of %u hz in FDT\n", speed);
1455                }
1456            }
1457            else
1458                printf("Warning: invalid USB reference clock type \"%s\" in FDT\n", type ? type : "NULL");
1459        }
1460    }
1461#endif
1462    switch (cvmx_sysinfo_get()->board_type)
1463    {
1464        case CVMX_BOARD_TYPE_BBGW_REF:
1465        case CVMX_BOARD_TYPE_LANAI2_A:
1466        case CVMX_BOARD_TYPE_LANAI2_U:
1467        case CVMX_BOARD_TYPE_LANAI2_G:
1468#if defined(OCTEON_VENDOR_LANNER)
1469    case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
1470    case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
1471#endif
1472#if defined(OCTEON_BOARD_CAPK_0100ND)
1473	case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
1474#endif
1475        case CVMX_BOARD_TYPE_NIC10E_66:
1476            return USB_CLOCK_TYPE_CRYSTAL_12;
1477        case CVMX_BOARD_TYPE_NIC10E:
1478            return USB_CLOCK_TYPE_REF_12;
1479        default:
1480            break;
1481    }
1482    if (OCTEON_IS_MODEL(OCTEON_CN6XXX)	/* Most boards except NIC10e use a 12MHz crystal */
1483        || OCTEON_IS_MODEL(OCTEON_CNF7XXX))
1484        return USB_CLOCK_TYPE_CRYSTAL_12;
1485    return USB_CLOCK_TYPE_REF_48;
1486}
1487
1488
1489/**
1490 * @INTERNAL
1491 * Adjusts the number of available USB ports on Octeon based on board
1492 * specifics.
1493 *
1494 * @param supported_ports expected number of ports based on chip type;
1495 *
1496 *
1497 * @return number of available usb ports, based on board specifics.
1498 *         Return value is supported_ports if function does not
1499 *         override.
1500 */
1501int __cvmx_helper_board_usb_get_num_ports(int supported_ports)
1502{
1503    switch (cvmx_sysinfo_get()->board_type)
1504    {
1505        case CVMX_BOARD_TYPE_NIC_XLE_4G:
1506        case CVMX_BOARD_TYPE_NIC2E:
1507            return 0;
1508    }
1509
1510    return supported_ports;
1511}
1512
1513
1514