1210284Sjmallett/***********************license start***************
2215990Sjmallett * Copyright (c) 2003-2010  Cavium Networks (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
18215990Sjmallett *   * Neither the name of Cavium Networks 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"
29215990Sjmallett * AND WITH ALL FAULTS AND CAVIUM  NETWORKS 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 *
52215990Sjmallett * <hr>$Revision: 49627 $<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"
75215990Sjmallett#endif
76210284Sjmallett
77210284Sjmallett/**
78210284Sjmallett * cvmx_override_board_link_get(int ipd_port) is a function
79210284Sjmallett * pointer. It is meant to allow customization of the process of
80210284Sjmallett * talking to a PHY to determine link speed. It is called every
81210284Sjmallett * time a PHY must be polled for link status. Users should set
82210284Sjmallett * this pointer to a function before calling any cvmx-helper
83210284Sjmallett * operations.
84210284Sjmallett */
85210284SjmallettCVMX_SHARED cvmx_helper_link_info_t (*cvmx_override_board_link_get)(int ipd_port) = NULL;
86210284Sjmallett
87210284Sjmallett/**
88210284Sjmallett * Return the MII PHY address associated with the given IPD
89210284Sjmallett * port. A result of -1 means there isn't a MII capable PHY
90210284Sjmallett * connected to this port. On chips supporting multiple MII
91210284Sjmallett * busses the bus number is encoded in bits <15:8>.
92210284Sjmallett *
93210284Sjmallett * This function must be modified for every new Octeon board.
94210284Sjmallett * Internally it uses switch statements based on the cvmx_sysinfo
95210284Sjmallett * data to determine board types and revisions. It replies on the
96210284Sjmallett * fact that every Octeon board receives a unique board type
97210284Sjmallett * enumeration from the bootloader.
98210284Sjmallett *
99210284Sjmallett * @param ipd_port Octeon IPD port to get the MII address for.
100210284Sjmallett *
101210284Sjmallett * @return MII PHY address and bus number or -1.
102210284Sjmallett */
103210284Sjmallettint cvmx_helper_board_get_mii_address(int ipd_port)
104210284Sjmallett{
105210311Sjmallett    /*
106210311Sjmallett     * Board types we have to know at compile-time.
107210311Sjmallett     */
108210311Sjmallett#ifdef OCTEON_BOARD_CAPK_0100ND
109210311Sjmallett    switch (ipd_port) {
110210311Sjmallett    case 0:
111210311Sjmallett	return 2;
112210311Sjmallett    case 1:
113210311Sjmallett	return 3;
114210311Sjmallett    case 2:
115210311Sjmallett	/* XXX Switch PHY?  */
116210311Sjmallett	return -1;
117210311Sjmallett    default:
118210311Sjmallett	return -1;
119210311Sjmallett    }
120210311Sjmallett#endif
121210311Sjmallett
122210311Sjmallett    /*
123210311Sjmallett     * For board types we can determine at runtime.
124210311Sjmallett     */
125210284Sjmallett    switch (cvmx_sysinfo_get()->board_type)
126210284Sjmallett    {
127210284Sjmallett        case CVMX_BOARD_TYPE_SIM:
128210284Sjmallett            /* Simulator doesn't have MII */
129210284Sjmallett            return -1;
130210284Sjmallett        case CVMX_BOARD_TYPE_EBT3000:
131210284Sjmallett        case CVMX_BOARD_TYPE_EBT5800:
132210284Sjmallett        case CVMX_BOARD_TYPE_THUNDER:
133210284Sjmallett        case CVMX_BOARD_TYPE_NICPRO2:
134210284Sjmallett            /* Interface 0 is SPI4, interface 1 is RGMII */
135210284Sjmallett            if ((ipd_port >= 16) && (ipd_port < 20))
136210284Sjmallett                return ipd_port - 16;
137210284Sjmallett            else
138210284Sjmallett                return -1;
139215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_A:
140215990Sjmallett            if (ipd_port == 0)
141215990Sjmallett                return 0;
142215990Sjmallett            else
143215990Sjmallett                return -1;
144215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_U:
145215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_G:
146215990Sjmallett            if (ipd_port == 0)
147215990Sjmallett                return 0x1c;
148215990Sjmallett            else
149215990Sjmallett                return -1;
150210284Sjmallett        case CVMX_BOARD_TYPE_KODAMA:
151210284Sjmallett        case CVMX_BOARD_TYPE_EBH3100:
152210284Sjmallett        case CVMX_BOARD_TYPE_HIKARI:
153210284Sjmallett        case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
154210284Sjmallett        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
155210284Sjmallett        case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
156210284Sjmallett            /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a
157210284Sjmallett                switch */
158210284Sjmallett            if (ipd_port == 0)
159210284Sjmallett                return 4;
160210284Sjmallett            else if (ipd_port == 1)
161210284Sjmallett                return 9;
162210284Sjmallett            else
163210284Sjmallett                return -1;
164210284Sjmallett        case CVMX_BOARD_TYPE_NAC38:
165210284Sjmallett            /* Board has 8 RGMII ports PHYs are 0-7 */
166210284Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
167210284Sjmallett                return ipd_port;
168210284Sjmallett            else if ((ipd_port >= 16) && (ipd_port < 20))
169210284Sjmallett                return ipd_port - 16 + 4;
170210284Sjmallett            else
171210284Sjmallett                return -1;
172210284Sjmallett        case CVMX_BOARD_TYPE_EBH3000:
173210284Sjmallett            /* Board has dual SPI4 and no PHYs */
174210284Sjmallett            return -1;
175215990Sjmallett        case CVMX_BOARD_TYPE_EBT5810:
176215990Sjmallett            /* Board has 10g PHYs hooked up to the MII controller on the
177215990Sjmallett            ** IXF18201 MAC.  The 10G PHYS use clause 45 MDIO which the CN58XX
178215990Sjmallett            ** does not support. All MII accesses go through the IXF part. */
179215990Sjmallett            return -1;
180210284Sjmallett        case CVMX_BOARD_TYPE_EBH5200:
181210284Sjmallett        case CVMX_BOARD_TYPE_EBH5201:
182210284Sjmallett        case CVMX_BOARD_TYPE_EBT5200:
183215990Sjmallett            /* Board has 2 management ports */
184215990Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
185215990Sjmallett                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
186210284Sjmallett            /* Board has 4 SGMII ports. The PHYs start right after the MII
187210284Sjmallett                ports MII0 = 0, MII1 = 1, SGMII = 2-5 */
188210284Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
189210284Sjmallett                return ipd_port+2;
190210284Sjmallett            else
191210284Sjmallett                return -1;
192210284Sjmallett        case CVMX_BOARD_TYPE_EBH5600:
193210284Sjmallett        case CVMX_BOARD_TYPE_EBH5601:
194215990Sjmallett        case CVMX_BOARD_TYPE_EBH5610:
195215990Sjmallett            /* Board has 1 management port */
196215990Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
197215990Sjmallett                return 0;
198210284Sjmallett            /* Board has 8 SGMII ports. 4 connect out, two connect to a switch,
199210284Sjmallett                and 2 loop to each other */
200210284Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
201210284Sjmallett                return ipd_port+1;
202210284Sjmallett            else
203210284Sjmallett                return -1;
204215990Sjmallett        case CVMX_BOARD_TYPE_EBB5600:
205215990Sjmallett            {
206215990Sjmallett                static unsigned char qlm_switch_addr = 0;
207215990Sjmallett
208215990Sjmallett                /* Board has 1 management port */
209215990Sjmallett                if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
210215990Sjmallett                    return 0;
211215990Sjmallett
212215990Sjmallett                /* Board has 8 SGMII ports. 4 connected QLM1, 4 connected QLM3 */
213215990Sjmallett                if ((ipd_port >= 0) && (ipd_port < 4))
214215990Sjmallett                {
215215990Sjmallett                    if (qlm_switch_addr != 0x3)
216215990Sjmallett                    {
217215990Sjmallett                        qlm_switch_addr = 0x3;  /* QLM1 */
218215990Sjmallett                        cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
219215990Sjmallett                        cvmx_wait_usec(11000); /* Let the write complete */
220215990Sjmallett                    }
221215990Sjmallett                    return ipd_port+1 + (1<<8);
222215990Sjmallett                }
223215990Sjmallett                else if ((ipd_port >= 16) && (ipd_port < 20))
224215990Sjmallett                {
225215990Sjmallett                    if (qlm_switch_addr != 0xC)
226215990Sjmallett                    {
227215990Sjmallett                        qlm_switch_addr = 0xC;  /* QLM3 */
228215990Sjmallett                        cvmx_twsix_write_ia(0, 0x71, 0, 1, 1, qlm_switch_addr);
229215990Sjmallett                        cvmx_wait_usec(11000); /* Let the write complete */
230215990Sjmallett                    }
231215990Sjmallett                    return ipd_port-16+1 + (1<<8);
232215990Sjmallett                }
233215990Sjmallett                else
234215990Sjmallett                    return -1;
235215990Sjmallett            }
236215990Sjmallett        case CVMX_BOARD_TYPE_EBB6300:
237215990Sjmallett            /* Board has 2 management ports */
238215990Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
239215990Sjmallett                return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT + 4;
240215990Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
241215990Sjmallett                return ipd_port + 1 + (1<<8);
242215990Sjmallett            else
243215990Sjmallett                return -1;
244210284Sjmallett        case CVMX_BOARD_TYPE_CUST_NB5:
245210284Sjmallett            if (ipd_port == 2)
246210284Sjmallett                return 4;
247210284Sjmallett            else
248210284Sjmallett                return -1;
249210284Sjmallett        case CVMX_BOARD_TYPE_NIC_XLE_4G:
250210284Sjmallett            /* Board has 4 SGMII ports. connected QLM3(interface 1) */
251210284Sjmallett            if ((ipd_port >= 16) && (ipd_port < 20))
252210284Sjmallett                return ipd_port - 16 + 1;
253210284Sjmallett            else
254210284Sjmallett                return -1;
255215990Sjmallett        case CVMX_BOARD_TYPE_NIC_XLE_10G:
256215990Sjmallett            return -1;  /* We don't use clause 45 MDIO for anything */
257210284Sjmallett        case CVMX_BOARD_TYPE_BBGW_REF:
258210284Sjmallett            return -1;  /* No PHYs are connected to Octeon, everything is through switch */
259215990Sjmallett	case CVMX_BOARD_TYPE_CUST_WSX16:
260215990Sjmallett		if (ipd_port >= 0 && ipd_port <= 3)
261215990Sjmallett			return ipd_port;
262215990Sjmallett		else if (ipd_port >= 16 && ipd_port <= 19)
263215990Sjmallett			return ipd_port - 16 + 4;
264215990Sjmallett		else
265215990Sjmallett			return -1;
266210311Sjmallett
267210311Sjmallett	/* Private vendor-defined boards.  */
268210311Sjmallett#if defined(OCTEON_VENDOR_LANNER)
269215014Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
270215014Sjmallett	    /* Interface 1 is 12 BCM5482S PHYs.  */
271215014Sjmallett            if ((ipd_port >= 16) && (ipd_port < 28))
272215014Sjmallett                return ipd_port - 16;
273215014Sjmallett	    return -1;
274215014Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
275217214Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
276217214Sjmallett		return (ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT) + 0x81;
277215014Sjmallett            if ((ipd_port >= 0) && (ipd_port < 4))
278215014Sjmallett                return ipd_port;
279215014Sjmallett	    return -1;
280210311Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
281216476Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
282213346Sjmallett	    /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell
283213346Sjmallett	       88E1111 interfaces.  */
284210311Sjmallett	    switch (ipd_port) {
285210311Sjmallett	    case 0:
286213346Sjmallett		return 16;
287210311Sjmallett	    case 1:
288210311Sjmallett		return 1;
289210311Sjmallett	    case 2:
290210311Sjmallett		return 2;
291210311Sjmallett	    default:
292210311Sjmallett		return -1;
293210311Sjmallett	    }
294210311Sjmallett#endif
295210284Sjmallett    }
296210284Sjmallett
297210284Sjmallett    /* Some unknown board. Somebody forgot to update this function... */
298215990Sjmallett    cvmx_dprintf("%s: Unknown board type %d\n",
299215990Sjmallett                 __FUNCTION__, cvmx_sysinfo_get()->board_type);
300210284Sjmallett    return -1;
301210284Sjmallett}
302215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
303215990SjmallettEXPORT_SYMBOL(cvmx_helper_board_get_mii_address);
304215990Sjmallett#endif
305210284Sjmallett
306210284Sjmallett
307210284Sjmallett/**
308210284Sjmallett * @INTERNAL
309210284Sjmallett * This function is the board specific method of determining an
310210284Sjmallett * ethernet ports link speed. Most Octeon boards have Marvell PHYs
311210284Sjmallett * and are handled by the fall through case. This function must be
312210284Sjmallett * updated for boards that don't have the normal Marvell PHYs.
313210284Sjmallett *
314210284Sjmallett * This function must be modified for every new Octeon board.
315210284Sjmallett * Internally it uses switch statements based on the cvmx_sysinfo
316210284Sjmallett * data to determine board types and revisions. It relies on the
317210284Sjmallett * fact that every Octeon board receives a unique board type
318210284Sjmallett * enumeration from the bootloader.
319210284Sjmallett *
320210284Sjmallett * @param ipd_port IPD input port associated with the port we want to get link
321210284Sjmallett *                 status for.
322210284Sjmallett *
323210284Sjmallett * @return The ports link status. If the link isn't fully resolved, this must
324210284Sjmallett *         return zero.
325210284Sjmallett */
326210284Sjmallettcvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
327210284Sjmallett{
328210284Sjmallett    cvmx_helper_link_info_t result;
329210284Sjmallett    int phy_addr;
330210284Sjmallett    int is_broadcom_phy = 0;
331210284Sjmallett
332210284Sjmallett    /* Give the user a chance to override the processing of this function */
333210284Sjmallett    if (cvmx_override_board_link_get)
334210284Sjmallett        return cvmx_override_board_link_get(ipd_port);
335210284Sjmallett
336210284Sjmallett    /* Unless we fix it later, all links are defaulted to down */
337210284Sjmallett    result.u64 = 0;
338210284Sjmallett
339210311Sjmallett#if !defined(OCTEON_BOARD_CAPK_0100ND)
340210284Sjmallett    /* This switch statement should handle all ports that either don't use
341210284Sjmallett        Marvell PHYS, or don't support in-band status */
342210284Sjmallett    switch (cvmx_sysinfo_get()->board_type)
343210284Sjmallett    {
344210284Sjmallett        case CVMX_BOARD_TYPE_SIM:
345210284Sjmallett            /* The simulator gives you a simulated 1Gbps full duplex link */
346210284Sjmallett            result.s.link_up = 1;
347210284Sjmallett            result.s.full_duplex = 1;
348210284Sjmallett            result.s.speed = 1000;
349210284Sjmallett            return result;
350215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_A:
351215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_U:
352215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_G:
353215990Sjmallett            break;
354210284Sjmallett        case CVMX_BOARD_TYPE_EBH3100:
355210284Sjmallett        case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
356210284Sjmallett        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
357210284Sjmallett        case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
358210284Sjmallett            /* Port 1 on these boards is always Gigabit */
359210284Sjmallett            if (ipd_port == 1)
360210284Sjmallett            {
361210284Sjmallett                result.s.link_up = 1;
362210284Sjmallett                result.s.full_duplex = 1;
363210284Sjmallett                result.s.speed = 1000;
364210284Sjmallett                return result;
365210284Sjmallett            }
366210284Sjmallett            /* Fall through to the generic code below */
367210284Sjmallett            break;
368215990Sjmallett        case CVMX_BOARD_TYPE_EBH5600:
369215990Sjmallett        case CVMX_BOARD_TYPE_EBH5601:
370215990Sjmallett        case CVMX_BOARD_TYPE_EBH5610:
371215990Sjmallett            /* Board has 1 management ports */
372215990Sjmallett            if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
373215990Sjmallett                is_broadcom_phy = 1;
374215990Sjmallett            break;
375215990Sjmallett        case CVMX_BOARD_TYPE_EBH5200:
376215990Sjmallett        case CVMX_BOARD_TYPE_EBH5201:
377215990Sjmallett        case CVMX_BOARD_TYPE_EBT5200:
378215990Sjmallett            /* Board has 2 management ports */
379215990Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
380215990Sjmallett                is_broadcom_phy = 1;
381215990Sjmallett            break;
382215990Sjmallett        case CVMX_BOARD_TYPE_EBB6300:   /* Only for MII mode, with PHY addresses 0/1. Default is RGMII*/
383215990Sjmallett            if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))
384215990Sjmallett                && cvmx_helper_board_get_mii_address(ipd_port) >= 0 && cvmx_helper_board_get_mii_address(ipd_port) <= 1)
385215990Sjmallett                is_broadcom_phy = 1;
386215990Sjmallett            break;
387210284Sjmallett        case CVMX_BOARD_TYPE_CUST_NB5:
388210284Sjmallett            /* Port 1 on these boards is always Gigabit */
389210284Sjmallett            if (ipd_port == 1)
390210284Sjmallett            {
391210284Sjmallett                result.s.link_up = 1;
392210284Sjmallett                result.s.full_duplex = 1;
393210284Sjmallett                result.s.speed = 1000;
394210284Sjmallett                return result;
395210284Sjmallett            }
396210284Sjmallett            else /* The other port uses a broadcom PHY */
397210284Sjmallett                is_broadcom_phy = 1;
398210284Sjmallett            break;
399210284Sjmallett        case CVMX_BOARD_TYPE_BBGW_REF:
400210284Sjmallett            /* Port 1 on these boards is always Gigabit */
401210284Sjmallett            if (ipd_port == 2)
402215990Sjmallett            {
403210284Sjmallett                /* Port 2 is not hooked up */
404210284Sjmallett                result.u64 = 0;
405210284Sjmallett                return result;
406210284Sjmallett            }
407210284Sjmallett            else
408210284Sjmallett            {
409210284Sjmallett                /* Ports 0 and 1 connect to the switch */
410210284Sjmallett                result.s.link_up = 1;
411210284Sjmallett                result.s.full_duplex = 1;
412210284Sjmallett                result.s.speed = 1000;
413210284Sjmallett                return result;
414210284Sjmallett            }
415210284Sjmallett            break;
416210311Sjmallett	/* Private vendor-defined boards.  */
417210311Sjmallett#if defined(OCTEON_VENDOR_LANNER)
418215014Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
419215014Sjmallett	    /* Ports are BCM5482S */
420215014Sjmallett	    is_broadcom_phy = 1;
421215014Sjmallett	    break;
422210311Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
423216476Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
424210311Sjmallett	    /* Port 0 connects to the switch */
425210311Sjmallett	    if (ipd_port == 0)
426210311Sjmallett	    {
427210311Sjmallett                result.s.link_up = 1;
428210311Sjmallett                result.s.full_duplex = 1;
429210311Sjmallett                result.s.speed = 1000;
430210311Sjmallett		return result;
431210311Sjmallett	    }
432210311Sjmallett	    break;
433210311Sjmallett#endif
434210284Sjmallett    }
435210311Sjmallett#endif
436210284Sjmallett
437210284Sjmallett    phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
438210284Sjmallett    if (phy_addr != -1)
439210284Sjmallett    {
440210284Sjmallett        if (is_broadcom_phy)
441210284Sjmallett        {
442210284Sjmallett            /* Below we are going to read SMI/MDIO register 0x19 which works
443210284Sjmallett                on Broadcom parts */
444210284Sjmallett            int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19);
445210284Sjmallett            switch ((phy_status>>8) & 0x7)
446210284Sjmallett            {
447210284Sjmallett                case 0:
448210284Sjmallett                    result.u64 = 0;
449210284Sjmallett                    break;
450210284Sjmallett                case 1:
451210284Sjmallett                    result.s.link_up = 1;
452210284Sjmallett                    result.s.full_duplex = 0;
453210284Sjmallett                    result.s.speed = 10;
454210284Sjmallett                    break;
455210284Sjmallett                case 2:
456210284Sjmallett                    result.s.link_up = 1;
457210284Sjmallett                    result.s.full_duplex = 1;
458210284Sjmallett                    result.s.speed = 10;
459210284Sjmallett                    break;
460210284Sjmallett                case 3:
461210284Sjmallett                    result.s.link_up = 1;
462210284Sjmallett                    result.s.full_duplex = 0;
463210284Sjmallett                    result.s.speed = 100;
464210284Sjmallett                    break;
465210284Sjmallett                case 4:
466210284Sjmallett                    result.s.link_up = 1;
467210284Sjmallett                    result.s.full_duplex = 1;
468210284Sjmallett                    result.s.speed = 100;
469210284Sjmallett                    break;
470210284Sjmallett                case 5:
471210284Sjmallett                    result.s.link_up = 1;
472210284Sjmallett                    result.s.full_duplex = 1;
473210284Sjmallett                    result.s.speed = 100;
474210284Sjmallett                    break;
475210284Sjmallett                case 6:
476210284Sjmallett                    result.s.link_up = 1;
477210284Sjmallett                    result.s.full_duplex = 0;
478210284Sjmallett                    result.s.speed = 1000;
479210284Sjmallett                    break;
480210284Sjmallett                case 7:
481210284Sjmallett                    result.s.link_up = 1;
482210284Sjmallett                    result.s.full_duplex = 1;
483210284Sjmallett                    result.s.speed = 1000;
484210284Sjmallett                    break;
485210284Sjmallett            }
486210284Sjmallett        }
487210284Sjmallett        else
488210284Sjmallett        {
489210284Sjmallett            /* This code assumes we are using a Marvell Gigabit PHY. All the
490210284Sjmallett                speed information can be read from register 17 in one go. Somebody
491210284Sjmallett                using a different PHY will need to handle it above in the board
492210284Sjmallett                specific area */
493210284Sjmallett            int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
494210284Sjmallett
495210284Sjmallett            /* If the resolve bit 11 isn't set, see if autoneg is turned off
496210284Sjmallett                (bit 12, reg 0). The resolve bit doesn't get set properly when
497210284Sjmallett                autoneg is off, so force it */
498210284Sjmallett            if ((phy_status & (1<<11)) == 0)
499210284Sjmallett            {
500210284Sjmallett                int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
501210284Sjmallett                if ((auto_status & (1<<12)) == 0)
502210284Sjmallett                    phy_status |= 1<<11;
503210284Sjmallett            }
504210284Sjmallett
505210284Sjmallett            /* Only return a link if the PHY has finished auto negotiation
506210284Sjmallett                and set the resolved bit (bit 11) */
507210284Sjmallett            if (phy_status & (1<<11))
508210284Sjmallett            {
509210311Sjmallett#if defined(OCTEON_BOARD_CAPK_0100ND)
510210311Sjmallett                result.s.link_up = (phy_status>>10)&1;
511210311Sjmallett#else
512210284Sjmallett                result.s.link_up = 1;
513210311Sjmallett#endif
514210284Sjmallett                result.s.full_duplex = ((phy_status>>13)&1);
515210284Sjmallett                switch ((phy_status>>14)&3)
516210284Sjmallett                {
517210284Sjmallett                    case 0: /* 10 Mbps */
518210284Sjmallett                        result.s.speed = 10;
519210284Sjmallett                        break;
520210284Sjmallett                    case 1: /* 100 Mbps */
521210284Sjmallett                        result.s.speed = 100;
522210284Sjmallett                        break;
523210284Sjmallett                    case 2: /* 1 Gbps */
524210284Sjmallett                        result.s.speed = 1000;
525210284Sjmallett                        break;
526210284Sjmallett                    case 3: /* Illegal */
527210284Sjmallett                        result.u64 = 0;
528210284Sjmallett                        break;
529210284Sjmallett                }
530210284Sjmallett            }
531210284Sjmallett        }
532210284Sjmallett    }
533210284Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
534210284Sjmallett    {
535210284Sjmallett        /* We don't have a PHY address, so attempt to use in-band status. It is
536210284Sjmallett            really important that boards not supporting in-band status never get
537210284Sjmallett            here. Reading broken in-band status tends to do bad things */
538210284Sjmallett        cvmx_gmxx_rxx_rx_inbnd_t inband_status;
539210284Sjmallett        int interface = cvmx_helper_get_interface_num(ipd_port);
540210284Sjmallett        int index = cvmx_helper_get_interface_index_num(ipd_port);
541210284Sjmallett        inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
542210284Sjmallett
543210284Sjmallett        result.s.link_up = inband_status.s.status;
544210284Sjmallett        result.s.full_duplex = inband_status.s.duplex;
545210284Sjmallett        switch (inband_status.s.speed)
546210284Sjmallett        {
547210284Sjmallett            case 0: /* 10 Mbps */
548210284Sjmallett                result.s.speed = 10;
549210284Sjmallett                break;
550210284Sjmallett            case 1: /* 100 Mbps */
551210284Sjmallett                result.s.speed = 100;
552210284Sjmallett                break;
553210284Sjmallett            case 2: /* 1 Gbps */
554210284Sjmallett                result.s.speed = 1000;
555210284Sjmallett                break;
556210284Sjmallett            case 3: /* Illegal */
557210284Sjmallett                result.u64 = 0;
558210284Sjmallett                break;
559210284Sjmallett        }
560210284Sjmallett    }
561210284Sjmallett    else
562210284Sjmallett    {
563210284Sjmallett        /* We don't have a PHY address and we don't have in-band status. There
564210284Sjmallett            is no way to determine the link speed. Return down assuming this
565210284Sjmallett            port isn't wired */
566210284Sjmallett        result.u64 = 0;
567210284Sjmallett    }
568210284Sjmallett
569210284Sjmallett    /* If link is down, return all fields as zero. */
570210284Sjmallett    if (!result.s.link_up)
571210284Sjmallett        result.u64 = 0;
572210284Sjmallett
573210284Sjmallett    return result;
574210284Sjmallett}
575210284Sjmallett
576210284Sjmallett
577210284Sjmallett/**
578210284Sjmallett * This function as a board specific method of changing the PHY
579215990Sjmallett * speed, duplex, and autonegotiation. This programs the PHY and
580210284Sjmallett * not Octeon. This can be used to force Octeon's links to
581210284Sjmallett * specific settings.
582210284Sjmallett *
583210284Sjmallett * @param phy_addr  The address of the PHY to program
584215990Sjmallett * @param link_flags
585215990Sjmallett *                  Flags to control autonegotiation.  Bit 0 is autonegotiation
586215990Sjmallett *                  enable/disable to maintain backward compatibility.
587215990Sjmallett * @param link_info Link speed to program. If the speed is zero and autonegotiation
588210284Sjmallett *                  is enabled, all possible negotiation speeds are advertised.
589210284Sjmallett *
590210284Sjmallett * @return Zero on success, negative on failure
591210284Sjmallett */
592210284Sjmallettint cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags,
593210284Sjmallett                                   cvmx_helper_link_info_t link_info)
594210284Sjmallett{
595210284Sjmallett
596210284Sjmallett    /* Set the flow control settings based on link_flags */
597210284Sjmallett    if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch)
598210284Sjmallett    {
599210284Sjmallett        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
600210284Sjmallett        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
601210284Sjmallett        reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
602210284Sjmallett        reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
603210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
604210284Sjmallett    }
605210284Sjmallett
606210284Sjmallett    /* If speed isn't set and autoneg is on advertise all supported modes */
607210284Sjmallett    if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0))
608210284Sjmallett    {
609210284Sjmallett        cvmx_mdio_phy_reg_control_t reg_control;
610210284Sjmallett        cvmx_mdio_phy_reg_status_t reg_status;
611210284Sjmallett        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
612210284Sjmallett        cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
613210284Sjmallett        cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
614210284Sjmallett
615210284Sjmallett        reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
616210284Sjmallett        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
617210284Sjmallett        reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4;
618210284Sjmallett        reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full;
619210284Sjmallett        reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half;
620210284Sjmallett        reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full;
621210284Sjmallett        reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half;
622210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
623210284Sjmallett        if (reg_status.s.capable_extended_status)
624210284Sjmallett        {
625210284Sjmallett            reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
626210284Sjmallett            reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
627210284Sjmallett            reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full;
628210284Sjmallett            reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half;
629210284Sjmallett            cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
630210284Sjmallett        }
631210284Sjmallett        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
632210284Sjmallett        reg_control.s.autoneg_enable = 1;
633210284Sjmallett        reg_control.s.restart_autoneg = 1;
634210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
635210284Sjmallett    }
636210284Sjmallett    else if ((link_flags & set_phy_link_flags_autoneg))
637210284Sjmallett    {
638210284Sjmallett        cvmx_mdio_phy_reg_control_t reg_control;
639210284Sjmallett        cvmx_mdio_phy_reg_status_t reg_status;
640210284Sjmallett        cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
641210284Sjmallett        cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
642210284Sjmallett        cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
643210284Sjmallett
644210284Sjmallett        reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
645210284Sjmallett        reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
646210284Sjmallett        reg_autoneg_adver.s.advert_100base_t4 = 0;
647210284Sjmallett        reg_autoneg_adver.s.advert_10base_tx_full = 0;
648210284Sjmallett        reg_autoneg_adver.s.advert_10base_tx_half = 0;
649210284Sjmallett        reg_autoneg_adver.s.advert_100base_tx_full = 0;
650210284Sjmallett        reg_autoneg_adver.s.advert_100base_tx_half = 0;
651210284Sjmallett        if (reg_status.s.capable_extended_status)
652210284Sjmallett        {
653210284Sjmallett            reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
654210284Sjmallett            reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
655210284Sjmallett            reg_control_1000.s.advert_1000base_t_full = 0;
656210284Sjmallett            reg_control_1000.s.advert_1000base_t_half = 0;
657210284Sjmallett        }
658210284Sjmallett        switch (link_info.s.speed)
659210284Sjmallett        {
660210284Sjmallett            case 10:
661210284Sjmallett                reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex;
662210284Sjmallett                reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex;
663210284Sjmallett                break;
664210284Sjmallett            case 100:
665210284Sjmallett                reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex;
666210284Sjmallett                reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex;
667210284Sjmallett                break;
668210284Sjmallett            case 1000:
669210284Sjmallett                reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex;
670210284Sjmallett                reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex;
671210284Sjmallett                break;
672210284Sjmallett        }
673210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
674210284Sjmallett        if (reg_status.s.capable_extended_status)
675210284Sjmallett            cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
676210284Sjmallett        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
677210284Sjmallett        reg_control.s.autoneg_enable = 1;
678210284Sjmallett        reg_control.s.restart_autoneg = 1;
679210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
680210284Sjmallett    }
681210284Sjmallett    else
682210284Sjmallett    {
683210284Sjmallett        cvmx_mdio_phy_reg_control_t reg_control;
684210284Sjmallett        reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
685210284Sjmallett        reg_control.s.autoneg_enable = 0;
686210284Sjmallett        reg_control.s.restart_autoneg = 1;
687210284Sjmallett        reg_control.s.duplex = link_info.s.full_duplex;
688210284Sjmallett        if (link_info.s.speed == 1000)
689210284Sjmallett        {
690210284Sjmallett            reg_control.s.speed_msb = 1;
691210284Sjmallett            reg_control.s.speed_lsb = 0;
692210284Sjmallett        }
693210284Sjmallett        else if (link_info.s.speed == 100)
694210284Sjmallett        {
695210284Sjmallett            reg_control.s.speed_msb = 0;
696210284Sjmallett            reg_control.s.speed_lsb = 1;
697210284Sjmallett        }
698210284Sjmallett        else if (link_info.s.speed == 10)
699210284Sjmallett        {
700210284Sjmallett            reg_control.s.speed_msb = 0;
701210284Sjmallett            reg_control.s.speed_lsb = 0;
702210284Sjmallett        }
703210284Sjmallett        cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
704210284Sjmallett    }
705210284Sjmallett    return 0;
706210284Sjmallett}
707210284Sjmallett
708210284Sjmallett
709210284Sjmallett/**
710210284Sjmallett * @INTERNAL
711210284Sjmallett * This function is called by cvmx_helper_interface_probe() after it
712210284Sjmallett * determines the number of ports Octeon can support on a specific
713210284Sjmallett * interface. This function is the per board location to override
714210284Sjmallett * this value. It is called with the number of ports Octeon might
715210284Sjmallett * support and should return the number of actual ports on the
716210284Sjmallett * board.
717210284Sjmallett *
718215990Sjmallett * This function must be modified for every new Octeon board.
719210284Sjmallett * Internally it uses switch statements based on the cvmx_sysinfo
720215990Sjmallett * data to determine board types and revisions. It relies on the
721210284Sjmallett * fact that every Octeon board receives a unique board type
722210284Sjmallett * enumeration from the bootloader.
723210284Sjmallett *
724210284Sjmallett * @param interface Interface to probe
725210284Sjmallett * @param supported_ports
726210284Sjmallett *                  Number of ports Octeon supports.
727210284Sjmallett *
728210284Sjmallett * @return Number of ports the actual board supports. Many times this will
729210284Sjmallett *         simple be "support_ports".
730210284Sjmallett */
731210284Sjmallettint __cvmx_helper_board_interface_probe(int interface, int supported_ports)
732210284Sjmallett{
733210284Sjmallett    switch (cvmx_sysinfo_get()->board_type)
734210284Sjmallett    {
735210284Sjmallett        case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
736215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_A:
737215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_U:
738215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_G:
739210284Sjmallett            if (interface == 0)
740210284Sjmallett                return 2;
741210284Sjmallett	    break;
742210284Sjmallett        case CVMX_BOARD_TYPE_BBGW_REF:
743210284Sjmallett            if (interface == 0)
744210284Sjmallett                return 2;
745210284Sjmallett	    break;
746210284Sjmallett        case CVMX_BOARD_TYPE_NIC_XLE_4G:
747210284Sjmallett            if (interface == 0)
748210284Sjmallett                return 0;
749210284Sjmallett	    break;
750210284Sjmallett        /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
751210284Sjmallett            which we don't support. Disable ports connected to it */
752210284Sjmallett        case CVMX_BOARD_TYPE_EBH5600:
753210284Sjmallett            if (interface == 1)
754210284Sjmallett                return 0;
755210284Sjmallett	    break;
756215990Sjmallett        case CVMX_BOARD_TYPE_EBB5600:
757215990Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
758215990Sjmallett            if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_PICMG)
759215990Sjmallett                return 0;
760215990Sjmallett#endif
761215990Sjmallett	    break;
762215990Sjmallett        case CVMX_BOARD_TYPE_EBT5810:
763215990Sjmallett            return 1;  /* Two ports on each SPI: 1 hooked to MAC, 1 loopback
764215990Sjmallett                       ** Loopback disabled by default. */
765212844Sjmallett#if defined(OCTEON_VENDOR_LANNER)
766212844Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
767212844Sjmallett	    if (interface == 1)
768212844Sjmallett	        return 12;
769212844Sjmallett	    break;
770212844Sjmallett#endif
771210284Sjmallett    }
772210284Sjmallett#ifdef CVMX_BUILD_FOR_UBOOT
773210284Sjmallett    if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi"))
774210284Sjmallett        return 0;
775210284Sjmallett#endif
776210284Sjmallett    return supported_ports;
777210284Sjmallett}
778210284Sjmallett
779210284Sjmallett
780210284Sjmallett/**
781210284Sjmallett * @INTERNAL
782210284Sjmallett * Enable packet input/output from the hardware. This function is
783210284Sjmallett * called after by cvmx_helper_packet_hardware_enable() to
784210284Sjmallett * perform board specific initialization. For most boards
785210284Sjmallett * nothing is needed.
786210284Sjmallett *
787210284Sjmallett * @param interface Interface to enable
788210284Sjmallett *
789210284Sjmallett * @return Zero on success, negative on failure
790210284Sjmallett */
791210284Sjmallettint __cvmx_helper_board_hardware_enable(int interface)
792210284Sjmallett{
793210284Sjmallett    if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5)
794210284Sjmallett    {
795210284Sjmallett        if (interface == 0)
796210284Sjmallett        {
797210284Sjmallett            /* Different config for switch port */
798210284Sjmallett            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
799210284Sjmallett            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
800210284Sjmallett            /* Boards with gigabit WAN ports need a different setting that is
801210284Sjmallett                compatible with 100 Mbit settings */
802210284Sjmallett            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc);
803210284Sjmallett            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc);
804210284Sjmallett        }
805210284Sjmallett    }
806215990Sjmallett    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_LANAI2_U)
807215990Sjmallett    {
808215990Sjmallett        if (interface == 0)
809215990Sjmallett        {
810215990Sjmallett            cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 16);
811215990Sjmallett            cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 16);
812215990Sjmallett        }
813215990Sjmallett    }
814210284Sjmallett    else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5)
815210284Sjmallett    {
816215990Sjmallett        /* Broadcom PHYs require different ASX clocks. Unfortunately
817210284Sjmallett            many customer don't define a new board Id and simply
818210284Sjmallett            mangle the CN3010_EVB_HS5 */
819210284Sjmallett        if (interface == 0)
820210284Sjmallett        {
821210284Sjmallett            /* Some customers boards use a hacked up bootloader that identifies them as
822210284Sjmallett            ** CN3010_EVB_HS5 evaluation boards.  This leads to all kinds of configuration
823210284Sjmallett            ** problems.  Detect one case, and print warning, while trying to do the right thing.
824210284Sjmallett            */
825210284Sjmallett            int phy_addr = cvmx_helper_board_get_mii_address(0);
826210284Sjmallett            if (phy_addr != -1)
827210284Sjmallett            {
828210284Sjmallett                int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2);
829210284Sjmallett                /* Is it a Broadcom PHY? */
830210284Sjmallett                if (phy_identifier == 0x0143)
831210284Sjmallett                {
832210284Sjmallett                    cvmx_dprintf("\n");
833210284Sjmallett                    cvmx_dprintf("ERROR:\n");
834210284Sjmallett                    cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
835210284Sjmallett                    cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
836210284Sjmallett                    cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n");
837210284Sjmallett                    cvmx_dprintf("ERROR:\n");
838210284Sjmallett                    cvmx_dprintf("\n");
839210284Sjmallett                    cvmx_wait(1000000000);
840210284Sjmallett                    cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5);
841210284Sjmallett                    cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5);
842210284Sjmallett                }
843210284Sjmallett            }
844210284Sjmallett        }
845210284Sjmallett    }
846210284Sjmallett    return 0;
847210284Sjmallett}
848210284Sjmallett
849215990Sjmallett
850215990Sjmallett/**
851215990Sjmallett * @INTERNAL
852215990Sjmallett * Gets the clock type used for the USB block based on board type.
853215990Sjmallett * Used by the USB code for auto configuration of clock type.
854215990Sjmallett *
855215990Sjmallett * @return USB clock type enumeration
856215990Sjmallett */
857210284Sjmallettcvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void)
858210284Sjmallett{
859215990Sjmallett    switch (cvmx_sysinfo_get()->board_type)
860215990Sjmallett    {
861215990Sjmallett        case CVMX_BOARD_TYPE_BBGW_REF:
862215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_A:
863215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_U:
864215990Sjmallett        case CVMX_BOARD_TYPE_LANAI2_G:
865210311Sjmallett#if defined(OCTEON_VENDOR_LANNER)
866210311Sjmallett    case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
867216476Sjmallett    case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
868210311Sjmallett#endif
869210284Sjmallett            return USB_CLOCK_TYPE_CRYSTAL_12;
870210284Sjmallett    }
871210284Sjmallett    return USB_CLOCK_TYPE_REF_48;
872210284Sjmallett}
873210284Sjmallett
874215990Sjmallett
875215990Sjmallett/**
876215990Sjmallett * @INTERNAL
877215990Sjmallett * Adjusts the number of available USB ports on Octeon based on board
878215990Sjmallett * specifics.
879215990Sjmallett *
880215990Sjmallett * @param supported_ports expected number of ports based on chip type;
881215990Sjmallett *
882215990Sjmallett *
883215990Sjmallett * @return number of available usb ports, based on board specifics.
884215990Sjmallett *         Return value is supported_ports if function does not
885215990Sjmallett *         override.
886215990Sjmallett */
887210284Sjmallettint __cvmx_helper_board_usb_get_num_ports(int supported_ports)
888210284Sjmallett{
889215990Sjmallett    switch (cvmx_sysinfo_get()->board_type)
890215990Sjmallett    {
891210284Sjmallett        case CVMX_BOARD_TYPE_NIC_XLE_4G:
892210284Sjmallett            return 0;
893210284Sjmallett    }
894210284Sjmallett
895210284Sjmallett    return supported_ports;
896210284Sjmallett}
897210284Sjmallett
898210284Sjmallett
899