cvmx-helper-board.c revision 244984
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;
388210284Sjmallett        case CVMX_BOARD_TYPE_EBT3000:
389210284Sjmallett        case CVMX_BOARD_TYPE_EBT5800:
390210284Sjmallett        case CVMX_BOARD_TYPE_THUNDER:
391210284Sjmallett        case CVMX_BOARD_TYPE_NICPRO2:
392210284Sjmallett            /* Interface 0 is SPI4, interface 1 is RGMII */
393210284Sjmallett            if ((ipd_port >= 16) && (ipd_port < 20))
394210284Sjmallett                return ipd_port - 16;
395210284Sjmallett            else
396210284Sjmallett                return -1;
397215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_A:
398215990Sjmallett            if (ipd_port == 0)
399215990Sjmallett                return 0;
400215990Sjmallett            else
401215990Sjmallett                return -1;
402215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_U:
403215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_G:
404215990Sjmallett            if (ipd_port == 0)
405215990Sjmallett                return 0x1c;
406215990Sjmallett            else
407215990Sjmallett                return -1;
408210284Sjmallett        case CVMX_BOARD_TYPE_KODAMA:
409210284Sjmallett        case CVMX_BOARD_TYPE_EBH3100:
410210284Sjmallett        case CVMX_BOARD_TYPE_HIKARI:
411210284Sjmallett        case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
412210284Sjmallett        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
413210284Sjmallett        case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
414210284Sjmallett            /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a
415210284Sjmallett                switch */
416210284Sjmallett            if (ipd_port == 0)
417210284Sjmallett                return 4;
418210284Sjmallett            else if (ipd_port == 1)
419210284Sjmallett                return 9;
420210284Sjmallett            else
421210284Sjmallett                return -1;
422210284Sjmallett        case CVMX_BOARD_TYPE_EBH3000:
423210284Sjmallett            /* Board has dual SPI4 and no PHYs */
424210284Sjmallett            return -1;
425215990Sjmallett        case CVMX_BOARD_TYPE_EBT5810:
426215990Sjmallett            /* Board has 10g PHYs hooked up to the MII controller on the
427215990Sjmallett            ** IXF18201 MAC.  The 10G PHYS use clause 45 MDIO which the CN58XX
428215990Sjmallett            ** does not support. All MII accesses go through the IXF part. */
429215990Sjmallett            return -1;
430210284Sjmallett        case CVMX_BOARD_TYPE_EBH5200:
431210284Sjmallett        case CVMX_BOARD_TYPE_EBH5201:
432210284Sjmallett        case CVMX_BOARD_TYPE_EBT5200:
433215990Sjmallett            /* Board has 2 management ports */
434215990Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
435215990Sjmallett                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
436210284Sjmallett            /* Board has 4 SGMII ports. The PHYs start right after the MII
437210284Sjmallett                ports MII0 = 0, MII1 = 1, SGMII = 2-5 */
438210284Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
439210284Sjmallett                return ipd_port+2;
440210284Sjmallett            else
441210284Sjmallett                return -1;
442210284Sjmallett        case CVMX_BOARD_TYPE_EBH5600:
443210284Sjmallett        case CVMX_BOARD_TYPE_EBH5601:
444215990Sjmallett        case CVMX_BOARD_TYPE_EBH5610:
445215990Sjmallett            /* Board has 1 management port */
446215990Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
447215990Sjmallett                return 0;
448210284Sjmallett            /* Board has 8 SGMII ports. 4 connect out, two connect to a switch,
449210284Sjmallett                and 2 loop to each other */
450210284Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
451210284Sjmallett                return ipd_port+1;
452210284Sjmallett            else
453210284Sjmallett                return -1;
454242423Sjmallett        case CVMX_BOARD_TYPE_EBT5600:
455242423Sjmallett	    /* Board has 1 management port */
456242423Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
457242423Sjmallett                return 0;
458242423Sjmallett	    /* Board has 1 XAUI port connected to a switch.  */
459242423Sjmallett	    return -1;
460215990Sjmallett        case CVMX_BOARD_TYPE_EBB5600:
461215990Sjmallett            {
462215990Sjmallett                static unsigned char qlm_switch_addr = 0;
463215990Sjmallett
464215990Sjmallett                /* Board has 1 management port */
465215990Sjmallett                if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
466215990Sjmallett                    return 0;
467215990Sjmallett
468215990Sjmallett                /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */
469215990Sjmallett                if ((ipd_port >= 0) && (ipd_port < 4))
470215990Sjmallett                {
471215990Sjmallett                    if (qlm_switch_addr != 0x3)
472215990Sjmallett                    {
473215990Sjmallett                        qlm_switch_addr = 0x3;  /* QLM1 */
474215990Sjmallett                        cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
475215990Sjmallett                        cvmx_wait_usec(11000); /* Let the write complete */
476215990Sjmallett                    }
477215990Sjmallett                    return ipd_port+1 + (1<<8);
478215990Sjmallett                }
479215990Sjmallett                else if ((ipd_port >= 16) && (ipd_port < 20))
480215990Sjmallett                {
481215990Sjmallett                    if (qlm_switch_addr != 0xC)
482215990Sjmallett                    {
483215990Sjmallett                        qlm_switch_addr = 0xC;  /* QLM3 */
484215990Sjmallett                        cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
485215990Sjmallett                        cvmx_wait_usec(11000); /* Let the write complete */
486215990Sjmallett                    }
487215990Sjmallett                    return ipd_port-16+1 + (1<<8);
488215990Sjmallett                }
489215990Sjmallett                else
490215990Sjmallett                    return -1;
491215990Sjmallett            }
492215990Sjmallett        case CVMX_BOARD_TYPE_EBB6300:
493215990Sjmallett            /* Board has 2 management ports */
494215990Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
495215990Sjmallett                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
496215990Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
497215990Sjmallett                return ipd_port + 1 + (1<<8);
498215990Sjmallett            else
499215990Sjmallett                return -1;
500232812Sjmallett        case CVMX_BOARD_TYPE_EBB6800:
501232812Sjmallett            /* Board has 1 management ports */
502232812Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
503232812Sjmallett                return 6;
504232812Sjmallett            if (ipd_port >= 0x800 && ipd_port < 0x900) /* QLM 0*/
505232812Sjmallett                return 0x101 + ((ipd_port >> 4) & 3); /* SMI 1*/
506232812Sjmallett            if (ipd_port >= 0xa00 && ipd_port < 0xb00) /* QLM 2*/
507232812Sjmallett                return 0x201 + ((ipd_port >> 4) & 3); /* SMI 2*/
508232812Sjmallett            if (ipd_port >= 0xb00 && ipd_port < 0xc00) /* QLM 3*/
509232812Sjmallett                return 0x301 + ((ipd_port >> 4) & 3); /* SMI 3*/
510232812Sjmallett            if (ipd_port >= 0xc00 && ipd_port < 0xd00) /* QLM 4*/
511232812Sjmallett                return 0x001 + ((ipd_port >> 4) & 3); /* SMI 0*/
512232812Sjmallett            return -1;
513232812Sjmallett        case CVMX_BOARD_TYPE_EP6300C:
514232812Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
515232812Sjmallett                return 0x01;
516232812Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT+1)
517232812Sjmallett                return 0x02;
518232812Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
519232812Sjmallett            {
520232812Sjmallett                int interface = cvmx_helper_get_interface_num(ipd_port);
521232812Sjmallett                int mode = cvmx_helper_interface_get_mode(interface);
522232812Sjmallett                if (mode == CVMX_HELPER_INTERFACE_MODE_XAUI)
523232812Sjmallett                    return ipd_port;
524232812Sjmallett                else if ((ipd_port >= 0) && (ipd_port < 4))
525232812Sjmallett                    return ipd_port + 3;
526232812Sjmallett                else
527232812Sjmallett                    return -1;
528232812Sjmallett            }
529232812Sjmallett#endif
530232812Sjmallett            break;
531210284Sjmallett        case CVMX_BOARD_TYPE_CUST_NB5:
532210284Sjmallett            if (ipd_port == 2)
533210284Sjmallett                return 4;
534210284Sjmallett            else
535210284Sjmallett                return -1;
536210284Sjmallett        case CVMX_BOARD_TYPE_NIC_XLE_4G:
537210284Sjmallett            /* Board has 4 SGMII ports. connected QLM3(interface 1) */
538210284Sjmallett            if ((ipd_port >= 16) && (ipd_port < 20))
539210284Sjmallett                return ipd_port - 16 + 1;
540210284Sjmallett            else
541210284Sjmallett                return -1;
542215990Sjmallett        case CVMX_BOARD_TYPE_NIC_XLE_10G:
543232812Sjmallett        case CVMX_BOARD_TYPE_NIC10E:
544215990Sjmallett            return -1;  /* We don't use clause 45 MDIO for anything */
545232812Sjmallett        case CVMX_BOARD_TYPE_NIC4E:
546232812Sjmallett            if (ipd_port >= 0 && ipd_port <= 3)
547232812Sjmallett                return (ipd_port + 0x1f) & 0x1f;
548232812Sjmallett            else
549232812Sjmallett                return -1;
550232812Sjmallett        case CVMX_BOARD_TYPE_NIC2E:
551232812Sjmallett            if (ipd_port >= 0 && ipd_port <= 1)
552232812Sjmallett                return (ipd_port + 1);
553232812Sjmallett            else
554232812Sjmallett                return -1;
555232812Sjmallett        case CVMX_BOARD_TYPE_REDWING:
556232812Sjmallett	    return -1;  /* No PHYs connected to Octeon */
557210284Sjmallett        case CVMX_BOARD_TYPE_BBGW_REF:
558210284Sjmallett            return -1;  /* No PHYs are connected to Octeon, everything is through switch */
559215990Sjmallett	case CVMX_BOARD_TYPE_CUST_WSX16:
560215990Sjmallett		if (ipd_port >= 0 && ipd_port <= 3)
561215990Sjmallett			return ipd_port;
562215990Sjmallett		else if (ipd_port >= 16 && ipd_port <= 19)
563215990Sjmallett			return ipd_port - 16 + 4;
564215990Sjmallett		else
565215990Sjmallett			return -1;
566210311Sjmallett
567210311Sjmallett	/* Private vendor-defined boards.  */
568210311Sjmallett#if defined(OCTEON_VENDOR_LANNER)
569215014Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
570215014Sjmallett	    /* Interface 1 is 12 BCM5482S PHYs.  */
571215014Sjmallett            if ((ipd_port >= 16) && (ipd_port < 28))
572215014Sjmallett                return ipd_port - 16;
573215014Sjmallett	    return -1;
574215014Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
575217214Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
576217214Sjmallett		return (ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT) + 0x81;
577215014Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
578215014Sjmallett                return ipd_port;
579215014Sjmallett	    return -1;
580210311Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
581216476Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
582213346Sjmallett	    /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell
583213346Sjmallett	       88E1111 interfaces.  */
584210311Sjmallett	    switch (ipd_port) {
585210311Sjmallett	    case 0:
586213346Sjmallett		return 16;
587210311Sjmallett	    case 1:
588210311Sjmallett		return 1;
589210311Sjmallett	    case 2:
590210311Sjmallett		return 2;
591210311Sjmallett	    default:
592210311Sjmallett		return -1;
593210311Sjmallett	    }
594210311Sjmallett#endif
595244984Sjmallett#if defined(OCTEON_VENDOR_UBIQUITI)
596244984Sjmallett	case CVMX_BOARD_TYPE_CUST_UBIQUITI_E100:
597244984Sjmallett	    if (ipd_port > 2)
598244984Sjmallett		return -1;
599244984Sjmallett	    return (7 - ipd_port);
600244984Sjmallett#endif
601242116Sjmallett#if defined(OCTEON_VENDOR_RADISYS)
602242116Sjmallett	case CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE:
603242116Sjmallett	    /* No MII.  */
604242116Sjmallett	    return -1;
605242116Sjmallett#endif
606210284Sjmallett    }
607210284Sjmallett
608210284Sjmallett    /* Some unknown board. Somebody forgot to update this function... */
609215990Sjmallett    cvmx_dprintf("%s: Unknown board type %d\n",
610215990Sjmallett                 __FUNCTION__, cvmx_sysinfo_get()->board_type);
611210284Sjmallett    return -1;
612210284Sjmallett}
613215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
614215990SjmallettEXPORT_SYMBOL(cvmx_helper_board_get_mii_address);
615215990Sjmallett#endif
616210284Sjmallett
617232812Sjmallett/**
618232812Sjmallett * @INTERNAL
619232812Sjmallett * Get link state of marvell PHY
620232812Sjmallett */
621232812Sjmallettstatic cvmx_helper_link_info_t __get_marvell_phy_link_state(int phy_addr)
622232812Sjmallett{
623232812Sjmallett    cvmx_helper_link_info_t  result;
624232812Sjmallett    int phy_status;
625210284Sjmallett
626232812Sjmallett    result.u64 = 0;
627232812Sjmallett    /*All the speed information can be read from register 17 in one go.*/
628232812Sjmallett    phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
629232812Sjmallett
630232812Sjmallett    /* If the resolve bit 11 isn't set, see if autoneg is turned off
631232812Sjmallett       (bit 12, reg 0). The resolve bit doesn't get set properly when
632232812Sjmallett       autoneg is off, so force it */
633232812Sjmallett    if ((phy_status & (1<<11)) == 0)
634232812Sjmallett    {
635232812Sjmallett        int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
636232812Sjmallett        if ((auto_status & (1<<12)) == 0)
637232812Sjmallett            phy_status |= 1<<11;
638232812Sjmallett    }
639232812Sjmallett
640232812Sjmallett    /* Only return a link if the PHY has finished auto negotiation
641232812Sjmallett       and set the resolved bit (bit 11) */
642232812Sjmallett    if (phy_status & (1<<11))
643232812Sjmallett    {
644232812Sjmallett        result.s.link_up = 1;
645232812Sjmallett        result.s.full_duplex = ((phy_status>>13)&1);
646232812Sjmallett        switch ((phy_status>>14)&3)
647232812Sjmallett        {
648232812Sjmallett            case 0: /* 10 Mbps */
649232812Sjmallett                result.s.speed = 10;
650232812Sjmallett                break;
651232812Sjmallett            case 1: /* 100 Mbps */
652232812Sjmallett                result.s.speed = 100;
653232812Sjmallett                break;
654232812Sjmallett            case 2: /* 1 Gbps */
655232812Sjmallett                result.s.speed = 1000;
656232812Sjmallett                break;
657232812Sjmallett            case 3: /* Illegal */
658232812Sjmallett                result.u64 = 0;
659232812Sjmallett                break;
660232812Sjmallett        }
661232812Sjmallett    }
662232812Sjmallett    return result;
663232812Sjmallett}
664232812Sjmallett
665210284Sjmallett/**
666210284Sjmallett * @INTERNAL
667232812Sjmallett * Get link state of broadcom PHY
668232812Sjmallett */
669232812Sjmallettstatic cvmx_helper_link_info_t __get_broadcom_phy_link_state(int phy_addr)
670232812Sjmallett{
671232812Sjmallett    cvmx_helper_link_info_t  result;
672232812Sjmallett    int phy_status;
673232812Sjmallett
674232812Sjmallett    result.u64 = 0;
675232812Sjmallett    /* Below we are going to read SMI/MDIO register 0x19 which works
676232812Sjmallett       on Broadcom parts */
677232812Sjmallett    phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19);
678232812Sjmallett    switch ((phy_status>>8) & 0x7)
679232812Sjmallett    {
680232812Sjmallett        case 0:
681232812Sjmallett            result.u64 = 0;
682232812Sjmallett            break;
683232812Sjmallett        case 1:
684232812Sjmallett            result.s.link_up = 1;
685232812Sjmallett            result.s.full_duplex = 0;
686232812Sjmallett            result.s.speed = 10;
687232812Sjmallett            break;
688232812Sjmallett        case 2:
689232812Sjmallett            result.s.link_up = 1;
690232812Sjmallett            result.s.full_duplex = 1;
691232812Sjmallett            result.s.speed = 10;
692232812Sjmallett            break;
693232812Sjmallett        case 3:
694232812Sjmallett            result.s.link_up = 1;
695232812Sjmallett            result.s.full_duplex = 0;
696232812Sjmallett            result.s.speed = 100;
697232812Sjmallett            break;
698232812Sjmallett        case 4:
699232812Sjmallett            result.s.link_up = 1;
700232812Sjmallett            result.s.full_duplex = 1;
701232812Sjmallett            result.s.speed = 100;
702232812Sjmallett            break;
703232812Sjmallett        case 5:
704232812Sjmallett            result.s.link_up = 1;
705232812Sjmallett            result.s.full_duplex = 1;
706232812Sjmallett            result.s.speed = 100;
707232812Sjmallett            break;
708232812Sjmallett        case 6:
709232812Sjmallett            result.s.link_up = 1;
710232812Sjmallett            result.s.full_duplex = 0;
711232812Sjmallett            result.s.speed = 1000;
712232812Sjmallett            break;
713232812Sjmallett        case 7:
714232812Sjmallett            result.s.link_up = 1;
715232812Sjmallett            result.s.full_duplex = 1;
716232812Sjmallett            result.s.speed = 1000;
717232812Sjmallett            break;
718232812Sjmallett    }
719232812Sjmallett    return result;
720232812Sjmallett}
721232812Sjmallett
722232812Sjmallett
723232812Sjmallett/**
724232812Sjmallett * @INTERNAL
725232812Sjmallett * Get link state using inband status
726232812Sjmallett */
727232812Sjmallettstatic cvmx_helper_link_info_t __get_inband_link_state(int ipd_port)
728232812Sjmallett{
729232812Sjmallett    cvmx_helper_link_info_t  result;
730232812Sjmallett    cvmx_gmxx_rxx_rx_inbnd_t inband_status;
731232812Sjmallett    int interface = cvmx_helper_get_interface_num(ipd_port);
732232812Sjmallett    int index = cvmx_helper_get_interface_index_num(ipd_port);
733232812Sjmallett
734232812Sjmallett    result.u64 = 0;
735232812Sjmallett    inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
736232812Sjmallett    result.s.link_up = inband_status.s.status;
737232812Sjmallett    result.s.full_duplex = inband_status.s.duplex;
738232812Sjmallett    switch (inband_status.s.speed)
739232812Sjmallett    {
740232812Sjmallett        case 0: /* 10 Mbps */
741232812Sjmallett            result.s.speed = 10;
742232812Sjmallett            break;
743232812Sjmallett        case 1: /* 100 Mbps */
744232812Sjmallett            result.s.speed = 100;
745232812Sjmallett            break;
746232812Sjmallett        case 2: /* 1 Gbps */
747232812Sjmallett            result.s.speed = 1000;
748232812Sjmallett            break;
749232812Sjmallett        case 3: /* Illegal */
750232812Sjmallett            result.u64 = 0;
751232812Sjmallett            break;
752232812Sjmallett    }
753232812Sjmallett    return result;
754232812Sjmallett}
755232812Sjmallett
756232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
757232812Sjmallett/**
758232812Sjmallett * @INTERNAL
759232812Sjmallett * Switch MDIO mux to the specified port.
760232812Sjmallett */
761232812Sjmallettstatic int __switch_mdio_mux(int ipd_port)
762232812Sjmallett{
763232812Sjmallett    /* This method is board specific and doesn't use the device tree
764232812Sjmallett       information as SE doesn't implement MDIO MUX abstration */
765232812Sjmallett    switch (cvmx_sysinfo_get()->board_type)
766232812Sjmallett    {
767232812Sjmallett        case CVMX_BOARD_TYPE_EBB5600:
768232812Sjmallett        {
769232812Sjmallett            static unsigned char qlm_switch_addr = 0;
770232812Sjmallett            /* Board has 1 management port */
771232812Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
772232812Sjmallett                return 0;
773232812Sjmallett            /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */
774232812Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
775232812Sjmallett            {
776232812Sjmallett                if (qlm_switch_addr != 0x3)
777232812Sjmallett                {
778232812Sjmallett                    qlm_switch_addr = 0x3;  /* QLM1 */
779232812Sjmallett                    cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
780232812Sjmallett                    cvmx_wait_usec(11000); /* Let the write complete */
781232812Sjmallett                }
782232812Sjmallett                return ipd_port+1 + (1<<8);
783232812Sjmallett            }
784232812Sjmallett            else if ((ipd_port >= 16) && (ipd_port < 20))
785232812Sjmallett            {
786232812Sjmallett                if (qlm_switch_addr != 0xC)
787232812Sjmallett                {
788232812Sjmallett                    qlm_switch_addr = 0xC;  /* QLM3 */
789232812Sjmallett                    cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
790232812Sjmallett                    cvmx_wait_usec(11000); /* Let the write complete */
791232812Sjmallett                }
792232812Sjmallett                return ipd_port-16+1 + (1<<8);
793232812Sjmallett            }
794232812Sjmallett            else
795232812Sjmallett                return -1;
796232812Sjmallett        }
797232812Sjmallett        case CVMX_BOARD_TYPE_EBB6600:
798232812Sjmallett        {
799232812Sjmallett            static unsigned char qlm_switch_addr = 0;
800232812Sjmallett            int old_twsi_switch_reg;
801232812Sjmallett            /* Board has 2 management ports */
802232812Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) &&
803232812Sjmallett                (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
804232812Sjmallett                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
805232812Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */
806232812Sjmallett            {
807232812Sjmallett                if (qlm_switch_addr != 2)
808232812Sjmallett                {
809232812Sjmallett                    int tries;
810232812Sjmallett                    qlm_switch_addr = 2;
811232812Sjmallett                    tries = 3;
812232812Sjmallett                    do {
813232812Sjmallett                        old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0);
814232812Sjmallett                    } while (tries-- > 0 && old_twsi_switch_reg < 0);
815232812Sjmallett                    /* Set I2C MUX to enable port expander */
816232812Sjmallett                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8);
817232812Sjmallett                    /* Set selecter to QLM 1 */
818232812Sjmallett                    cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xff);
819232812Sjmallett                    /* disable port expander */
820232812Sjmallett                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg);
821232812Sjmallett                }
822232812Sjmallett                return 0x101 + ipd_port;
823232812Sjmallett            }
824232812Sjmallett            else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 1 */
825232812Sjmallett            {
826232812Sjmallett                if (qlm_switch_addr != 1)
827232812Sjmallett                {
828232812Sjmallett                    int tries;
829232812Sjmallett                    qlm_switch_addr = 1;
830232812Sjmallett                    tries = 3;
831232812Sjmallett                    do {
832232812Sjmallett                            old_twsi_switch_reg = cvmx_twsix_read8(0, 0x70, 0);
833232812Sjmallett                    } while (tries-- > 0 && old_twsi_switch_reg < 0);
834232812Sjmallett                    /* Set I2C MUX to enable port expander */
835232812Sjmallett                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, 8);
836232812Sjmallett                    /* Set selecter to QLM 2 */
837232812Sjmallett                    cvmx_retry_i2c_write(0, 0x38, 0, 1, 0, 0xf7);
838232812Sjmallett                    /* disable port expander */
839232812Sjmallett                    cvmx_retry_i2c_write(0, 0x70, 0, 1, 0, old_twsi_switch_reg);
840232812Sjmallett                }
841232812Sjmallett                return 0x101 + (ipd_port - 16);
842232812Sjmallett            } else
843232812Sjmallett                return -1;
844232812Sjmallett        }
845232812Sjmallett        case CVMX_BOARD_TYPE_EBB6100:
846232812Sjmallett        {
847232812Sjmallett            static char gpio_configured = 0;
848232812Sjmallett
849232812Sjmallett            if (!gpio_configured)
850232812Sjmallett            {
851232812Sjmallett                cvmx_gpio_cfg(3, 1);
852232812Sjmallett                gpio_configured = 1;
853232812Sjmallett            }
854232812Sjmallett            /* Board has 2 management ports */
855232812Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) &&
856232812Sjmallett                (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
857232812Sjmallett                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
858232812Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4)) /* QLM 2 */
859232812Sjmallett            {
860232812Sjmallett                cvmx_gpio_set(1ull << 3);
861232812Sjmallett                return 0x101 + ipd_port;
862232812Sjmallett            }
863232812Sjmallett            else if ((ipd_port >= 16) && (ipd_port < 20)) /* QLM 0 */
864232812Sjmallett            {
865232812Sjmallett                cvmx_gpio_clear(1ull << 3);
866232812Sjmallett                return 0x101 + (ipd_port - 16);
867232812Sjmallett            }
868232812Sjmallett            else
869232812Sjmallett            {
870232812Sjmallett                printf("%s: Unknown ipd port 0x%x\n", __func__, ipd_port);
871232812Sjmallett                return -1;
872232812Sjmallett            }
873232812Sjmallett        }
874232812Sjmallett        default:
875232812Sjmallett        {
876232812Sjmallett            cvmx_dprintf("ERROR : unexpected mdio switch for board=%08x\n",
877232812Sjmallett                         cvmx_sysinfo_get()->board_type);
878232812Sjmallett            return -1;
879232812Sjmallett        }
880232812Sjmallett    }
881232812Sjmallett    /* should never get here */
882232812Sjmallett    return -1;
883232812Sjmallett}
884232812Sjmallett
885232812Sjmallett/**
886232812Sjmallett * @INTERNAL
887232812Sjmallett * This function is used ethernet ports link speed. This functions uses the
888232812Sjmallett * device tree information to determine the phy address and type of PHY.
889232812Sjmallett * The only supproted PHYs are Marvell and Broadcom.
890232812Sjmallett *
891232812Sjmallett * @param ipd_port IPD input port associated with the port we want to get link
892232812Sjmallett *                 status for.
893232812Sjmallett *
894232812Sjmallett * @return The ports link status. If the link isn't fully resolved, this must
895232812Sjmallett *         return zero.
896232812Sjmallett */
897232812Sjmallett
898232812Sjmallettcvmx_helper_link_info_t __cvmx_helper_board_link_get_from_dt(int ipd_port)
899232812Sjmallett{
900232812Sjmallett    cvmx_helper_link_info_t  result;
901232812Sjmallett    cvmx_phy_info_t phy_info;
902232812Sjmallett
903232812Sjmallett    result.u64 = 0;
904232812Sjmallett    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
905232812Sjmallett    {
906232812Sjmallett        /* The simulator gives you a simulated 1Gbps full duplex link */
907232812Sjmallett        result.s.link_up = 1;
908232812Sjmallett        result.s.full_duplex = 1;
909232812Sjmallett        result.s.speed = 1000;
910232812Sjmallett        return result;
911232812Sjmallett    }
912232812Sjmallett    phy_info = __get_phy_info_from_dt(ipd_port);
913232812Sjmallett    //cvmx_dprintf("ipd_port=%d phy_addr=%d dc=%d type=%d \n", ipd_port,
914232812Sjmallett    //             phy_info.phy_addr, phy_info.direct_connect, phy_info.phy_type);
915232812Sjmallett    if (phy_info.phy_addr < 0) return result;
916232812Sjmallett
917232812Sjmallett    if (phy_info.direct_connect == 0)
918232812Sjmallett        __switch_mdio_mux(ipd_port);
919232812Sjmallett    switch(phy_info.phy_type)
920232812Sjmallett    {
921232812Sjmallett        case BROADCOM_GENERIC_PHY:
922232812Sjmallett            result = __get_broadcom_phy_link_state(phy_info.phy_addr);
923232812Sjmallett            break;
924232812Sjmallett        case MARVELL_GENERIC_PHY:
925232812Sjmallett            result = __get_marvell_phy_link_state(phy_info.phy_addr);
926232812Sjmallett            break;
927232812Sjmallett        default:
928232812Sjmallett            result = __get_inband_link_state(ipd_port);
929232812Sjmallett    }
930232812Sjmallett    return result;
931232812Sjmallett
932232812Sjmallett}
933232812Sjmallett#endif
934232812Sjmallett
935232812Sjmallett/**
936232812Sjmallett * @INTERNAL
937232812Sjmallett * This function invokes  __cvmx_helper_board_link_get_from_dt when device tree
938232812Sjmallett * info is available. When the device tree information is not available then
939232812Sjmallett * this function is the board specific method of determining an
940210284Sjmallett * ethernet ports link speed. Most Octeon boards have Marvell PHYs
941210284Sjmallett * and are handled by the fall through case. This function must be
942210284Sjmallett * updated for boards that don't have the normal Marvell PHYs.
943210284Sjmallett *
944210284Sjmallett * This function must be modified for every new Octeon board.
945210284Sjmallett * Internally it uses switch statements based on the cvmx_sysinfo
946210284Sjmallett * data to determine board types and revisions. It relies on the
947210284Sjmallett * fact that every Octeon board receives a unique board type
948210284Sjmallett * enumeration from the bootloader.
949210284Sjmallett *
950210284Sjmallett * @param ipd_port IPD input port associated with the port we want to get link
951210284Sjmallett *                 status for.
952210284Sjmallett *
953210284Sjmallett * @return The ports link status. If the link isn't fully resolved, this must
954210284Sjmallett *         return zero.
955210284Sjmallett */
956210284Sjmallettcvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
957210284Sjmallett{
958210284Sjmallett    cvmx_helper_link_info_t result;
959210284Sjmallett    int phy_addr;
960210284Sjmallett    int is_broadcom_phy = 0;
961210284Sjmallett
962232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
963232812Sjmallett    if (cvmx_sysinfo_get()->fdt_addr)
964232812Sjmallett    {
965232812Sjmallett        return __cvmx_helper_board_link_get_from_dt(ipd_port);
966232812Sjmallett    }
967232812Sjmallett#endif
968232812Sjmallett
969210284Sjmallett    /* Give the user a chance to override the processing of this function */
970210284Sjmallett    if (cvmx_override_board_link_get)
971210284Sjmallett        return cvmx_override_board_link_get(ipd_port);
972210284Sjmallett
973210284Sjmallett    /* Unless we fix it later, all links are defaulted to down */
974210284Sjmallett    result.u64 = 0;
975210284Sjmallett
976210311Sjmallett#if !defined(OCTEON_BOARD_CAPK_0100ND)
977210284Sjmallett    /* This switch statement should handle all ports that either don't use
978210284Sjmallett        Marvell PHYS, or don't support in-band status */
979210284Sjmallett    switch (cvmx_sysinfo_get()->board_type)
980210284Sjmallett    {
981210284Sjmallett        case CVMX_BOARD_TYPE_SIM:
982210284Sjmallett            /* The simulator gives you a simulated 1Gbps full duplex link */
983210284Sjmallett            result.s.link_up = 1;
984210284Sjmallett            result.s.full_duplex = 1;
985210284Sjmallett            result.s.speed = 1000;
986210284Sjmallett            return result;
987215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_A:
988215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_U:
989215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_G:
990215990Sjmallett            break;
991210284Sjmallett        case CVMX_BOARD_TYPE_EBH3100:
992210284Sjmallett        case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
993210284Sjmallett        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
994210284Sjmallett        case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
995210284Sjmallett            /* Port 1 on these boards is always Gigabit */
996210284Sjmallett            if (ipd_port == 1)
997210284Sjmallett            {
998210284Sjmallett                result.s.link_up = 1;
999210284Sjmallett                result.s.full_duplex = 1;
1000210284Sjmallett                result.s.speed = 1000;
1001210284Sjmallett                return result;
1002210284Sjmallett            }
1003210284Sjmallett            /* Fall through to the generic code below */
1004210284Sjmallett            break;
1005242423Sjmallett        case CVMX_BOARD_TYPE_EBT5600:
1006215990Sjmallett        case CVMX_BOARD_TYPE_EBH5600:
1007215990Sjmallett        case CVMX_BOARD_TYPE_EBH5601:
1008215990Sjmallett        case CVMX_BOARD_TYPE_EBH5610:
1009215990Sjmallett            /* Board has 1 management ports */
1010215990Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
1011215990Sjmallett                is_broadcom_phy = 1;
1012215990Sjmallett            break;
1013215990Sjmallett        case CVMX_BOARD_TYPE_EBH5200:
1014215990Sjmallett        case CVMX_BOARD_TYPE_EBH5201:
1015215990Sjmallett        case CVMX_BOARD_TYPE_EBT5200:
1016215990Sjmallett            /* Board has 2 management ports */
1017215990Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
1018215990Sjmallett                is_broadcom_phy = 1;
1019215990Sjmallett            break;
1020232812Sjmallett        case CVMX_BOARD_TYPE_EBB6100:
1021215990Sjmallett        case CVMX_BOARD_TYPE_EBB6300:   /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/
1022232812Sjmallett        case CVMX_BOARD_TYPE_EBB6600:   /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/
1023215990Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))
1024215990Sjmallett                && cvmx_helper_board_get_mii_address(ipd_port) >= 0 && cvmx_helper_board_get_mii_address(ipd_port) <= 1)
1025215990Sjmallett                is_broadcom_phy = 1;
1026215990Sjmallett            break;
1027232812Sjmallett        case CVMX_BOARD_TYPE_EP6300C:
1028232812Sjmallett            is_broadcom_phy = 1;
1029232812Sjmallett            break;
1030210284Sjmallett        case CVMX_BOARD_TYPE_CUST_NB5:
1031210284Sjmallett            /* Port 1 on these boards is always Gigabit */
1032210284Sjmallett            if (ipd_port == 1)
1033210284Sjmallett            {
1034210284Sjmallett                result.s.link_up = 1;
1035210284Sjmallett                result.s.full_duplex = 1;
1036210284Sjmallett                result.s.speed = 1000;
1037210284Sjmallett                return result;
1038210284Sjmallett            }
1039210284Sjmallett            else /* The other port uses a broadcom PHY */
1040210284Sjmallett                is_broadcom_phy = 1;
1041210284Sjmallett            break;
1042210284Sjmallett        case CVMX_BOARD_TYPE_BBGW_REF:
1043210284Sjmallett            /* Port 1 on these boards is always Gigabit */
1044210284Sjmallett            if (ipd_port == 2)
1045215990Sjmallett            {
1046210284Sjmallett                /* Port 2 is not hooked up */
1047210284Sjmallett                result.u64 = 0;
1048210284Sjmallett                return result;
1049210284Sjmallett            }
1050210284Sjmallett            else
1051210284Sjmallett            {
1052210284Sjmallett                /* Ports 0 and 1 connect to the switch */
1053210284Sjmallett                result.s.link_up = 1;
1054210284Sjmallett                result.s.full_duplex = 1;
1055210284Sjmallett                result.s.speed = 1000;
1056210284Sjmallett                return result;
1057210284Sjmallett            }
1058232812Sjmallett        case CVMX_BOARD_TYPE_NIC4E:
1059232812Sjmallett        case CVMX_BOARD_TYPE_NIC2E:
1060232812Sjmallett            is_broadcom_phy = 1;
1061210284Sjmallett            break;
1062210311Sjmallett	/* Private vendor-defined boards.  */
1063210311Sjmallett#if defined(OCTEON_VENDOR_LANNER)
1064215014Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
1065215014Sjmallett	    /* Ports are BCM5482S */
1066215014Sjmallett	    is_broadcom_phy = 1;
1067215014Sjmallett	    break;
1068210311Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
1069216476Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
1070210311Sjmallett	    /* Port 0 connects to the switch */
1071210311Sjmallett	    if (ipd_port == 0)
1072210311Sjmallett	    {
1073210311Sjmallett                result.s.link_up = 1;
1074210311Sjmallett                result.s.full_duplex = 1;
1075210311Sjmallett                result.s.speed = 1000;
1076210311Sjmallett		return result;
1077210311Sjmallett	    }
1078210311Sjmallett	    break;
1079210311Sjmallett#endif
1080210284Sjmallett    }
1081210311Sjmallett#endif
1082210284Sjmallett
1083210284Sjmallett    phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
1084232812Sjmallett    //cvmx_dprintf("ipd_port=%d phy_addr=%d broadcom=%d\n",
1085232812Sjmallett    //             ipd_port, phy_addr, is_broadcom_phy);
1086210284Sjmallett    if (phy_addr != -1)
1087210284Sjmallett    {
1088210284Sjmallett        if (is_broadcom_phy)
1089210284Sjmallett        {
1090232812Sjmallett            result =  __get_broadcom_phy_link_state(phy_addr);
1091210284Sjmallett        }
1092210284Sjmallett        else
1093210284Sjmallett        {
1094232812Sjmallett            /* This code assumes we are using a Marvell Gigabit PHY. */
1095232812Sjmallett            result = __get_marvell_phy_link_state(phy_addr);
1096210284Sjmallett        }
1097210284Sjmallett    }
1098232812Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX)
1099232812Sjmallett             || OCTEON_IS_MODEL(OCTEON_CN50XX))
1100210284Sjmallett    {
1101210284Sjmallett        /* We don't have a PHY address, so attempt to use in-band status. It is
1102210284Sjmallett            really important that boards not supporting in-band status never get
1103210284Sjmallett            here. Reading broken in-band status tends to do bad things */
1104232812Sjmallett        result = __get_inband_link_state(ipd_port);
1105210284Sjmallett    }
1106210284Sjmallett    else
1107210284Sjmallett    {
1108210284Sjmallett        /* We don't have a PHY address and we don't have in-band status. There
1109210284Sjmallett            is no way to determine the link speed. Return down assuming this
1110210284Sjmallett            port isn't wired */
1111210284Sjmallett        result.u64 = 0;
1112210284Sjmallett    }
1113210284Sjmallett
1114210284Sjmallett    /* If link is down, return all fields as zero. */
1115210284Sjmallett    if (!result.s.link_up)
1116210284Sjmallett        result.u64 = 0;
1117210284Sjmallett
1118210284Sjmallett    return result;
1119210284Sjmallett}
1120210284Sjmallett
1121210284Sjmallett
1122210284Sjmallett/**
1123210284Sjmallett * This function as a board specific method of changing the PHY
1124215990Sjmallett * speed, duplex, and autonegotiation. This programs the PHY and
1125210284Sjmallett * not Octeon. This can be used to force Octeon's links to
1126210284Sjmallett * specific settings.
1127210284Sjmallett *
1128210284Sjmallett * @param phy_addr  The address of the PHY to program
1129215990Sjmallett * @param link_flags
1130215990Sjmallett *                  Flags to control autonegotiation.  Bit 0 is autonegotiation
1131215990Sjmallett *                  enable/disable to maintain backward compatibility.
1132215990Sjmallett * @param link_info Link speed to program. If the speed is zero and autonegotiation
1133210284Sjmallett *                  is enabled, all possible negotiation speeds are advertised.
1134210284Sjmallett *
1135210284Sjmallett * @return Zero on success, negative on failure
1136210284Sjmallett */
1137210284Sjmallettint cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags,
1138210284Sjmallett                                   cvmx_helper_link_info_t link_info)
1139210284Sjmallett{
1140210284Sjmallett
1141210284Sjmallett    /* Set the flow control settings based on link_flags */
1142210284Sjmallett    if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch)
1143210284Sjmallett    {
1144210284Sjmallett        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1145210284Sjmallett        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1146210284Sjmallett        reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
1147210284Sjmallett        reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
1148210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1149210284Sjmallett    }
1150210284Sjmallett
1151210284Sjmallett    /* If speed isn't set and autoneg is on advertise all supported modes */
1152210284Sjmallett    if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0))
1153210284Sjmallett    {
1154210284Sjmallett        cvmx_mdio_phy_reg_control_t reg_control;
1155210284Sjmallett        cvmx_mdio_phy_reg_status_t reg_status;
1156210284Sjmallett        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1157210284Sjmallett        cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
1158210284Sjmallett        cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
1159210284Sjmallett
1160210284Sjmallett        reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
1161210284Sjmallett        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1162210284Sjmallett        reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4;
1163210284Sjmallett        reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full;
1164210284Sjmallett        reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half;
1165210284Sjmallett        reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full;
1166210284Sjmallett        reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half;
1167210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1168210284Sjmallett        if (reg_status.s.capable_extended_status)
1169210284Sjmallett        {
1170210284Sjmallett            reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
1171210284Sjmallett            reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
1172210284Sjmallett            reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full;
1173210284Sjmallett            reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half;
1174210284Sjmallett            cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
1175210284Sjmallett        }
1176210284Sjmallett        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1177210284Sjmallett        reg_control.s.autoneg_enable = 1;
1178210284Sjmallett        reg_control.s.restart_autoneg = 1;
1179210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1180210284Sjmallett    }
1181210284Sjmallett    else if ((link_flags & set_phy_link_flags_autoneg))
1182210284Sjmallett    {
1183210284Sjmallett        cvmx_mdio_phy_reg_control_t reg_control;
1184210284Sjmallett        cvmx_mdio_phy_reg_status_t reg_status;
1185210284Sjmallett        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
1186210284Sjmallett        cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
1187210284Sjmallett
1188210284Sjmallett        reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
1189210284Sjmallett        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
1190210284Sjmallett        reg_autoneg_adver.s.advert_100base_t4 = 0;
1191210284Sjmallett        reg_autoneg_adver.s.advert_10base_tx_full = 0;
1192210284Sjmallett        reg_autoneg_adver.s.advert_10base_tx_half = 0;
1193210284Sjmallett        reg_autoneg_adver.s.advert_100base_tx_full = 0;
1194210284Sjmallett        reg_autoneg_adver.s.advert_100base_tx_half = 0;
1195210284Sjmallett        if (reg_status.s.capable_extended_status)
1196210284Sjmallett        {
1197210284Sjmallett            reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
1198210284Sjmallett            reg_control_1000.s.advert_1000base_t_full = 0;
1199210284Sjmallett            reg_control_1000.s.advert_1000base_t_half = 0;
1200210284Sjmallett        }
1201210284Sjmallett        switch (link_info.s.speed)
1202210284Sjmallett        {
1203210284Sjmallett            case 10:
1204210284Sjmallett                reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex;
1205210284Sjmallett                reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex;
1206210284Sjmallett                break;
1207210284Sjmallett            case 100:
1208210284Sjmallett                reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex;
1209210284Sjmallett                reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex;
1210210284Sjmallett                break;
1211210284Sjmallett            case 1000:
1212210284Sjmallett                reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex;
1213210284Sjmallett                reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex;
1214210284Sjmallett                break;
1215210284Sjmallett        }
1216210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
1217210284Sjmallett        if (reg_status.s.capable_extended_status)
1218210284Sjmallett            cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
1219210284Sjmallett        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1220210284Sjmallett        reg_control.s.autoneg_enable = 1;
1221210284Sjmallett        reg_control.s.restart_autoneg = 1;
1222210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1223210284Sjmallett    }
1224210284Sjmallett    else
1225210284Sjmallett    {
1226210284Sjmallett        cvmx_mdio_phy_reg_control_t reg_control;
1227210284Sjmallett        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
1228210284Sjmallett        reg_control.s.autoneg_enable = 0;
1229210284Sjmallett        reg_control.s.restart_autoneg = 1;
1230210284Sjmallett        reg_control.s.duplex = link_info.s.full_duplex;
1231210284Sjmallett        if (link_info.s.speed == 1000)
1232210284Sjmallett        {
1233210284Sjmallett            reg_control.s.speed_msb = 1;
1234210284Sjmallett            reg_control.s.speed_lsb = 0;
1235210284Sjmallett        }
1236210284Sjmallett        else if (link_info.s.speed == 100)
1237210284Sjmallett        {
1238210284Sjmallett            reg_control.s.speed_msb = 0;
1239210284Sjmallett            reg_control.s.speed_lsb = 1;
1240210284Sjmallett        }
1241210284Sjmallett        else if (link_info.s.speed == 10)
1242210284Sjmallett        {
1243210284Sjmallett            reg_control.s.speed_msb = 0;
1244210284Sjmallett            reg_control.s.speed_lsb = 0;
1245210284Sjmallett        }
1246210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
1247210284Sjmallett    }
1248210284Sjmallett    return 0;
1249210284Sjmallett}
1250210284Sjmallett
1251210284Sjmallett
1252210284Sjmallett/**
1253210284Sjmallett * @INTERNAL
1254210284Sjmallett * This function is called by cvmx_helper_interface_probe() after it
1255210284Sjmallett * determines the number of ports Octeon can support on a specific
1256210284Sjmallett * interface. This function is the per board location to override
1257210284Sjmallett * this value. It is called with the number of ports Octeon might
1258210284Sjmallett * support and should return the number of actual ports on the
1259210284Sjmallett * board.
1260210284Sjmallett *
1261215990Sjmallett * This function must be modified for every new Octeon board.
1262210284Sjmallett * Internally it uses switch statements based on the cvmx_sysinfo
1263215990Sjmallett * data to determine board types and revisions. It relies on the
1264210284Sjmallett * fact that every Octeon board receives a unique board type
1265210284Sjmallett * enumeration from the bootloader.
1266210284Sjmallett *
1267210284Sjmallett * @param interface Interface to probe
1268210284Sjmallett * @param supported_ports
1269210284Sjmallett *                  Number of ports Octeon supports.
1270210284Sjmallett *
1271210284Sjmallett * @return Number of ports the actual board supports. Many times this will
1272210284Sjmallett *         simple be "support_ports".
1273210284Sjmallett */
1274210284Sjmallettint __cvmx_helper_board_interface_probe(int interface, int supported_ports)
1275210284Sjmallett{
1276210284Sjmallett    switch (cvmx_sysinfo_get()->board_type)
1277210284Sjmallett    {
1278210284Sjmallett        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
1279215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_A:
1280215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_U:
1281215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_G:
1282210284Sjmallett            if (interface == 0)
1283210284Sjmallett                return 2;
1284210284Sjmallett	    break;
1285210284Sjmallett        case CVMX_BOARD_TYPE_BBGW_REF:
1286210284Sjmallett            if (interface == 0)
1287210284Sjmallett                return 2;
1288210284Sjmallett	    break;
1289210284Sjmallett        case CVMX_BOARD_TYPE_NIC_XLE_4G:
1290210284Sjmallett            if (interface == 0)
1291210284Sjmallett                return 0;
1292210284Sjmallett	    break;
1293210284Sjmallett        /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
1294210284Sjmallett            which we don't support. Disable ports connected to it */
1295210284Sjmallett        case CVMX_BOARD_TYPE_EBH5600:
1296210284Sjmallett            if (interface == 1)
1297210284Sjmallett                return 0;
1298210284Sjmallett	    break;
1299215990Sjmallett        case CVMX_BOARD_TYPE_EBB5600:
1300215990Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
1301215990Sjmallett            if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_PICMG)
1302215990Sjmallett                return 0;
1303215990Sjmallett#endif
1304215990Sjmallett	    break;
1305242423Sjmallett        case CVMX_BOARD_TYPE_EBT5600:
1306242423Sjmallett	    /* Disable loopback.  */
1307242423Sjmallett	    if (interface == 3)
1308242423Sjmallett		return 0;
1309242423Sjmallett	    break;
1310215990Sjmallett        case CVMX_BOARD_TYPE_EBT5810:
1311215990Sjmallett            return 1;  /* Two ports on each SPI: 1 hooked to MAC, 1 loopback
1312215990Sjmallett                       ** Loopback disabled by default. */
1313232812Sjmallett        case CVMX_BOARD_TYPE_NIC2E:
1314232812Sjmallett            if (interface == 0)
1315232812Sjmallett                return 2;
1316212844Sjmallett#if defined(OCTEON_VENDOR_LANNER)
1317212844Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
1318212844Sjmallett	    if (interface == 1)
1319212844Sjmallett	        return 12;
1320212844Sjmallett	    break;
1321212844Sjmallett#endif
1322210284Sjmallett    }
1323210284Sjmallett#ifdef CVMX_BUILD_FOR_UBOOT
1324210284Sjmallett    if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi"))
1325210284Sjmallett        return 0;
1326210284Sjmallett#endif
1327210284Sjmallett    return supported_ports;
1328210284Sjmallett}
1329210284Sjmallett
1330210284Sjmallett
1331210284Sjmallett/**
1332210284Sjmallett * @INTERNAL
1333210284Sjmallett * Enable packet input/output from the hardware. This function is
1334210284Sjmallett * called after by cvmx_helper_packet_hardware_enable() to
1335210284Sjmallett * perform board specific initialization. For most boards
1336210284Sjmallett * nothing is needed.
1337210284Sjmallett *
1338210284Sjmallett * @param interface Interface to enable
1339210284Sjmallett *
1340210284Sjmallett * @return Zero on success, negative on failure
1341210284Sjmallett */
1342210284Sjmallettint __cvmx_helper_board_hardware_enable(int interface)
1343210284Sjmallett{
1344210284Sjmallett    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5)
1345210284Sjmallett    {
1346210284Sjmallett        if (interface == 0)
1347210284Sjmallett        {
1348210284Sjmallett            /* Different config for switch port */
1349210284Sjmallett            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
1350210284Sjmallett            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
1351210284Sjmallett            /* Boards with gigabit WAN ports need a different setting that is
1352210284Sjmallett                compatible with 100 Mbit settings */
1353210284Sjmallett            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc);
1354210284Sjmallett            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc);
1355210284Sjmallett        }
1356210284Sjmallett    }
1357215990Sjmallett    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_LANAI2_U)
1358215990Sjmallett    {
1359215990Sjmallett        if (interface == 0)
1360215990Sjmallett        {
1361215990Sjmallett            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 16);
1362215990Sjmallett            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 16);
1363215990Sjmallett        }
1364215990Sjmallett    }
1365210284Sjmallett    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5)
1366210284Sjmallett    {
1367215990Sjmallett        /* Broadcom PHYs require different ASX clocks. Unfortunately
1368210284Sjmallett            many customer don't define a new board Id and simply
1369210284Sjmallett            mangle the CN3010_EVB_HS5 */
1370210284Sjmallett        if (interface == 0)
1371210284Sjmallett        {
1372210284Sjmallett            /* Some customers boards use a hacked up bootloader that identifies them as
1373210284Sjmallett            ** CN3010_EVB_HS5 evaluation boards.  This leads to all kinds of configuration
1374210284Sjmallett            ** problems.  Detect one case, and print warning, while trying to do the right thing.
1375210284Sjmallett            */
1376210284Sjmallett            int phy_addr = cvmx_helper_board_get_mii_address(0);
1377210284Sjmallett            if (phy_addr != -1)
1378210284Sjmallett            {
1379210284Sjmallett                int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2);
1380210284Sjmallett                /* Is it a Broadcom PHY? */
1381210284Sjmallett                if (phy_identifier == 0x0143)
1382210284Sjmallett                {
1383210284Sjmallett                    cvmx_dprintf("\n");
1384210284Sjmallett                    cvmx_dprintf("ERROR:\n");
1385210284Sjmallett                    cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
1386210284Sjmallett                    cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
1387210284Sjmallett                    cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n");
1388210284Sjmallett                    cvmx_dprintf("ERROR:\n");
1389210284Sjmallett                    cvmx_dprintf("\n");
1390210284Sjmallett                    cvmx_wait(1000000000);
1391210284Sjmallett                    cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5);
1392210284Sjmallett                    cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5);
1393210284Sjmallett                }
1394210284Sjmallett            }
1395210284Sjmallett        }
1396210284Sjmallett    }
1397210284Sjmallett    return 0;
1398210284Sjmallett}
1399210284Sjmallett
1400215990Sjmallett
1401215990Sjmallett/**
1402215990Sjmallett * @INTERNAL
1403215990Sjmallett * Gets the clock type used for the USB block based on board type.
1404215990Sjmallett * Used by the USB code for auto configuration of clock type.
1405215990Sjmallett *
1406215990Sjmallett * @return USB clock type enumeration
1407215990Sjmallett */
1408210284Sjmallettcvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void)
1409210284Sjmallett{
1410232812Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && (!defined(__FreeBSD__) || !defined(_KERNEL))
1411232812Sjmallett    const void *fdt_addr = CASTPTR(const void *, cvmx_sysinfo_get()->fdt_addr);
1412232812Sjmallett    int nodeoffset;
1413232812Sjmallett    const void *nodep;
1414232812Sjmallett    int len;
1415232812Sjmallett    uint32_t speed = 0;
1416232812Sjmallett    const char *type = NULL;
1417232812Sjmallett
1418232812Sjmallett    if (fdt_addr)
1419232812Sjmallett    {
1420232812Sjmallett        nodeoffset = fdt_path_offset(fdt_addr, "/soc/uctl");
1421232812Sjmallett        if (nodeoffset < 0)
1422232812Sjmallett            nodeoffset = fdt_path_offset(fdt_addr, "/soc/usbn");
1423232812Sjmallett
1424232812Sjmallett        if (nodeoffset >= 0)
1425232812Sjmallett        {
1426232812Sjmallett            nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-type", &len);
1427232812Sjmallett            if (nodep != NULL && len > 0)
1428232812Sjmallett                type = (const char *)nodep;
1429232812Sjmallett            else
1430232812Sjmallett                type = "unknown";
1431232812Sjmallett            nodep = fdt_getprop(fdt_addr, nodeoffset, "refclk-frequency", &len);
1432232812Sjmallett            if (nodep != NULL && len == sizeof(uint32_t))
1433232812Sjmallett                speed = fdt32_to_cpu(*(int *)nodep);
1434232812Sjmallett            else
1435232812Sjmallett                speed = 0;
1436232812Sjmallett            if (!strcmp(type, "crystal"))
1437232812Sjmallett            {
1438232812Sjmallett                if (speed == 0 || speed == 12000000)
1439232812Sjmallett                    return USB_CLOCK_TYPE_CRYSTAL_12;
1440232812Sjmallett                else
1441232812Sjmallett                    printf("Warning: invalid crystal speed for USB clock type in FDT\n");
1442232812Sjmallett            }
1443232812Sjmallett            else if (!strcmp(type, "external"))
1444232812Sjmallett            {
1445232812Sjmallett                switch (speed) {
1446232812Sjmallett                case 12000000:
1447232812Sjmallett                    return USB_CLOCK_TYPE_REF_12;
1448232812Sjmallett                case 24000000:
1449232812Sjmallett                    return USB_CLOCK_TYPE_REF_24;
1450232812Sjmallett                case 0:
1451232812Sjmallett                case 48000000:
1452232812Sjmallett                    return USB_CLOCK_TYPE_REF_48;
1453232812Sjmallett                default:
1454232812Sjmallett                    printf("Warning: invalid USB clock speed of %u hz in FDT\n", speed);
1455232812Sjmallett                }
1456232812Sjmallett            }
1457232812Sjmallett            else
1458232812Sjmallett                printf("Warning: invalid USB reference clock type \"%s\" in FDT\n", type ? type : "NULL");
1459232812Sjmallett        }
1460232812Sjmallett    }
1461232812Sjmallett#endif
1462215990Sjmallett    switch (cvmx_sysinfo_get()->board_type)
1463215990Sjmallett    {
1464215990Sjmallett        case CVMX_BOARD_TYPE_BBGW_REF:
1465215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_A:
1466215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_U:
1467215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_G:
1468210311Sjmallett#if defined(OCTEON_VENDOR_LANNER)
1469210311Sjmallett    case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
1470216476Sjmallett    case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
1471210311Sjmallett#endif
1472229070Sgonzo#if defined(OCTEON_BOARD_CAPK_0100ND)
1473229070Sgonzo	case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
1474229070Sgonzo#endif
1475232812Sjmallett        case CVMX_BOARD_TYPE_NIC10E_66:
1476210284Sjmallett            return USB_CLOCK_TYPE_CRYSTAL_12;
1477232812Sjmallett        case CVMX_BOARD_TYPE_NIC10E:
1478232812Sjmallett            return USB_CLOCK_TYPE_REF_12;
1479232812Sjmallett        default:
1480232812Sjmallett            break;
1481210284Sjmallett    }
1482232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN6XXX)	/* Most boards except NIC10e use a 12MHz crystal */
1483232812Sjmallett        || OCTEON_IS_MODEL(OCTEON_CNF7XXX))
1484232812Sjmallett        return USB_CLOCK_TYPE_CRYSTAL_12;
1485210284Sjmallett    return USB_CLOCK_TYPE_REF_48;
1486210284Sjmallett}
1487210284Sjmallett
1488215990Sjmallett
1489215990Sjmallett/**
1490215990Sjmallett * @INTERNAL
1491215990Sjmallett * Adjusts the number of available USB ports on Octeon based on board
1492215990Sjmallett * specifics.
1493215990Sjmallett *
1494215990Sjmallett * @param supported_ports expected number of ports based on chip type;
1495215990Sjmallett *
1496215990Sjmallett *
1497215990Sjmallett * @return number of available usb ports, based on board specifics.
1498215990Sjmallett *         Return value is supported_ports if function does not
1499215990Sjmallett *         override.
1500215990Sjmallett */
1501210284Sjmallettint __cvmx_helper_board_usb_get_num_ports(int supported_ports)
1502210284Sjmallett{
1503215990Sjmallett    switch (cvmx_sysinfo_get()->board_type)
1504215990Sjmallett    {
1505210284Sjmallett        case CVMX_BOARD_TYPE_NIC_XLE_4G:
1506232812Sjmallett        case CVMX_BOARD_TYPE_NIC2E:
1507210284Sjmallett            return 0;
1508210284Sjmallett    }
1509210284Sjmallett
1510210284Sjmallett    return supported_ports;
1511210284Sjmallett}
1512210284Sjmallett
1513210284Sjmallett
1514