1210284Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2011  Cavium Inc. (support@cavium.com). All rights
3215990Sjmallett * reserved.
4210284Sjmallett *
5210284Sjmallett *
6215990Sjmallett * Redistribution and use in source and binary forms, with or without
7215990Sjmallett * modification, are permitted provided that the following conditions are
8215990Sjmallett * met:
9210284Sjmallett *
10215990Sjmallett *   * Redistributions of source code must retain the above copyright
11215990Sjmallett *     notice, this list of conditions and the following disclaimer.
12210284Sjmallett *
13215990Sjmallett *   * Redistributions in binary form must reproduce the above
14215990Sjmallett *     copyright notice, this list of conditions and the following
15215990Sjmallett *     disclaimer in the documentation and/or other materials provided
16215990Sjmallett *     with the distribution.
17215990Sjmallett
18232812Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19215990Sjmallett *     its contributors may be used to endorse or promote products
20215990Sjmallett *     derived from this software without specific prior written
21215990Sjmallett *     permission.
22215990Sjmallett
23215990Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215990Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215990Sjmallett * regulations, and may be subject to export or import  regulations in other
26215990Sjmallett * countries.
27215990Sjmallett
28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38210284Sjmallett ***********************license end**************************************/
39210284Sjmallett
40210284Sjmallett
41210284Sjmallett
42210284Sjmallett
43210284Sjmallett
44210284Sjmallett
45215990Sjmallett
46210284Sjmallett/**
47210284Sjmallett * @file
48210284Sjmallett *
49210284Sjmallett * Helper functions to abstract board specific data about
50210284Sjmallett * network ports from the rest of the cvmx-helper files.
51210284Sjmallett *
52232812Sjmallett * <hr>$Revision: 70030 $<hr>
53210284Sjmallett */
54215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
55215990Sjmallett#include <linux/module.h>
56215990Sjmallett#include <asm/octeon/cvmx.h>
57215990Sjmallett#include <asm/octeon/cvmx-bootinfo.h>
58215990Sjmallett#include <asm/octeon/cvmx-smix-defs.h>
59215990Sjmallett#include <asm/octeon/cvmx-gmxx-defs.h>
60215990Sjmallett#include <asm/octeon/cvmx-asxx-defs.h>
61215990Sjmallett#include <asm/octeon/cvmx-mdio.h>
62215990Sjmallett#include <asm/octeon/cvmx-helper.h>
63215990Sjmallett#include <asm/octeon/cvmx-helper-util.h>
64215990Sjmallett#include <asm/octeon/cvmx-helper-board.h>
65215990Sjmallett#include <asm/octeon/cvmx-twsi.h>
66215990Sjmallett#else
67210284Sjmallett#include "cvmx.h"
68210284Sjmallett#include "cvmx-app-init.h"
69215990Sjmallett#include "cvmx-sysinfo.h"
70215990Sjmallett#include "cvmx-twsi.h"
71210284Sjmallett#include "cvmx-mdio.h"
72210284Sjmallett#include "cvmx-helper.h"
73210284Sjmallett#include "cvmx-helper-util.h"
74210284Sjmallett#include "cvmx-helper-board.h"
75232812Sjmallett#include "cvmx-gpio.h"
76232815Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL)
77232812Sjmallett#ifdef __U_BOOT__
78232812Sjmallett# include <libfdt.h>
79232812Sjmallett#else
80232812Sjmallett# include "libfdt/libfdt.h"
81215990Sjmallett#endif
82232815Sjmallett#endif
83232812Sjmallett#include "cvmx-swap.h"
84232812Sjmallett#endif
85210284Sjmallett
86210284Sjmallett/**
87210284Sjmallett * cvmx_override_board_link_get(int ipd_port) is a function
88210284Sjmallett * pointer. It is meant to allow customization of the process of
89210284Sjmallett * talking to a PHY to determine link speed. It is called every
90210284Sjmallett * time a PHY must be polled for link status. Users should set
91210284Sjmallett * this pointer to a function before calling any cvmx-helper
92210284Sjmallett * operations.
93210284Sjmallett */
94210284SjmallettCVMX_SHARED cvmx_helper_link_info_t (*cvmx_override_board_link_get)(int ipd_port) = NULL;
95210284Sjmallett
96232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
97232812Sjmallett
98232812Sjmallettstatic 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)
99232812Sjmallett{
100232812Sjmallett    int tries = 3;
101232812Sjmallett    int r;
102232812Sjmallett    do {
103232812Sjmallett        r = cvmx_twsix_write_ia(twsi_id, dev_addr, internal_addr, num_bytes, ia_width_bytes, data);
104232812Sjmallett    } while (tries-- > 0 && r < 0);
105232812Sjmallett}
106232812Sjmallett
107232812Sjmallettstatic int __pip_eth_node(const void *fdt_addr, int aliases, int ipd_port)
108232812Sjmallett{
109232812Sjmallett    char name_buffer[20];
110232812Sjmallett    const char*pip_path;
111232812Sjmallett    int pip, iface, eth;
112232812Sjmallett    int interface_num    = cvmx_helper_get_interface_num(ipd_port);
113232812Sjmallett    int interface_index  = cvmx_helper_get_interface_index_num(ipd_port);
114232812Sjmallett
115232812Sjmallett    pip_path = fdt_getprop(fdt_addr, aliases, "pip", NULL);
116232812Sjmallett    if (!pip_path)
117232812Sjmallett    {
118232812Sjmallett        cvmx_dprintf("ERROR: pip path not found in device tree\n");
119232812Sjmallett        return -1;
120232812Sjmallett    }
121232812Sjmallett    pip = fdt_path_offset(fdt_addr, pip_path);
122232812Sjmallett    if (pip < 0)
123232812Sjmallett    {
124232812Sjmallett        cvmx_dprintf("ERROR: pip not found in device tree\n");
125232812Sjmallett        return -1;
126232812Sjmallett    }
127232812Sjmallett#ifdef __U_BOOT__
128232812Sjmallett    sprintf(name_buffer, "interface@%d", interface_num);
129232812Sjmallett#else
130232812Sjmallett    snprintf(name_buffer, sizeof(name_buffer), "interface@%d", interface_num);
131232812Sjmallett#endif
132232812Sjmallett    iface =  fdt_subnode_offset(fdt_addr, pip, name_buffer);
133232812Sjmallett    if (iface < 0)
134232812Sjmallett    {
135232812Sjmallett        cvmx_dprintf("ERROR : pip intf %d not found in device tree \n",
136232812Sjmallett                     interface_num);
137232812Sjmallett        return -1;
138232812Sjmallett    }
139232812Sjmallett#ifdef __U_BOOT__
140232812Sjmallett    sprintf(name_buffer, "ethernet@%x", interface_index);
141232812Sjmallett#else
142232812Sjmallett    snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", interface_index);
143232812Sjmallett#endif
144232812Sjmallett    eth = fdt_subnode_offset(fdt_addr, iface, name_buffer);
145232812Sjmallett    if (eth < 0)
146232812Sjmallett    {
147232812Sjmallett        cvmx_dprintf("ERROR : pip interface@%d ethernet@%d not found in device "
148232812Sjmallett                     "tree\n", interface_num, interface_index);
149232812Sjmallett        return -1;
150232812Sjmallett    }
151232812Sjmallett    return eth;
152232812Sjmallett}
153232812Sjmallett
154232812Sjmallettstatic int __mix_eth_node(const void *fdt_addr, int aliases, int interface_index)
155232812Sjmallett{
156232812Sjmallett    char name_buffer[20];
157232812Sjmallett    const char*mix_path;
158232812Sjmallett    int mix;
159232812Sjmallett
160232812Sjmallett#ifdef __U_BOOT__
161232812Sjmallett    sprintf(name_buffer, "mix%d", interface_index);
162232812Sjmallett#else
163232812Sjmallett    snprintf(name_buffer, sizeof(name_buffer), "mix%d", interface_index);
164232812Sjmallett#endif
165232812Sjmallett    mix_path = fdt_getprop(fdt_addr, aliases, name_buffer, NULL);
166232812Sjmallett    if (!mix_path)
167232812Sjmallett    {
168232812Sjmallett        cvmx_dprintf("ERROR: mix%d path not found in device tree\n",interface_index);
169232812Sjmallett    }
170232812Sjmallett    mix = fdt_path_offset(fdt_addr, mix_path);
171232812Sjmallett    if (mix < 0)
172232812Sjmallett    {
173232812Sjmallett        cvmx_dprintf("ERROR: %s not found in device tree\n", mix_path);
174232812Sjmallett        return -1;
175232812Sjmallett    }
176232812Sjmallett    return mix;
177232812Sjmallett}
178232812Sjmallett
179232812Sjmalletttypedef struct cvmx_phy_info
180232812Sjmallett{
181232812Sjmallett    int phy_addr;
182232812Sjmallett    int direct_connect;
183232812Sjmallett    cvmx_phy_type_t phy_type;
184232812Sjmallett}cvmx_phy_info_t;
185232812Sjmallett
186232812Sjmallett
187232812Sjmallettstatic int __mdiobus_addr_to_unit(uint32_t addr)
188232812Sjmallett{
189232812Sjmallett    int unit = (addr >> 7) & 3;
190232812Sjmallett    if (!OCTEON_IS_MODEL(OCTEON_CN68XX))
191232812Sjmallett        unit >>= 1;
192232812Sjmallett    return unit;
193232812Sjmallett}
194210284Sjmallett/**
195210284Sjmallett * Return the MII PHY address associated with the given IPD
196232812Sjmallett * port. The phy address is obtained from the device tree.
197232812Sjmallett *
198232812Sjmallett * @param ipd_port Octeon IPD port to get the MII address for.
199232812Sjmallett *
200232812Sjmallett * @return MII PHY address and bus number or -1.
201232812Sjmallett */
202232812Sjmallett
203232812Sjmallettstatic cvmx_phy_info_t __get_phy_info_from_dt(int ipd_port)
204232812Sjmallett{
205232812Sjmallett    const void *fdt_addr = CASTPTR(const void *, cvmx_sysinfo_get()->fdt_addr);
206232812Sjmallett    uint32_t *phy_handle;
207232812Sjmallett    int aliases, eth, phy, phy_parent, phandle, ret;
208232812Sjmallett    cvmx_phy_info_t phy_info;
209232812Sjmallett    int mdio_unit=-1;
210232812Sjmallett    const char *phy_comaptible_str;
211232812Sjmallett    uint32_t *phy_addr_ptr;
212232812Sjmallett
213232812Sjmallett    phy_info.phy_addr = -1;
214232812Sjmallett    phy_info.direct_connect = -1;
215232812Sjmallett    phy_info.phy_type = (cvmx_phy_type_t) -1;
216232812Sjmallett
217232812Sjmallett    if (!fdt_addr)
218232812Sjmallett    {
219232812Sjmallett        cvmx_dprintf("No device tree found.\n");
220232812Sjmallett        return phy_info;
221232812Sjmallett    }
222232812Sjmallett    aliases = fdt_path_offset(fdt_addr, "/aliases");
223232812Sjmallett    if (aliases < 0) {
224232812Sjmallett        cvmx_dprintf("Error: No /aliases node in device tree.\n");
225232812Sjmallett        return phy_info;
226232812Sjmallett    }
227232812Sjmallett    if (ipd_port < 0)
228232812Sjmallett    {
229232812Sjmallett        int interface_index = ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
230232812Sjmallett        eth = __mix_eth_node(fdt_addr, aliases, interface_index) ;
231232812Sjmallett    }
232232812Sjmallett    else
233232812Sjmallett    {
234232812Sjmallett        eth = __pip_eth_node(fdt_addr, aliases, ipd_port);
235232812Sjmallett    }
236232812Sjmallett    if (eth < 0 )
237232812Sjmallett    {
238232812Sjmallett        cvmx_dprintf("ERROR : cannot find interface for ipd_port=%d\n", ipd_port);
239232812Sjmallett        return phy_info;
240232812Sjmallett    }
241232812Sjmallett    /* Get handle to phy */
242232812Sjmallett    phy_handle = (uint32_t *) fdt_getprop(fdt_addr, eth, "phy-handle", NULL);
243232812Sjmallett    if (!phy_handle)
244232812Sjmallett    {
245232812Sjmallett        cvmx_dprintf("ERROR : phy handle not found in device tree ipd_port=%d"
246232812Sjmallett                     "\n", ipd_port);
247232812Sjmallett        return phy_info;
248232812Sjmallett    }
249232812Sjmallett    phandle = cvmx_be32_to_cpu(*phy_handle);
250232812Sjmallett    phy = fdt_node_offset_by_phandle(fdt_addr, phandle);
251232812Sjmallett    if (phy < 0)
252232812Sjmallett    {
253232812Sjmallett        cvmx_dprintf("ERROR : cannot find phy for ipd_port=%d ret=%d\n",
254232812Sjmallett                     ipd_port, phy);
255232812Sjmallett        return phy_info;
256232812Sjmallett    }
257232812Sjmallett    phy_comaptible_str = (const char *) fdt_getprop(fdt_addr, phy,
258232812Sjmallett                                                    "compatible", NULL);
259232812Sjmallett    if (!phy_comaptible_str)
260232812Sjmallett    {
261232812Sjmallett        cvmx_dprintf("ERROR : no compatible prop in phy\n");
262232812Sjmallett        return phy_info;
263232812Sjmallett    }
264232812Sjmallett    if (memcmp("marvell", phy_comaptible_str, strlen("marvell")) == 0)
265232812Sjmallett    {
266232812Sjmallett        phy_info.phy_type = MARVELL_GENERIC_PHY;
267232812Sjmallett    }
268232812Sjmallett    else if (memcmp("broadcom", phy_comaptible_str, strlen("broadcom")) == 0)
269232812Sjmallett    {
270232812Sjmallett        phy_info.phy_type = BROADCOM_GENERIC_PHY;
271232812Sjmallett    }
272232812Sjmallett    else
273232812Sjmallett    {
274232812Sjmallett        phy_info.phy_type = -1;
275232812Sjmallett    }
276232812Sjmallett
277232812Sjmallett    /* Check if PHY parent is the octeon MDIO bus. Some boards are connected
278232812Sjmallett       though a MUX and for them direct_connect_to_phy will be 0 */
279232812Sjmallett    phy_parent = fdt_parent_offset(fdt_addr, phy);
280232812Sjmallett    if (phy_parent < 0)
281232812Sjmallett    {
282232812Sjmallett        cvmx_dprintf("ERROR : cannot find phy parent for ipd_port=%d ret=%d\n",
283232812Sjmallett                     ipd_port, phy_parent);
284232812Sjmallett        return phy_info;
285232812Sjmallett    }
286232812Sjmallett    ret = fdt_node_check_compatible(fdt_addr, phy_parent,
287232812Sjmallett                                    "cavium,octeon-3860-mdio");
288232812Sjmallett    if (ret == 0)
289232812Sjmallett    {
290232812Sjmallett        phy_info.direct_connect = 1 ;
291232812Sjmallett        uint32_t *mdio_reg_base = (uint32_t *) fdt_getprop(fdt_addr, phy_parent,"reg",0);
292232812Sjmallett        if (mdio_reg_base == 0)
293232812Sjmallett        {
294232812Sjmallett            cvmx_dprintf("ERROR : unable to get reg property in phy mdio\n");
295232812Sjmallett            return phy_info;
296232812Sjmallett        }
297232812Sjmallett        mdio_unit = __mdiobus_addr_to_unit(mdio_reg_base[1]);
298232812Sjmallett        //cvmx_dprintf("phy parent=%s reg_base=%08x unit=%d \n",
299232812Sjmallett        //             fdt_get_name(fdt_addr,phy_parent, NULL), mdio_reg_base[1], mdio_unit);
300232812Sjmallett    }
301232812Sjmallett    else
302232812Sjmallett    {
303232812Sjmallett        phy_info.direct_connect = 0;
304232812Sjmallett        /* The PHY is not directly connected to the Octeon MDIO bus.
305232812Sjmallett           SE doesn't  have abstractions for MDIO MUX or MDIO MUX drivers and
306232812Sjmallett           hence for the non direct cases code will be needed which is
307232812Sjmallett           board specific.
308232812Sjmallett           For now the the MDIO Unit is defaulted to 1.
309232812Sjmallett        */
310232812Sjmallett        mdio_unit = 1;
311232812Sjmallett    }
312232812Sjmallett
313232812Sjmallett    phy_addr_ptr = (uint32_t *) fdt_getprop(fdt_addr, phy, "reg", NULL);
314232812Sjmallett    phy_info.phy_addr = cvmx_be32_to_cpu(*phy_addr_ptr) | mdio_unit << 8;
315232812Sjmallett    return phy_info;
316232812Sjmallett
317232812Sjmallett}
318232812Sjmallett
319232812Sjmallett/**
320232812Sjmallett * Return the MII PHY address associated with the given IPD
321232812Sjmallett * port. The phy address is obtained from the device tree.
322232812Sjmallett *
323232812Sjmallett * @param ipd_port Octeon IPD port to get the MII address for.
324232812Sjmallett *
325232812Sjmallett * @return MII PHY address and bus number or -1.
326232812Sjmallett */
327232812Sjmallett
328232812Sjmallettint cvmx_helper_board_get_mii_address_from_dt(int ipd_port)
329232812Sjmallett{
330232812Sjmallett        cvmx_phy_info_t phy_info = __get_phy_info_from_dt(ipd_port);
331232812Sjmallett        return phy_info.phy_addr;
332232812Sjmallett}
333232812Sjmallett#endif
334232812Sjmallett
335232812Sjmallett/**
336232812Sjmallett * Return the MII PHY address associated with the given IPD
337210284Sjmallett * port. A result of -1 means there isn't a MII capable PHY
338210284Sjmallett * connected to this port. On chips supporting multiple MII
339210284Sjmallett * busses the bus number is encoded in bits <15:8>.
340210284Sjmallett *
341210284Sjmallett * This function must be modified for every new Octeon board.
342210284Sjmallett * Internally it uses switch statements based on the cvmx_sysinfo
343210284Sjmallett * data to determine board types and revisions. It replies on the
344210284Sjmallett * fact that every Octeon board receives a unique board type
345210284Sjmallett * enumeration from the bootloader.
346210284Sjmallett *
347210284Sjmallett * @param ipd_port Octeon IPD port to get the MII address for.
348210284Sjmallett *
349210284Sjmallett * @return MII PHY address and bus number or -1.
350210284Sjmallett */
351210284Sjmallettint cvmx_helper_board_get_mii_address(int ipd_port)
352210284Sjmallett{
353210311Sjmallett    /*
354210311Sjmallett     * Board types we have to know at compile-time.
355210311Sjmallett     */
356210311Sjmallett#ifdef OCTEON_BOARD_CAPK_0100ND
357210311Sjmallett    switch (ipd_port) {
358210311Sjmallett    case 0:
359210311Sjmallett	return 2;
360210311Sjmallett    case 1:
361210311Sjmallett	return 3;
362210311Sjmallett    case 2:
363210311Sjmallett	/* XXX Switch PHY?  */
364210311Sjmallett	return -1;
365210311Sjmallett    default:
366210311Sjmallett	return -1;
367210311Sjmallett    }
368210311Sjmallett#endif
369210311Sjmallett
370210311Sjmallett    /*
371210311Sjmallett     * For board types we can determine at runtime.
372210311Sjmallett     */
373232812Sjmallett    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
374232812Sjmallett        return -1;
375232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
376232812Sjmallett    if (cvmx_sysinfo_get()->fdt_addr)
377232812Sjmallett    {
378232812Sjmallett        cvmx_phy_info_t phy_info = __get_phy_info_from_dt(ipd_port);
379232812Sjmallett        //cvmx_dprintf("ipd_port=%d phy_addr=%d\n", ipd_port, phy_info.phy_addr);
380232812Sjmallett        if (phy_info.phy_addr >= 0) return phy_info.phy_addr;
381232812Sjmallett    }
382232812Sjmallett#endif
383210284Sjmallett    switch (cvmx_sysinfo_get()->board_type)
384210284Sjmallett    {
385210284Sjmallett        case CVMX_BOARD_TYPE_SIM:
386210284Sjmallett            /* Simulator doesn't have MII */
387210284Sjmallett            return -1;
388250428Simp#if !defined(OCTEON_VENDOR_GEFES)
389250428Simp        case CVMX_BOARD_TYPE_EBT5800:
390250428Simp        case CVMX_BOARD_TYPE_NICPRO2:
391250428Simp#endif
392210284Sjmallett        case CVMX_BOARD_TYPE_EBT3000:
393210284Sjmallett        case CVMX_BOARD_TYPE_THUNDER:
394210284Sjmallett            /* Interface 0 is SPI4, interface 1 is RGMII */
395210284Sjmallett            if ((ipd_port >= 16) && (ipd_port < 20))
396210284Sjmallett                return ipd_port - 16;
397210284Sjmallett            else
398210284Sjmallett                return -1;
399215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_A:
400215990Sjmallett            if (ipd_port == 0)
401215990Sjmallett                return 0;
402215990Sjmallett            else
403215990Sjmallett                return -1;
404215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_U:
405215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_G:
406215990Sjmallett            if (ipd_port == 0)
407215990Sjmallett                return 0x1c;
408215990Sjmallett            else
409215990Sjmallett                return -1;
410210284Sjmallett        case CVMX_BOARD_TYPE_KODAMA:
411210284Sjmallett        case CVMX_BOARD_TYPE_EBH3100:
412210284Sjmallett        case CVMX_BOARD_TYPE_HIKARI:
413210284Sjmallett        case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
414210284Sjmallett        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
415250428Simp#if !defined(OCTEON_VENDOR_GEFES)
416210284Sjmallett        case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
417250428Simp#endif
418210284Sjmallett            /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a
419210284Sjmallett                switch */
420210284Sjmallett            if (ipd_port == 0)
421210284Sjmallett                return 4;
422210284Sjmallett            else if (ipd_port == 1)
423210284Sjmallett                return 9;
424210284Sjmallett            else
425210284Sjmallett                return -1;
426210284Sjmallett        case CVMX_BOARD_TYPE_EBH3000:
427210284Sjmallett            /* Board has dual SPI4 and no PHYs */
428210284Sjmallett            return -1;
429215990Sjmallett        case CVMX_BOARD_TYPE_EBT5810:
430215990Sjmallett            /* Board has 10g PHYs hooked up to the MII controller on the
431215990Sjmallett            ** IXF18201 MAC.  The 10G PHYS use clause 45 MDIO which the CN58XX
432215990Sjmallett            ** does not support. All MII accesses go through the IXF part. */
433215990Sjmallett            return -1;
434210284Sjmallett        case CVMX_BOARD_TYPE_EBH5200:
435210284Sjmallett        case CVMX_BOARD_TYPE_EBH5201:
436210284Sjmallett        case CVMX_BOARD_TYPE_EBT5200:
437215990Sjmallett            /* Board has 2 management ports */
438215990Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
439215990Sjmallett                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
440210284Sjmallett            /* Board has 4 SGMII ports. The PHYs start right after the MII
441210284Sjmallett                ports MII0 = 0, MII1 = 1, SGMII = 2-5 */
442210284Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
443210284Sjmallett                return ipd_port+2;
444210284Sjmallett            else
445210284Sjmallett                return -1;
446210284Sjmallett        case CVMX_BOARD_TYPE_EBH5600:
447210284Sjmallett        case CVMX_BOARD_TYPE_EBH5601:
448215990Sjmallett        case CVMX_BOARD_TYPE_EBH5610:
449215990Sjmallett            /* Board has 1 management port */
450215990Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
451215990Sjmallett                return 0;
452210284Sjmallett            /* Board has 8 SGMII ports. 4 connect out, two connect to a switch,
453210284Sjmallett                and 2 loop to each other */
454210284Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
455210284Sjmallett                return ipd_port+1;
456210284Sjmallett            else
457210284Sjmallett                return -1;
458242423Sjmallett        case CVMX_BOARD_TYPE_EBT5600:
459242423Sjmallett	    /* Board has 1 management port */
460242423Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
461242423Sjmallett                return 0;
462242423Sjmallett	    /* Board has 1 XAUI port connected to a switch.  */
463242423Sjmallett	    return -1;
464215990Sjmallett        case CVMX_BOARD_TYPE_EBB5600:
465215990Sjmallett            {
466215990Sjmallett                static unsigned char qlm_switch_addr = 0;
467215990Sjmallett
468215990Sjmallett                /* Board has 1 management port */
469215990Sjmallett                if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
470215990Sjmallett                    return 0;
471215990Sjmallett
472215990Sjmallett                /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */
473215990Sjmallett                if ((ipd_port >= 0) && (ipd_port < 4))
474215990Sjmallett                {
475215990Sjmallett                    if (qlm_switch_addr != 0x3)
476215990Sjmallett                    {
477215990Sjmallett                        qlm_switch_addr = 0x3;  /* QLM1 */
478215990Sjmallett                        cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
479215990Sjmallett                        cvmx_wait_usec(11000); /* Let the write complete */
480215990Sjmallett                    }
481215990Sjmallett                    return ipd_port+1 + (1<<8);
482215990Sjmallett                }
483215990Sjmallett                else if ((ipd_port >= 16) && (ipd_port < 20))
484215990Sjmallett                {
485215990Sjmallett                    if (qlm_switch_addr != 0xC)
486215990Sjmallett                    {
487215990Sjmallett                        qlm_switch_addr = 0xC;  /* QLM3 */
488215990Sjmallett                        cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
489215990Sjmallett                        cvmx_wait_usec(11000); /* Let the write complete */
490215990Sjmallett                    }
491215990Sjmallett                    return ipd_port-16+1 + (1<<8);
492215990Sjmallett                }
493215990Sjmallett                else
494215990Sjmallett                    return -1;
495215990Sjmallett            }
496215990Sjmallett        case CVMX_BOARD_TYPE_EBB6300:
497215990Sjmallett            /* Board has 2 management ports */
498215990Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
499215990Sjmallett                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
500215990Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
501215990Sjmallett                return ipd_port + 1 + (1<<8);
502215990Sjmallett            else
503215990Sjmallett                return -1;
504232812Sjmallett        case CVMX_BOARD_TYPE_EBB6800:
505232812Sjmallett            /* Board has 1 management ports */
506232812Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
507232812Sjmallett                return 6;
508232812Sjmallett            if (ipd_port >= 0x800 && ipd_port < 0x900) /* QLM 0*/
509232812Sjmallett                return 0x101 + ((ipd_port >> 4) & 3); /* SMI 1*/
510232812Sjmallett            if (ipd_port >= 0xa00 && ipd_port < 0xb00) /* QLM 2*/
511232812Sjmallett                return 0x201 + ((ipd_port >> 4) & 3); /* SMI 2*/
512232812Sjmallett            if (ipd_port >= 0xb00 && ipd_port < 0xc00) /* QLM 3*/
513232812Sjmallett                return 0x301 + ((ipd_port >> 4) & 3); /* SMI 3*/
514232812Sjmallett            if (ipd_port >= 0xc00 && ipd_port < 0xd00) /* QLM 4*/
515232812Sjmallett                return 0x001 + ((ipd_port >> 4) & 3); /* SMI 0*/
516232812Sjmallett            return -1;
517232812Sjmallett        case CVMX_BOARD_TYPE_EP6300C:
518232812Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
519232812Sjmallett                return 0x01;
520232812Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT+1)
521232812Sjmallett                return 0x02;
522232812Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
523232812Sjmallett            {
524232812Sjmallett                int interface = cvmx_helper_get_interface_num(ipd_port);
525232812Sjmallett                int mode = cvmx_helper_interface_get_mode(interface);
526232812Sjmallett                if (mode == CVMX_HELPER_INTERFACE_MODE_XAUI)
527232812Sjmallett                    return ipd_port;
528232812Sjmallett                else if ((ipd_port >= 0) && (ipd_port < 4))
529232812Sjmallett                    return ipd_port + 3;
530232812Sjmallett                else
531232812Sjmallett                    return -1;
532232812Sjmallett            }
533232812Sjmallett#endif
534232812Sjmallett            break;
535210284Sjmallett        case CVMX_BOARD_TYPE_CUST_NB5:
536210284Sjmallett            if (ipd_port == 2)
537210284Sjmallett                return 4;
538210284Sjmallett            else
539210284Sjmallett                return -1;
540210284Sjmallett        case CVMX_BOARD_TYPE_NIC_XLE_4G:
541210284Sjmallett            /* Board has 4 SGMII ports. connected QLM3(interface 1) */
542210284Sjmallett            if ((ipd_port >= 16) && (ipd_port < 20))
543210284Sjmallett                return ipd_port - 16 + 1;
544210284Sjmallett            else
545210284Sjmallett                return -1;
546215990Sjmallett        case CVMX_BOARD_TYPE_NIC_XLE_10G:
547232812Sjmallett        case CVMX_BOARD_TYPE_NIC10E:
548215990Sjmallett            return -1;  /* We don't use clause 45 MDIO for anything */
549232812Sjmallett        case CVMX_BOARD_TYPE_NIC4E:
550232812Sjmallett            if (ipd_port >= 0 && ipd_port <= 3)
551232812Sjmallett                return (ipd_port + 0x1f) & 0x1f;
552232812Sjmallett            else
553232812Sjmallett                return -1;
554232812Sjmallett        case CVMX_BOARD_TYPE_NIC2E:
555232812Sjmallett            if (ipd_port >= 0 && ipd_port <= 1)
556232812Sjmallett                return (ipd_port + 1);
557232812Sjmallett            else
558232812Sjmallett                return -1;
559232812Sjmallett        case CVMX_BOARD_TYPE_REDWING:
560232812Sjmallett	    return -1;  /* No PHYs connected to Octeon */
561210284Sjmallett        case CVMX_BOARD_TYPE_BBGW_REF:
562210284Sjmallett            return -1;  /* No PHYs are connected to Octeon, everything is through switch */
563215990Sjmallett	case CVMX_BOARD_TYPE_CUST_WSX16:
564215990Sjmallett		if (ipd_port >= 0 && ipd_port <= 3)
565215990Sjmallett			return ipd_port;
566215990Sjmallett		else if (ipd_port >= 16 && ipd_port <= 19)
567215990Sjmallett			return ipd_port - 16 + 4;
568215990Sjmallett		else
569215990Sjmallett			return -1;
570210311Sjmallett
571210311Sjmallett	/* Private vendor-defined boards.  */
572210311Sjmallett#if defined(OCTEON_VENDOR_LANNER)
573215014Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
574215014Sjmallett	    /* Interface 1 is 12 BCM5482S PHYs.  */
575215014Sjmallett            if ((ipd_port >= 16) && (ipd_port < 28))
576215014Sjmallett                return ipd_port - 16;
577215014Sjmallett	    return -1;
578215014Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
579217214Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
580217214Sjmallett		return (ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT) + 0x81;
581215014Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
582215014Sjmallett                return ipd_port;
583215014Sjmallett	    return -1;
584210311Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
585216476Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
586213346Sjmallett	    /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell
587213346Sjmallett	       88E1111 interfaces.  */
588210311Sjmallett	    switch (ipd_port) {
589210311Sjmallett	    case 0:
590213346Sjmallett		return 16;
591210311Sjmallett	    case 1:
592210311Sjmallett		return 1;
593210311Sjmallett	    case 2:
594210311Sjmallett		return 2;
595210311Sjmallett	    default:
596210311Sjmallett		return -1;
597210311Sjmallett	    }
598210311Sjmallett#endif
599244984Sjmallett#if defined(OCTEON_VENDOR_UBIQUITI)
600244984Sjmallett	case CVMX_BOARD_TYPE_CUST_UBIQUITI_E100:
601320073Sjhibbits	case CVMX_BOARD_TYPE_CUST_UBIQUITI_USG:
602244984Sjmallett	    if (ipd_port > 2)
603244984Sjmallett		return -1;
604244984Sjmallett	    return (7 - ipd_port);
605244984Sjmallett#endif
606242116Sjmallett#if defined(OCTEON_VENDOR_RADISYS)
607242116Sjmallett	case CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE:
608242116Sjmallett	    /* No MII.  */
609242116Sjmallett	    return -1;
610242116Sjmallett#endif
611250428Simp#if defined(OCTEON_VENDOR_GEFES)
612250428Simp        case CVMX_BOARD_TYPE_AT5810:
613250428Simp		return -1;
614250428Simp        case CVMX_BOARD_TYPE_TNPA3804:
615250428Simp    	case CVMX_BOARD_TYPE_CUST_TNPA5804:
616250428Simp	case CVMX_BOARD_TYPE_CUST_W5800:
617250428Simp	case CVMX_BOARD_TYPE_WNPA3850:
618250428Simp	case CVMX_BOARD_TYPE_W3860:
619250428Simp		return -1;// RGMII boards should use inbad status
620250428Simp	case CVMX_BOARD_TYPE_CUST_W5651X:
621250428Simp	case CVMX_BOARD_TYPE_CUST_W5650:
622250428Simp	case CVMX_BOARD_TYPE_CUST_TNPA56X4:
623250428Simp	case CVMX_BOARD_TYPE_CUST_TNPA5651X:
624250428Simp        case CVMX_BOARD_TYPE_CUST_W63XX:
625250428Simp		return -1; /* No PHYs are connected to Octeon, PHYs inside of SFPs which is accessed over TWSI */
626250428Simp	case CVMX_BOARD_TYPE_CUST_W5434:
627250428Simp		/* Board has 4 SGMII ports. 4 connect out
628250428Simp		 * must return the MII address of the PHY connected to each IPD port
629250428Simp		 */
630250428Simp		if ((ipd_port >= 16) && (ipd_port < 20))
631250428Simp			return ipd_port - 16 + 0x40;
632250428Simp		else
633250428Simp			return -1;
634250428Simp#endif
635210284Sjmallett    }
636210284Sjmallett
637210284Sjmallett    /* Some unknown board. Somebody forgot to update this function... */
638215990Sjmallett    cvmx_dprintf("%s: Unknown board type %d\n",
639215990Sjmallett                 __FUNCTION__, cvmx_sysinfo_get()->board_type);
640210284Sjmallett    return -1;
641210284Sjmallett}
642215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
643215990SjmallettEXPORT_SYMBOL(cvmx_helper_board_get_mii_address);
644215990Sjmallett#endif
645210284Sjmallett
646232812Sjmallett/**
647232812Sjmallett * @INTERNAL
648232812Sjmallett * Get link state of marvell PHY
649232812Sjmallett */
650232812Sjmallettstatic cvmx_helper_link_info_t __get_marvell_phy_link_state(int phy_addr)
651232812Sjmallett{
652232812Sjmallett    cvmx_helper_link_info_t  result;
653232812Sjmallett    int phy_status;
654210284Sjmallett
655232812Sjmallett    result.u64 = 0;
656232812Sjmallett    /*All the speed information can be read from register 17 in one go.*/
657232812Sjmallett    phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
658232812Sjmallett
659232812Sjmallett    /* If the resolve bit 11 isn't set, see if autoneg is turned off
660232812Sjmallett       (bit 12, reg 0). The resolve bit doesn't get set properly when
661232812Sjmallett       autoneg is off, so force it */
662232812Sjmallett    if ((phy_status & (1<<11)) == 0)
663232812Sjmallett    {
664232812Sjmallett        int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
665232812Sjmallett        if ((auto_status & (1<<12)) == 0)
666232812Sjmallett            phy_status |= 1<<11;
667232812Sjmallett    }
668232812Sjmallett
669232812Sjmallett    /* Only return a link if the PHY has finished auto negotiation
670232812Sjmallett       and set the resolved bit (bit 11) */
671232812Sjmallett    if (phy_status & (1<<11))
672232812Sjmallett    {
673232812Sjmallett        result.s.link_up = 1;
674232812Sjmallett        result.s.full_duplex = ((phy_status>>13)&1);
675232812Sjmallett        switch ((phy_status>>14)&3)
676232812Sjmallett        {
677232812Sjmallett            case 0: /* 10 Mbps */
678232812Sjmallett                result.s.speed = 10;
679232812Sjmallett                break;
680232812Sjmallett            case 1: /* 100 Mbps */
681232812Sjmallett                result.s.speed = 100;
682232812Sjmallett                break;
683232812Sjmallett            case 2: /* 1 Gbps */
684232812Sjmallett                result.s.speed = 1000;
685232812Sjmallett                break;
686232812Sjmallett            case 3: /* Illegal */
687232812Sjmallett                result.u64 = 0;
688232812Sjmallett                break;
689232812Sjmallett        }
690232812Sjmallett    }
691232812Sjmallett    return result;
692232812Sjmallett}
693232812Sjmallett
694210284Sjmallett/**
695210284Sjmallett * @INTERNAL
696232812Sjmallett * Get link state of broadcom PHY
697232812Sjmallett */
698232812Sjmallettstatic cvmx_helper_link_info_t __get_broadcom_phy_link_state(int phy_addr)
699232812Sjmallett{
700232812Sjmallett    cvmx_helper_link_info_t  result;
701232812Sjmallett    int phy_status;
702232812Sjmallett
703232812Sjmallett    result.u64 = 0;
704232812Sjmallett    /* Below we are going to read SMI/MDIO register 0x19 which works
705232812Sjmallett       on Broadcom parts */
706232812Sjmallett    phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19);
707232812Sjmallett    switch ((phy_status>>8) & 0x7)
708232812Sjmallett    {
709232812Sjmallett        case 0:
710232812Sjmallett            result.u64 = 0;
711232812Sjmallett            break;
712232812Sjmallett        case 1:
713232812Sjmallett            result.s.link_up = 1;
714232812Sjmallett            result.s.full_duplex = 0;
715232812Sjmallett            result.s.speed = 10;
716232812Sjmallett            break;
717232812Sjmallett        case 2:
718232812Sjmallett            result.s.link_up = 1;
719232812Sjmallett            result.s.full_duplex = 1;
720232812Sjmallett            result.s.speed = 10;
721232812Sjmallett            break;
722232812Sjmallett        case 3:
723232812Sjmallett            result.s.link_up = 1;
724232812Sjmallett            result.s.full_duplex = 0;
725232812Sjmallett            result.s.speed = 100;
726232812Sjmallett            break;
727232812Sjmallett        case 4:
728232812Sjmallett            result.s.link_up = 1;
729232812Sjmallett            result.s.full_duplex = 1;
730232812Sjmallett            result.s.speed = 100;
731232812Sjmallett            break;
732232812Sjmallett        case 5:
733232812Sjmallett            result.s.link_up = 1;
734232812Sjmallett            result.s.full_duplex = 1;
735232812Sjmallett            result.s.speed = 100;
736232812Sjmallett            break;
737232812Sjmallett        case 6:
738232812Sjmallett            result.s.link_up = 1;
739232812Sjmallett            result.s.full_duplex = 0;
740232812Sjmallett            result.s.speed = 1000;
741232812Sjmallett            break;
742232812Sjmallett        case 7:
743232812Sjmallett            result.s.link_up = 1;
744232812Sjmallett            result.s.full_duplex = 1;
745232812Sjmallett            result.s.speed = 1000;
746232812Sjmallett            break;
747232812Sjmallett    }
748232812Sjmallett    return result;
749232812Sjmallett}
750232812Sjmallett
751232812Sjmallett
752232812Sjmallett/**
753232812Sjmallett * @INTERNAL
754232812Sjmallett * Get link state using inband status
755232812Sjmallett */
756232812Sjmallettstatic cvmx_helper_link_info_t __get_inband_link_state(int ipd_port)
757232812Sjmallett{
758232812Sjmallett    cvmx_helper_link_info_t  result;
759232812Sjmallett    cvmx_gmxx_rxx_rx_inbnd_t inband_status;
760232812Sjmallett    int interface = cvmx_helper_get_interface_num(ipd_port);
761232812Sjmallett    int index = cvmx_helper_get_interface_index_num(ipd_port);
762232812Sjmallett
763232812Sjmallett    result.u64 = 0;
764232812Sjmallett    inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
765232812Sjmallett    result.s.link_up = inband_status.s.status;
766232812Sjmallett    result.s.full_duplex = inband_status.s.duplex;
767232812Sjmallett    switch (inband_status.s.speed)
768232812Sjmallett    {
769232812Sjmallett        case 0: /* 10 Mbps */
770232812Sjmallett            result.s.speed = 10;
771232812Sjmallett            break;
772232812Sjmallett        case 1: /* 100 Mbps */
773232812Sjmallett            result.s.speed = 100;
774232812Sjmallett            break;
775232812Sjmallett        case 2: /* 1 Gbps */
776232812Sjmallett            result.s.speed = 1000;
777232812Sjmallett            break;
778232812Sjmallett        case 3: /* Illegal */
779232812Sjmallett            result.u64 = 0;
780232812Sjmallett            break;
781232812Sjmallett    }
782232812Sjmallett    return result;
783232812Sjmallett}
784232812Sjmallett
785232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
786232812Sjmallett/**
787232812Sjmallett * @INTERNAL
788232812Sjmallett * Switch MDIO mux to the specified port.
789232812Sjmallett */
790232812Sjmallettstatic int __switch_mdio_mux(int ipd_port)
791232812Sjmallett{
792232812Sjmallett    /* This method is board specific and doesn't use the device tree
793232812Sjmallett       information as SE doesn't implement MDIO MUX abstration */
794232812Sjmallett    switch (cvmx_sysinfo_get()->board_type)
795232812Sjmallett    {
796232812Sjmallett        case CVMX_BOARD_TYPE_EBB5600:
797232812Sjmallett        {
798232812Sjmallett            static unsigned char qlm_switch_addr = 0;
799232812Sjmallett            /* Board has 1 management port */
800232812Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
801232812Sjmallett                return 0;
802232812Sjmallett            /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */
803232812Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
804232812Sjmallett            {
805232812Sjmallett                if (qlm_switch_addr != 0x3)
806232812Sjmallett                {
807232812Sjmallett                    qlm_switch_addr = 0x3;  /* QLM1 */
808232812Sjmallett                    cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
809232812Sjmallett                    cvmx_wait_usec(11000); /* Let the write complete */
810232812Sjmallett                }
811232812Sjmallett                return ipd_port+1 + (1<<8);
812232812Sjmallett            }
813232812Sjmallett            else if ((ipd_port >= 16) && (ipd_port < 20))
814232812Sjmallett            {
815232812Sjmallett                if (qlm_switch_addr != 0xC)
816232812Sjmallett                {
817232812Sjmallett                    qlm_switch_addr = 0xC;  /* QLM3 */
818232812Sjmallett                    cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
819232812Sjmallett                    cvmx_wait_usec(11000); /* Let the write complete */
820232812Sjmallett                }
821232812Sjmallett                return ipd_port-16+1 + (1<<8);
822232812Sjmallett            }
823232812Sjmallett            else
824232812Sjmallett                return -1;
825232812Sjmallett        }
826232812Sjmallett        case CVMX_BOARD_TYPE_EBB6600:
827232812Sjmallett        {
828232812Sjmallett            static unsigned char qlm_switch_addr = 0;
829232812Sjmallett            int old_twsi_switch_reg;
830232812Sjmallett            /* Board has 2 management ports */
831232812Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) &&
832232812Sjmallett                (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
833232812Sjmallett                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
834232812Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */
835232812Sjmallett            {
836232812Sjmallett                if (qlm_switch_addr != 2)
837232812Sjmallett                {
838232812Sjmallett                    int tries;
839232812Sjmallett                    qlm_switch_addr = 2;
840232812Sjmallett                    tries = 3;
841232812Sjmallett                    do {
842232812Sjmallett                        old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0);
843232812Sjmallett                    } while (tries-- > 0 && old_twsi_switch_reg < 0);
844232812Sjmallett                    /* Set I2C MUX to enable port expander */
845232812Sjmallett                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8);
846232812Sjmallett                    /* Set selecter to QLM 1 */
847232812Sjmallett                    cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xff);
848232812Sjmallett                    /* disable port expander */
849232812Sjmallett                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg);
850232812Sjmallett                }
851232812Sjmallett                return 0x101 + ipd_port;
852232812Sjmallett            }
853232812Sjmallett            else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 1 */
854232812Sjmallett            {
855232812Sjmallett                if (qlm_switch_addr != 1)
856232812Sjmallett                {
857232812Sjmallett                    int tries;
858232812Sjmallett                    qlm_switch_addr = 1;
859232812Sjmallett                    tries = 3;
860232812Sjmallett                    do {
861232812Sjmallett                            old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0);
862232812Sjmallett                    } while (tries-- > 0 && old_twsi_switch_reg < 0);
863232812Sjmallett                    /* Set I2C MUX to enable port expander */
864232812Sjmallett                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8);
865232812Sjmallett                    /* Set selecter to QLM 2 */
866232812Sjmallett                    cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xf7);
867232812Sjmallett                    /* disable port expander */
868232812Sjmallett                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg);
869232812Sjmallett                }
870232812Sjmallett                return 0x101 + (ipd_port - 16);
871232812Sjmallett            } else
872232812Sjmallett                return -1;
873232812Sjmallett        }
874232812Sjmallett        case CVMX_BOARD_TYPE_EBB6100:
875232812Sjmallett        {
876232812Sjmallett            static char gpio_configured = 0;
877232812Sjmallett
878232812Sjmallett            if (!gpio_configured)
879232812Sjmallett            {
880232812Sjmallett                cvmx_gpio_cfg(3, 1);
881232812Sjmallett                gpio_configured = 1;
882232812Sjmallett            }
883232812Sjmallett            /* Board has 2 management ports */
884232812Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) &&
885232812Sjmallett                (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
886232812Sjmallett                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
887232812Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */
888232812Sjmallett            {
889232812Sjmallett                cvmx_gpio_set(1ull << 3);
890232812Sjmallett                return 0x101 + ipd_port;
891232812Sjmallett            }
892232812Sjmallett            else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 0 */
893232812Sjmallett            {
894232812Sjmallett                cvmx_gpio_clear(1ull << 3);
895232812Sjmallett                return 0x101 + (ipd_port - 16);
896232812Sjmallett            }
897232812Sjmallett            else
898232812Sjmallett            {
899232812Sjmallett                printf("%s: Unknown ipd port 0x%x\n", __func__, ipd_port);
900232812Sjmallett                return -1;
901232812Sjmallett            }
902232812Sjmallett        }
903232812Sjmallett        default:
904232812Sjmallett        {
905232812Sjmallett            cvmx_dprintf("ERROR : unexpected mdio switch for board=%08x\n",
906232812Sjmallett                         cvmx_sysinfo_get()->board_type);
907232812Sjmallett            return -1;
908232812Sjmallett        }
909232812Sjmallett    }
910232812Sjmallett    /* should never get here */
911232812Sjmallett    return -1;
912232812Sjmallett}
913232812Sjmallett
914232812Sjmallett/**
915232812Sjmallett * @INTERNAL
916232812Sjmallett * This function is used ethernet ports link speed. This functions uses the
917232812Sjmallett * device tree information to determine the phy address and type of PHY.
918232812Sjmallett * The only supproted PHYs are Marvell and Broadcom.
919232812Sjmallett *
920232812Sjmallett * @param ipd_port IPD input port associated with the port we want to get link
921232812Sjmallett *                 status for.
922232812Sjmallett *
923232812Sjmallett * @return The ports link status. If the link isn't fully resolved, this must
924232812Sjmallett *         return zero.
925232812Sjmallett */
926232812Sjmallett
927232812Sjmallettcvmx_helper_link_info_t __cvmx_helper_board_link_get_from_dt(int ipd_port)
928232812Sjmallett{
929232812Sjmallett    cvmx_helper_link_info_t  result;
930232812Sjmallett    cvmx_phy_info_t phy_info;
931232812Sjmallett
932232812Sjmallett    result.u64 = 0;
933232812Sjmallett    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
934232812Sjmallett    {
935232812Sjmallett        /* The simulator gives you a simulated 1Gbps full duplex link */
936232812Sjmallett        result.s.link_up = 1;
937232812Sjmallett        result.s.full_duplex = 1;
938232812Sjmallett        result.s.speed = 1000;
939232812Sjmallett        return result;
940232812Sjmallett    }
941232812Sjmallett    phy_info = __get_phy_info_from_dt(ipd_port);
942232812Sjmallett    //cvmx_dprintf("ipd_port=%d phy_addr=%d dc=%d type=%d \n", ipd_port,
943232812Sjmallett    //             phy_info.phy_addr, phy_info.direct_connect, phy_info.phy_type);
944232812Sjmallett    if (phy_info.phy_addr < 0) return result;
945232812Sjmallett
946232812Sjmallett    if (phy_info.direct_connect == 0)
947232812Sjmallett        __switch_mdio_mux(ipd_port);
948232812Sjmallett    switch(phy_info.phy_type)
949232812Sjmallett    {
950232812Sjmallett        case BROADCOM_GENERIC_PHY:
951232812Sjmallett            result = __get_broadcom_phy_link_state(phy_info.phy_addr);
952232812Sjmallett            break;
953232812Sjmallett        case MARVELL_GENERIC_PHY:
954232812Sjmallett            result = __get_marvell_phy_link_state(phy_info.phy_addr);
955232812Sjmallett            break;
956232812Sjmallett        default:
957232812Sjmallett            result = __get_inband_link_state(ipd_port);
958232812Sjmallett    }
959232812Sjmallett    return result;
960232812Sjmallett
961232812Sjmallett}
962232812Sjmallett#endif
963232812Sjmallett
964232812Sjmallett/**
965232812Sjmallett * @INTERNAL
966232812Sjmallett * This function invokes  __cvmx_helper_board_link_get_from_dt when device tree
967232812Sjmallett * info is available. When the device tree information is not available then
968232812Sjmallett * this function is the board specific method of determining an
969210284Sjmallett * ethernet ports link speed. Most Octeon boards have Marvell PHYs
970210284Sjmallett * and are handled by the fall through case. This function must be
971210284Sjmallett * updated for boards that don't have the normal Marvell PHYs.
972210284Sjmallett *
973210284Sjmallett * This function must be modified for every new Octeon board.
974210284Sjmallett * Internally it uses switch statements based on the cvmx_sysinfo
975210284Sjmallett * data to determine board types and revisions. It relies on the
976210284Sjmallett * fact that every Octeon board receives a unique board type
977210284Sjmallett * enumeration from the bootloader.
978210284Sjmallett *
979210284Sjmallett * @param ipd_port IPD input port associated with the port we want to get link
980210284Sjmallett *                 status for.
981210284Sjmallett *
982210284Sjmallett * @return The ports link status. If the link isn't fully resolved, this must
983210284Sjmallett *         return zero.
984210284Sjmallett */
985210284Sjmallettcvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
986210284Sjmallett{
987210284Sjmallett    cvmx_helper_link_info_t result;
988210284Sjmallett    int phy_addr;
989210284Sjmallett    int is_broadcom_phy = 0;
990210284Sjmallett
991232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
992232812Sjmallett    if (cvmx_sysinfo_get()->fdt_addr)
993232812Sjmallett    {
994232812Sjmallett        return __cvmx_helper_board_link_get_from_dt(ipd_port);
995232812Sjmallett    }
996232812Sjmallett#endif
997232812Sjmallett
998210284Sjmallett    /* Give the user a chance to override the processing of this function */
999210284Sjmallett    if (cvmx_override_board_link_get)
1000210284Sjmallett        return cvmx_override_board_link_get(ipd_port);
1001210284Sjmallett
1002210284Sjmallett    /* Unless we fix it later, all links are defaulted to down */
1003210284Sjmallett    result.u64 = 0;
1004210284Sjmallett
1005210311Sjmallett#if !defined(OCTEON_BOARD_CAPK_0100ND)
1006210284Sjmallett    /* This switch statement should handle all ports that either don't use
1007210284Sjmallett        Marvell PHYS, or don't support in-band status */
1008210284Sjmallett    switch (cvmx_sysinfo_get()->board_type)
1009210284Sjmallett    {
1010210284Sjmallett        case CVMX_BOARD_TYPE_SIM:
1011210284Sjmallett            /* The simulator gives you a simulated 1Gbps full duplex link */
1012210284Sjmallett            result.s.link_up = 1;
1013210284Sjmallett            result.s.full_duplex = 1;
1014210284Sjmallett            result.s.speed = 1000;
1015210284Sjmallett            return result;
1016215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_A:
1017215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_U:
1018215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_G:
1019215990Sjmallett            break;
1020210284Sjmallett        case CVMX_BOARD_TYPE_EBH3100:
1021210284Sjmallett        case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
1022210284Sjmallett        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
1023250428Simp#if !defined(OCTEON_VENDOR_GEFES)
1024210284Sjmallett        case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
1025250428Simp#endif
1026210284Sjmallett            /* Port 1 on these boards is always Gigabit */
1027210284Sjmallett            if (ipd_port == 1)
1028210284Sjmallett            {
1029210284Sjmallett                result.s.link_up = 1;
1030210284Sjmallett                result.s.full_duplex = 1;
1031210284Sjmallett                result.s.speed = 1000;
1032210284Sjmallett                return result;
1033210284Sjmallett            }
1034210284Sjmallett            /* Fall through to the generic code below */
1035210284Sjmallett            break;
1036242423Sjmallett        case CVMX_BOARD_TYPE_EBT5600:
1037215990Sjmallett        case CVMX_BOARD_TYPE_EBH5600:
1038215990Sjmallett        case CVMX_BOARD_TYPE_EBH5601:
1039215990Sjmallett        case CVMX_BOARD_TYPE_EBH5610:
1040215990Sjmallett            /* Board has 1 management ports */
1041215990Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
1042215990Sjmallett                is_broadcom_phy = 1;
1043215990Sjmallett            break;
1044215990Sjmallett        case CVMX_BOARD_TYPE_EBH5200:
1045215990Sjmallett        case CVMX_BOARD_TYPE_EBH5201:
1046215990Sjmallett        case CVMX_BOARD_TYPE_EBT5200:
1047215990Sjmallett            /* Board has 2 management ports */
1048215990Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
1049215990Sjmallett                is_broadcom_phy = 1;
1050215990Sjmallett            break;
1051232812Sjmallett        case CVMX_BOARD_TYPE_EBB6100:
1052215990Sjmallett        case CVMX_BOARD_TYPE_EBB6300:   /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/
1053232812Sjmallett        case CVMX_BOARD_TYPE_EBB6600:   /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/
1054215990Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))
1055215990Sjmallett                && cvmx_helper_board_get_mii_address(ipd_port) >= 0 && cvmx_helper_board_get_mii_address(ipd_port) <= 1)
1056215990Sjmallett                is_broadcom_phy = 1;
1057215990Sjmallett            break;
1058232812Sjmallett        case CVMX_BOARD_TYPE_EP6300C:
1059232812Sjmallett            is_broadcom_phy = 1;
1060232812Sjmallett            break;
1061210284Sjmallett        case CVMX_BOARD_TYPE_CUST_NB5:
1062210284Sjmallett            /* Port 1 on these boards is always Gigabit */
1063210284Sjmallett            if (ipd_port == 1)
1064210284Sjmallett            {
1065210284Sjmallett                result.s.link_up = 1;
1066210284Sjmallett                result.s.full_duplex = 1;
1067210284Sjmallett                result.s.speed = 1000;
1068210284Sjmallett                return result;
1069210284Sjmallett            }
1070210284Sjmallett            else /* The other port uses a broadcom PHY */
1071210284Sjmallett                is_broadcom_phy = 1;
1072210284Sjmallett            break;
1073210284Sjmallett        case CVMX_BOARD_TYPE_BBGW_REF:
1074210284Sjmallett            /* Port 1 on these boards is always Gigabit */
1075210284Sjmallett            if (ipd_port == 2)
1076215990Sjmallett            {
1077210284Sjmallett                /* Port 2 is not hooked up */
1078210284Sjmallett                result.u64 = 0;
1079210284Sjmallett                return result;
1080210284Sjmallett            }
1081210284Sjmallett            else
1082210284Sjmallett            {
1083210284Sjmallett                /* Ports 0 and 1 connect to the switch */
1084210284Sjmallett                result.s.link_up = 1;
1085210284Sjmallett                result.s.full_duplex = 1;
1086210284Sjmallett                result.s.speed = 1000;
1087210284Sjmallett                return result;
1088210284Sjmallett            }
1089232812Sjmallett        case CVMX_BOARD_TYPE_NIC4E:
1090232812Sjmallett        case CVMX_BOARD_TYPE_NIC2E:
1091232812Sjmallett            is_broadcom_phy = 1;
1092210284Sjmallett            break;
1093210311Sjmallett	/* Private vendor-defined boards.  */
1094210311Sjmallett#if defined(OCTEON_VENDOR_LANNER)
1095215014Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
1096215014Sjmallett	    /* Ports are BCM5482S */
1097215014Sjmallett	    is_broadcom_phy = 1;
1098215014Sjmallett	    break;
1099210311Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
1100216476Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
1101210311Sjmallett	    /* Port 0 connects to the switch */
1102210311Sjmallett	    if (ipd_port == 0)
1103210311Sjmallett	    {
1104210311Sjmallett                result.s.link_up = 1;
1105210311Sjmallett                result.s.full_duplex = 1;
1106210311Sjmallett                result.s.speed = 1000;
1107210311Sjmallett		return result;
1108210311Sjmallett	    }
1109210311Sjmallett	    break;
1110210311Sjmallett#endif
1111250428Simp#if defined(OCTEON_VENDOR_GEFES)
1112250428Simp	case CVMX_BOARD_TYPE_CUST_TNPA5651X:
1113250428Simp	   /* Since we don't auto-negotiate... 1Gbps full duplex link */
1114250428Simp	   result.s.link_up = 1;
1115250428Simp	   result.s.full_duplex = 1;
1116250428Simp	   result.s.speed = 1000;
1117250428Simp	   return result;
1118250428Simp	   break;
1119250428Simp#endif
1120210284Sjmallett    }
1121210311Sjmallett#endif
1122210284Sjmallett
1123210284Sjmallett    phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
1124232812Sjmallett    //cvmx_dprintf("ipd_port=%d phy_addr=%d broadcom=%d\n",
1125232812Sjmallett    //             ipd_port, phy_addr, is_broadcom_phy);
1126210284Sjmallett    if (phy_addr != -1)
1127210284Sjmallett    {
1128210284Sjmallett        if (is_broadcom_phy)
1129210284Sjmallett        {
1130232812Sjmallett            result =  __get_broadcom_phy_link_state(phy_addr);
1131210284Sjmallett        }
1132210284Sjmallett        else
1133210284Sjmallett        {
1134232812Sjmallett            /* This code assumes we are using a Marvell Gigabit PHY. */
1135232812Sjmallett            result = __get_marvell_phy_link_state(phy_addr);
1136210284Sjmallett        }
1137210284Sjmallett    }
1138232812Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX)
1139232812Sjmallett             || OCTEON_IS_MODEL(OCTEON_CN50XX))
1140210284Sjmallett    {
1141210284Sjmallett        /* We don't have a PHY address, so attempt to use in-band status. It is
1142210284Sjmallett            really important that boards not supporting in-band status never get
1143210284Sjmallett            here. Reading broken in-band status tends to do bad things */
1144232812Sjmallett        result = __get_inband_link_state(ipd_port);
1145210284Sjmallett    }
1146250428Simp#if defined(OCTEON_VENDOR_GEFES)
1147250428Simp    else if( (OCTEON_IS_MODEL(OCTEON_CN56XX)) || (OCTEON_IS_MODEL(OCTEON_CN63XX)) )
1148250428Simp    {
1149250428Simp        int interface = cvmx_helper_get_interface_num(ipd_port);
1150250428Simp        int index = cvmx_helper_get_interface_index_num(ipd_port);
1151250428Simp        cvmx_pcsx_miscx_ctl_reg_t mode_type;
1152250428Simp        cvmx_pcsx_mrx_status_reg_t mrx_status;
1153250428Simp        cvmx_pcsx_anx_adv_reg_t anxx_adv;
1154250428Simp        cvmx_pcsx_sgmx_lp_adv_reg_t sgmii_inband_status;
1155250428Simp
1156250428Simp        anxx_adv.u64 = cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface));
1157250428Simp        mrx_status.u64 = cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG(index, interface));
1158250428Simp
1159250428Simp        mode_type.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
1160250428Simp
1161250428Simp        /* Read Octeon's inband status */
1162250428Simp        sgmii_inband_status.u64 = cvmx_read_csr(CVMX_PCSX_SGMX_LP_ADV_REG(index, interface));
1163250428Simp
1164250428Simp        result.s.link_up = sgmii_inband_status.s.link;
1165250428Simp        result.s.full_duplex = sgmii_inband_status.s.dup;
1166250428Simp        switch (sgmii_inband_status.s.speed)
1167250428Simp        {
1168250428Simp        case 0: /* 10 Mbps */
1169250428Simp            result.s.speed = 10;
1170250428Simp            break;
1171250428Simp        case 1: /* 100 Mbps */
1172250428Simp            result.s.speed = 100;
1173250428Simp            break;
1174250428Simp        case 2: /* 1 Gbps */
1175250428Simp            result.s.speed = 1000;
1176250428Simp            break;
1177250428Simp        case 3: /* Illegal */
1178250428Simp            result.s.speed = 0;
1179250428Simp            result.s.link_up = 0;
1180250428Simp            break;
1181250428Simp        }
1182250428Simp    }
1183250428Simp#endif
1184210284Sjmallett    else
1185210284Sjmallett    {
1186210284Sjmallett        /* We don't have a PHY address and we don't have in-band status. There
1187210284Sjmallett            is no way to determine the link speed. Return down assuming this
1188210284Sjmallett            port isn't wired */
1189210284Sjmallett        result.u64 = 0;
1190210284Sjmallett    }
1191210284Sjmallett
1192210284Sjmallett    /* If link is down, return all fields as zero. */
1193210284Sjmallett    if (!result.s.link_up)
1194210284Sjmallett        result.u64 = 0;
1195210284Sjmallett
1196210284Sjmallett    return result;
1197210284Sjmallett}
1198210284Sjmallett
1199210284Sjmallett
1200210284Sjmallett/**
1201210284Sjmallett * This function as a board specific method of changing the PHY
1202215990Sjmallett * speed, duplex, and autonegotiation. This programs the PHY and
1203210284Sjmallett * not Octeon. This can be used to force Octeon's links to
1204210284Sjmallett * specific settings.
1205210284Sjmallett *
1206210284Sjmallett * @param phy_addr  The address of the PHY to program
1207215990Sjmallett * @param link_flags
1208215990Sjmallett *                  Flags to control autonegotiation.  Bit 0 is autonegotiation
1209215990Sjmallett *                  enable/disable to maintain backward compatibility.
1210215990Sjmallett * @param link_info Link speed to program. If the speed is zero and autonegotiation
1211210284Sjmallett *                  is enabled, all possible negotiation speeds are advertised.
1212210284Sjmallett *
1213210284Sjmallett * @return Zero on success, negative on failure
1214210284Sjmallett */
1215210284Sjmallettint cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags,
1216210284Sjmallett                                   cvmx_helper_link_info_t link_info)
1217210284Sjmallett{
1218210284Sjmallett
1219210284Sjmallett    /* Set the flow control settings based on link_flags */
1220210284Sjmallett    if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch)
1221210284Sjmallett    {
1222210284Sjmallett        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1223210284Sjmallett        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1224210284Sjmallett        reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
1225210284Sjmallett        reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
1226210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1227210284Sjmallett    }
1228210284Sjmallett
1229210284Sjmallett    /* If speed isn't set and autoneg is on advertise all supported modes */
1230210284Sjmallett    if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0))
1231210284Sjmallett    {
1232210284Sjmallett        cvmx_mdio_phy_reg_control_t reg_control;
1233210284Sjmallett        cvmx_mdio_phy_reg_status_t reg_status;
1234210284Sjmallett        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1235210284Sjmallett        cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
1236210284Sjmallett        cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
1237210284Sjmallett
1238210284Sjmallett        reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
1239210284Sjmallett        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1240210284Sjmallett        reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4;
1241210284Sjmallett        reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full;
1242210284Sjmallett        reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half;
1243210284Sjmallett        reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full;
1244210284Sjmallett        reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half;
1245210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1246210284Sjmallett        if (reg_status.s.capable_extended_status)
1247210284Sjmallett        {
1248210284Sjmallett            reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
1249210284Sjmallett            reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
1250210284Sjmallett            reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full;
1251210284Sjmallett            reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half;
1252210284Sjmallett            cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
1253210284Sjmallett        }
1254210284Sjmallett        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1255210284Sjmallett        reg_control.s.autoneg_enable = 1;
1256210284Sjmallett        reg_control.s.restart_autoneg = 1;
1257210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1258210284Sjmallett    }
1259210284Sjmallett    else if ((link_flags & set_phy_link_flags_autoneg))
1260210284Sjmallett    {
1261210284Sjmallett        cvmx_mdio_phy_reg_control_t reg_control;
1262210284Sjmallett        cvmx_mdio_phy_reg_status_t reg_status;
1263210284Sjmallett        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1264210284Sjmallett        cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
1265210284Sjmallett
1266210284Sjmallett        reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
1267210284Sjmallett        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1268210284Sjmallett        reg_autoneg_adver.s.advert_100base_t4 = 0;
1269210284Sjmallett        reg_autoneg_adver.s.advert_10base_tx_full = 0;
1270210284Sjmallett        reg_autoneg_adver.s.advert_10base_tx_half = 0;
1271210284Sjmallett        reg_autoneg_adver.s.advert_100base_tx_full = 0;
1272210284Sjmallett        reg_autoneg_adver.s.advert_100base_tx_half = 0;
1273210284Sjmallett        if (reg_status.s.capable_extended_status)
1274210284Sjmallett        {
1275210284Sjmallett            reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
1276210284Sjmallett            reg_control_1000.s.advert_1000base_t_full = 0;
1277210284Sjmallett            reg_control_1000.s.advert_1000base_t_half = 0;
1278210284Sjmallett        }
1279210284Sjmallett        switch (link_info.s.speed)
1280210284Sjmallett        {
1281210284Sjmallett            case 10:
1282210284Sjmallett                reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex;
1283210284Sjmallett                reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex;
1284210284Sjmallett                break;
1285210284Sjmallett            case 100:
1286210284Sjmallett                reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex;
1287210284Sjmallett                reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex;
1288210284Sjmallett                break;
1289210284Sjmallett            case 1000:
1290210284Sjmallett                reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex;
1291210284Sjmallett                reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex;
1292210284Sjmallett                break;
1293210284Sjmallett        }
1294210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1295210284Sjmallett        if (reg_status.s.capable_extended_status)
1296210284Sjmallett            cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
1297210284Sjmallett        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1298210284Sjmallett        reg_control.s.autoneg_enable = 1;
1299210284Sjmallett        reg_control.s.restart_autoneg = 1;
1300210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1301210284Sjmallett    }
1302210284Sjmallett    else
1303210284Sjmallett    {
1304210284Sjmallett        cvmx_mdio_phy_reg_control_t reg_control;
1305210284Sjmallett        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1306210284Sjmallett        reg_control.s.autoneg_enable = 0;
1307210284Sjmallett        reg_control.s.restart_autoneg = 1;
1308210284Sjmallett        reg_control.s.duplex = link_info.s.full_duplex;
1309210284Sjmallett        if (link_info.s.speed == 1000)
1310210284Sjmallett        {
1311210284Sjmallett            reg_control.s.speed_msb = 1;
1312210284Sjmallett            reg_control.s.speed_lsb = 0;
1313210284Sjmallett        }
1314210284Sjmallett        else if (link_info.s.speed == 100)
1315210284Sjmallett        {
1316210284Sjmallett            reg_control.s.speed_msb = 0;
1317210284Sjmallett            reg_control.s.speed_lsb = 1;
1318210284Sjmallett        }
1319210284Sjmallett        else if (link_info.s.speed == 10)
1320210284Sjmallett        {
1321210284Sjmallett            reg_control.s.speed_msb = 0;
1322210284Sjmallett            reg_control.s.speed_lsb = 0;
1323210284Sjmallett        }
1324210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1325210284Sjmallett    }
1326210284Sjmallett    return 0;
1327210284Sjmallett}
1328210284Sjmallett
1329210284Sjmallett
1330210284Sjmallett/**
1331210284Sjmallett * @INTERNAL
1332210284Sjmallett * This function is called by cvmx_helper_interface_probe() after it
1333210284Sjmallett * determines the number of ports Octeon can support on a specific
1334210284Sjmallett * interface. This function is the per board location to override
1335210284Sjmallett * this value. It is called with the number of ports Octeon might
1336210284Sjmallett * support and should return the number of actual ports on the
1337210284Sjmallett * board.
1338210284Sjmallett *
1339215990Sjmallett * This function must be modified for every new Octeon board.
1340210284Sjmallett * Internally it uses switch statements based on the cvmx_sysinfo
1341215990Sjmallett * data to determine board types and revisions. It relies on the
1342210284Sjmallett * fact that every Octeon board receives a unique board type
1343210284Sjmallett * enumeration from the bootloader.
1344210284Sjmallett *
1345210284Sjmallett * @param interface Interface to probe
1346210284Sjmallett * @param supported_ports
1347210284Sjmallett *                  Number of ports Octeon supports.
1348210284Sjmallett *
1349210284Sjmallett * @return Number of ports the actual board supports. Many times this will
1350210284Sjmallett *         simple be "support_ports".
1351210284Sjmallett */
1352210284Sjmallettint __cvmx_helper_board_interface_probe(int interface, int supported_ports)
1353210284Sjmallett{
1354210284Sjmallett    switch (cvmx_sysinfo_get()->board_type)
1355210284Sjmallett    {
1356210284Sjmallett        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
1357215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_A:
1358215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_U:
1359215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_G:
1360210284Sjmallett            if (interface == 0)
1361210284Sjmallett                return 2;
1362210284Sjmallett	    break;
1363210284Sjmallett        case CVMX_BOARD_TYPE_BBGW_REF:
1364210284Sjmallett            if (interface == 0)
1365210284Sjmallett                return 2;
1366210284Sjmallett	    break;
1367210284Sjmallett        case CVMX_BOARD_TYPE_NIC_XLE_4G:
1368210284Sjmallett            if (interface == 0)
1369210284Sjmallett                return 0;
1370210284Sjmallett	    break;
1371210284Sjmallett        /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
1372210284Sjmallett            which we don't support. Disable ports connected to it */
1373210284Sjmallett        case CVMX_BOARD_TYPE_EBH5600:
1374210284Sjmallett            if (interface == 1)
1375210284Sjmallett                return 0;
1376210284Sjmallett	    break;
1377215990Sjmallett        case CVMX_BOARD_TYPE_EBB5600:
1378215990Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
1379215990Sjmallett            if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_PICMG)
1380215990Sjmallett                return 0;
1381215990Sjmallett#endif
1382215990Sjmallett	    break;
1383242423Sjmallett        case CVMX_BOARD_TYPE_EBT5600:
1384242423Sjmallett	    /* Disable loopback.  */
1385242423Sjmallett	    if (interface == 3)
1386242423Sjmallett		return 0;
1387242423Sjmallett	    break;
1388215990Sjmallett        case CVMX_BOARD_TYPE_EBT5810:
1389215990Sjmallett            return 1;  /* Two ports on each SPI: 1 hooked to MAC, 1 loopback
1390215990Sjmallett                       ** Loopback disabled by default. */
1391232812Sjmallett        case CVMX_BOARD_TYPE_NIC2E:
1392232812Sjmallett            if (interface == 0)
1393232812Sjmallett                return 2;
1394212844Sjmallett#if defined(OCTEON_VENDOR_LANNER)
1395212844Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
1396212844Sjmallett	    if (interface == 1)
1397212844Sjmallett	        return 12;
1398212844Sjmallett	    break;
1399212844Sjmallett#endif
1400250428Simp#if defined(OCTEON_VENDOR_GEFES)
1401250428Simp        case CVMX_BOARD_TYPE_CUST_TNPA5651X:
1402250428Simp                if (interface < 2) /* interface can be EITHER 0 or 1 */
1403250428Simp			return 1;//always return 1 for XAUI and SGMII mode.
1404250428Simp		break;
1405250428Simp        case CVMX_BOARD_TYPE_CUST_TNPA56X4:
1406250428Simp		if ((interface == 0) &&
1407250428Simp			(cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_SGMII))
1408250428Simp		{
1409250428Simp			cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
1410250428Simp
1411250428Simp			/* For this port we need to set the mode to 1000BaseX */
1412250428Simp			pcsx_miscx_ctl_reg.u64 =
1413250428Simp				cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(0, interface));
1414250428Simp			pcsx_miscx_ctl_reg.cn56xx.mode = 1;
1415250428Simp			cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(0, interface),
1416250428Simp						   pcsx_miscx_ctl_reg.u64);
1417250428Simp			pcsx_miscx_ctl_reg.u64 =
1418250428Simp				cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(1, interface));
1419250428Simp			pcsx_miscx_ctl_reg.cn56xx.mode = 1;
1420250428Simp			cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(1, interface),
1421250428Simp						   pcsx_miscx_ctl_reg.u64);
1422250428Simp
1423250428Simp			return 2;
1424250428Simp		}
1425250428Simp		break;
1426250428Simp#endif
1427210284Sjmallett    }
1428210284Sjmallett#ifdef CVMX_BUILD_FOR_UBOOT
1429210284Sjmallett    if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi"))
1430210284Sjmallett        return 0;
1431210284Sjmallett#endif
1432210284Sjmallett    return supported_ports;
1433210284Sjmallett}
1434210284Sjmallett
1435210284Sjmallett
1436210284Sjmallett/**
1437210284Sjmallett * @INTERNAL
1438210284Sjmallett * Enable packet input/output from the hardware. This function is
1439210284Sjmallett * called after by cvmx_helper_packet_hardware_enable() to
1440210284Sjmallett * perform board specific initialization. For most boards
1441210284Sjmallett * nothing is needed.
1442210284Sjmallett *
1443210284Sjmallett * @param interface Interface to enable
1444210284Sjmallett *
1445210284Sjmallett * @return Zero on success, negative on failure
1446210284Sjmallett */
1447210284Sjmallettint __cvmx_helper_board_hardware_enable(int interface)
1448210284Sjmallett{
1449210284Sjmallett    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5)
1450210284Sjmallett    {
1451210284Sjmallett        if (interface == 0)
1452210284Sjmallett        {
1453210284Sjmallett            /* Different config for switch port */
1454210284Sjmallett            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
1455210284Sjmallett            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
1456210284Sjmallett            /* Boards with gigabit WAN ports need a different setting that is
1457210284Sjmallett                compatible with 100 Mbit settings */
1458210284Sjmallett            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc);
1459210284Sjmallett            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc);
1460210284Sjmallett        }
1461210284Sjmallett    }
1462215990Sjmallett    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_LANAI2_U)
1463215990Sjmallett    {
1464215990Sjmallett        if (interface == 0)
1465215990Sjmallett        {
1466215990Sjmallett            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 16);
1467215990Sjmallett            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 16);
1468215990Sjmallett        }
1469215990Sjmallett    }
1470210284Sjmallett    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5)
1471210284Sjmallett    {
1472215990Sjmallett        /* Broadcom PHYs require different ASX clocks. Unfortunately
1473210284Sjmallett            many customer don't define a new board Id and simply
1474210284Sjmallett            mangle the CN3010_EVB_HS5 */
1475210284Sjmallett        if (interface == 0)
1476210284Sjmallett        {
1477210284Sjmallett            /* Some customers boards use a hacked up bootloader that identifies them as
1478210284Sjmallett            ** CN3010_EVB_HS5 evaluation boards.  This leads to all kinds of configuration
1479210284Sjmallett            ** problems.  Detect one case, and print warning, while trying to do the right thing.
1480210284Sjmallett            */
1481210284Sjmallett            int phy_addr = cvmx_helper_board_get_mii_address(0);
1482210284Sjmallett            if (phy_addr != -1)
1483210284Sjmallett            {
1484210284Sjmallett                int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2);
1485210284Sjmallett                /* Is it a Broadcom PHY? */
1486210284Sjmallett                if (phy_identifier == 0x0143)
1487210284Sjmallett                {
1488210284Sjmallett                    cvmx_dprintf("\n");
1489210284Sjmallett                    cvmx_dprintf("ERROR:\n");
1490210284Sjmallett                    cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
1491210284Sjmallett                    cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
1492210284Sjmallett                    cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n");
1493210284Sjmallett                    cvmx_dprintf("ERROR:\n");
1494210284Sjmallett                    cvmx_dprintf("\n");
1495210284Sjmallett                    cvmx_wait(1000000000);
1496210284Sjmallett                    cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5);
1497210284Sjmallett                    cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5);
1498210284Sjmallett                }
1499210284Sjmallett            }
1500210284Sjmallett        }
1501210284Sjmallett    }
1502245712Sjmallett#if defined(OCTEON_VENDOR_UBIQUITI)
1503320073Sjhibbits    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_UBIQUITI_E100 ||
1504320073Sjhibbits        cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_UBIQUITI_USG)
1505245712Sjmallett    {
1506245712Sjmallett	/* Configure ASX cloks for all ports on interface 0.  */
1507245712Sjmallett	if (interface == 0)
1508245712Sjmallett	{
1509245712Sjmallett	    int port;
1510245712Sjmallett
1511245712Sjmallett	    for (port = 0; port < 3; port++) {
1512245712Sjmallett                cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 16);
1513245712Sjmallett                cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 0);
1514245712Sjmallett	    }
1515245712Sjmallett	}
1516245712Sjmallett    }
1517245712Sjmallett#endif
1518210284Sjmallett    return 0;
1519210284Sjmallett}
1520210284Sjmallett
1521215990Sjmallett
1522215990Sjmallett/**
1523215990Sjmallett * @INTERNAL
1524215990Sjmallett * Gets the clock type used for the USB block based on board type.
1525215990Sjmallett * Used by the USB code for auto configuration of clock type.
1526215990Sjmallett *
1527215990Sjmallett * @return USB clock type enumeration
1528215990Sjmallett */
1529210284Sjmallettcvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void)
1530210284Sjmallett{
1531232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
1532232812Sjmallett    const void *fdt_addr = CASTPTR(const void *, cvmx_sysinfo_get()->fdt_addr);
1533232812Sjmallett    int nodeoffset;
1534232812Sjmallett    const void *nodep;
1535232812Sjmallett    int len;
1536232812Sjmallett    uint32_t speed = 0;
1537232812Sjmallett    const char *type = NULL;
1538232812Sjmallett
1539232812Sjmallett    if (fdt_addr)
1540232812Sjmallett    {
1541232812Sjmallett        nodeoffset = fdt_path_offset(fdt_addr, "/soc/uctl");
1542232812Sjmallett        if (nodeoffset < 0)
1543232812Sjmallett            nodeoffset = fdt_path_offset(fdt_addr, "/soc/usbn");
1544232812Sjmallett
1545232812Sjmallett        if (nodeoffset >= 0)
1546232812Sjmallett        {
1547232812Sjmallett            nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-type", &len);
1548232812Sjmallett            if (nodep != NULL && len > 0)
1549232812Sjmallett                type = (const char *)nodep;
1550232812Sjmallett            else
1551232812Sjmallett                type = "unknown";
1552232812Sjmallett            nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-frequency", &len);
1553232812Sjmallett            if (nodep != NULL && len == sizeof(uint32_t))
1554232812Sjmallett                speed = fdt32_to_cpu(*(int *)nodep);
1555232812Sjmallett            else
1556232812Sjmallett                speed = 0;
1557232812Sjmallett            if (!strcmp(type, "crystal"))
1558232812Sjmallett            {
1559232812Sjmallett                if (speed == 0 || speed == 12000000)
1560232812Sjmallett                    return USB_CLOCK_TYPE_CRYSTAL_12;
1561232812Sjmallett                else
1562232812Sjmallett                    printf("Warning: invalid crystal speed for USB clock type in FDT\n");
1563232812Sjmallett            }
1564232812Sjmallett            else if (!strcmp(type, "external"))
1565232812Sjmallett            {
1566232812Sjmallett                switch (speed) {
1567232812Sjmallett                case 12000000:
1568232812Sjmallett                    return USB_CLOCK_TYPE_REF_12;
1569232812Sjmallett                case 24000000:
1570232812Sjmallett                    return USB_CLOCK_TYPE_REF_24;
1571232812Sjmallett                case 0:
1572232812Sjmallett                case 48000000:
1573232812Sjmallett                    return USB_CLOCK_TYPE_REF_48;
1574232812Sjmallett                default:
1575232812Sjmallett                    printf("Warning: invalid USB clock speed of %u hz in FDT\n", speed);
1576232812Sjmallett                }
1577232812Sjmallett            }
1578232812Sjmallett            else
1579232812Sjmallett                printf("Warning: invalid USB reference clock type \"%s\" in FDT\n", type ? type : "NULL");
1580232812Sjmallett        }
1581232812Sjmallett    }
1582232812Sjmallett#endif
1583215990Sjmallett    switch (cvmx_sysinfo_get()->board_type)
1584215990Sjmallett    {
1585215990Sjmallett        case CVMX_BOARD_TYPE_BBGW_REF:
1586215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_A:
1587215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_U:
1588215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_G:
1589210311Sjmallett#if defined(OCTEON_VENDOR_LANNER)
1590250428Simp        case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
1591250428Simp        case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
1592210311Sjmallett#endif
1593244985Sjmallett#if defined(OCTEON_VENDOR_UBIQUITI)
1594250428Simp        case CVMX_BOARD_TYPE_CUST_UBIQUITI_E100:
1595320073Sjhibbits        case CVMX_BOARD_TYPE_CUST_UBIQUITI_USG:
1596244985Sjmallett#endif
1597229070Sgonzo#if defined(OCTEON_BOARD_CAPK_0100ND)
1598229070Sgonzo	case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
1599229070Sgonzo#endif
1600250428Simp#if defined(OCTEON_VENDOR_GEFES) /* All GEFES' boards use same xtal type */
1601250428Simp        case CVMX_BOARD_TYPE_TNPA3804:
1602250428Simp        case CVMX_BOARD_TYPE_AT5810:
1603250428Simp        case CVMX_BOARD_TYPE_WNPA3850:
1604250428Simp        case CVMX_BOARD_TYPE_W3860:
1605250428Simp        case CVMX_BOARD_TYPE_CUST_TNPA5804:
1606250428Simp        case CVMX_BOARD_TYPE_CUST_W5434:
1607250428Simp        case CVMX_BOARD_TYPE_CUST_W5650:
1608250428Simp        case CVMX_BOARD_TYPE_CUST_W5800:
1609250428Simp        case CVMX_BOARD_TYPE_CUST_W5651X:
1610250428Simp        case CVMX_BOARD_TYPE_CUST_TNPA5651X:
1611250428Simp        case CVMX_BOARD_TYPE_CUST_TNPA56X4:
1612250428Simp        case CVMX_BOARD_TYPE_CUST_W63XX:
1613250428Simp#endif
1614232812Sjmallett        case CVMX_BOARD_TYPE_NIC10E_66:
1615210284Sjmallett            return USB_CLOCK_TYPE_CRYSTAL_12;
1616232812Sjmallett        case CVMX_BOARD_TYPE_NIC10E:
1617232812Sjmallett            return USB_CLOCK_TYPE_REF_12;
1618232812Sjmallett        default:
1619232812Sjmallett            break;
1620210284Sjmallett    }
1621232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN6XXX)	/* Most boards except NIC10e use a 12MHz crystal */
1622232812Sjmallett        || OCTEON_IS_MODEL(OCTEON_CNF7XXX))
1623232812Sjmallett        return USB_CLOCK_TYPE_CRYSTAL_12;
1624210284Sjmallett    return USB_CLOCK_TYPE_REF_48;
1625210284Sjmallett}
1626210284Sjmallett
1627215990Sjmallett
1628215990Sjmallett/**
1629215990Sjmallett * @INTERNAL
1630215990Sjmallett * Adjusts the number of available USB ports on Octeon based on board
1631215990Sjmallett * specifics.
1632215990Sjmallett *
1633215990Sjmallett * @param supported_ports expected number of ports based on chip type;
1634215990Sjmallett *
1635215990Sjmallett *
1636215990Sjmallett * @return number of available usb ports, based on board specifics.
1637215990Sjmallett *         Return value is supported_ports if function does not
1638215990Sjmallett *         override.
1639215990Sjmallett */
1640210284Sjmallettint __cvmx_helper_board_usb_get_num_ports(int supported_ports)
1641210284Sjmallett{
1642215990Sjmallett    switch (cvmx_sysinfo_get()->board_type)
1643215990Sjmallett    {
1644210284Sjmallett        case CVMX_BOARD_TYPE_NIC_XLE_4G:
1645232812Sjmallett        case CVMX_BOARD_TYPE_NIC2E:
1646210284Sjmallett            return 0;
1647210284Sjmallett    }
1648210284Sjmallett
1649210284Sjmallett    return supported_ports;
1650210284Sjmallett}
1651210284Sjmallett
1652210284Sjmallett
1653