| /***********************license start*************** | |
| * Author: Cavium Networks | |
| * | |
| * Contact: support@caviumnetworks.com | |
| * This file is part of the OCTEON SDK | |
| * | |
| * Copyright (c) 2003-2008 Cavium Networks | |
| * | |
| * This file is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU General Public License, Version 2, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This file is distributed in the hope that it will be useful, but | |
| * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | |
| * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | |
| * NONINFRINGEMENT. See the GNU General Public License for more | |
| * details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with this file; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
| * or visit http://www.gnu.org/licenses/. | |
| * | |
| * This file may also be available under a different license from Cavium. | |
| * Contact Cavium Networks for more information | |
| ***********************license end**************************************/ | |
| /* | |
| * | |
| * Helper functions to abstract board specific data about | |
| * network ports from the rest of the cvmx-helper files. | |
| */ | |
| #include <asm/octeon/octeon.h> | |
| #include <asm/octeon/cvmx-bootinfo.h> | |
| #include <asm/octeon/cvmx-config.h> | |
| #include <asm/octeon/cvmx-helper.h> | |
| #include <asm/octeon/cvmx-helper-util.h> | |
| #include <asm/octeon/cvmx-helper-board.h> | |
| #include <asm/octeon/cvmx-gmxx-defs.h> | |
| #include <asm/octeon/cvmx-asxx-defs.h> | |
| /** | |
| * Return the MII PHY address associated with the given IPD | |
| * port. A result of -1 means there isn't a MII capable PHY | |
| * connected to this port. On chips supporting multiple MII | |
| * busses the bus number is encoded in bits <15:8>. | |
| * | |
| * This function must be modified for every new Octeon board. | |
| * Internally it uses switch statements based on the cvmx_sysinfo | |
| * data to determine board types and revisions. It replies on the | |
| * fact that every Octeon board receives a unique board type | |
| * enumeration from the bootloader. | |
| * | |
| * @ipd_port: Octeon IPD port to get the MII address for. | |
| * | |
| * Returns MII PHY address and bus number or -1. | |
| */ | |
| int cvmx_helper_board_get_mii_address(int ipd_port) | |
| { | |
| switch (cvmx_sysinfo_get()->board_type) { | |
| case CVMX_BOARD_TYPE_SIM: | |
| /* Simulator doesn't have MII */ | |
| return -1; | |
| case CVMX_BOARD_TYPE_EBT3000: | |
| case CVMX_BOARD_TYPE_EBT5800: | |
| case CVMX_BOARD_TYPE_THUNDER: | |
| case CVMX_BOARD_TYPE_NICPRO2: | |
| /* Interface 0 is SPI4, interface 1 is RGMII */ | |
| if ((ipd_port >= 16) && (ipd_port < 20)) | |
| return ipd_port - 16; | |
| else | |
| return -1; | |
| case CVMX_BOARD_TYPE_KODAMA: | |
| case CVMX_BOARD_TYPE_EBH3100: | |
| case CVMX_BOARD_TYPE_HIKARI: | |
| case CVMX_BOARD_TYPE_CN3010_EVB_HS5: | |
| case CVMX_BOARD_TYPE_CN3005_EVB_HS5: | |
| case CVMX_BOARD_TYPE_CN3020_EVB_HS5: | |
| /* | |
| * Port 0 is WAN connected to a PHY, Port 1 is GMII | |
| * connected to a switch | |
| */ | |
| if (ipd_port == 0) | |
| return 4; | |
| else if (ipd_port == 1) | |
| return 9; | |
| else | |
| return -1; | |
| case CVMX_BOARD_TYPE_NAC38: | |
| /* Board has 8 RGMII ports PHYs are 0-7 */ | |
| if ((ipd_port >= 0) && (ipd_port < 4)) | |
| return ipd_port; | |
| else if ((ipd_port >= 16) && (ipd_port < 20)) | |
| return ipd_port - 16 + 4; | |
| else | |
| return -1; | |
| case CVMX_BOARD_TYPE_EBH3000: | |
| /* Board has dual SPI4 and no PHYs */ | |
| return -1; | |
| case CVMX_BOARD_TYPE_EBH5200: | |
| case CVMX_BOARD_TYPE_EBH5201: | |
| case CVMX_BOARD_TYPE_EBT5200: | |
| /* Board has 2 management ports */ | |
| if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && | |
| (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) | |
| return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT; | |
| /* | |
| * Board has 4 SGMII ports. The PHYs start right after the MII | |
| * ports MII0 = 0, MII1 = 1, SGMII = 2-5. | |
| */ | |
| if ((ipd_port >= 0) && (ipd_port < 4)) | |
| return ipd_port + 2; | |
| else | |
| return -1; | |
| case CVMX_BOARD_TYPE_EBH5600: | |
| case CVMX_BOARD_TYPE_EBH5601: | |
| case CVMX_BOARD_TYPE_EBH5610: | |
| /* Board has 1 management port */ | |
| if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) | |
| return 0; | |
| /* | |
| * Board has 8 SGMII ports. 4 connect out, two connect | |
| * to a switch, and 2 loop to each other | |
| */ | |
| if ((ipd_port >= 0) && (ipd_port < 4)) | |
| return ipd_port + 1; | |
| else | |
| return -1; | |
| case CVMX_BOARD_TYPE_CUST_NB5: | |
| if (ipd_port == 2) | |
| return 4; | |
| else | |
| return -1; | |
| case CVMX_BOARD_TYPE_NIC_XLE_4G: | |
| /* Board has 4 SGMII ports. connected QLM3(interface 1) */ | |
| if ((ipd_port >= 16) && (ipd_port < 20)) | |
| return ipd_port - 16 + 1; | |
| else | |
| return -1; | |
| case CVMX_BOARD_TYPE_NIC_XLE_10G: | |
| case CVMX_BOARD_TYPE_NIC10E: | |
| return -1; | |
| case CVMX_BOARD_TYPE_NIC4E: | |
| if (ipd_port >= 0 && ipd_port <= 3) | |
| return (ipd_port + 0x1f) & 0x1f; | |
| else | |
| return -1; | |
| case CVMX_BOARD_TYPE_NIC2E: | |
| if (ipd_port >= 0 && ipd_port <= 1) | |
| return ipd_port + 1; | |
| else | |
| return -1; | |
| case CVMX_BOARD_TYPE_BBGW_REF: | |
| /* | |
| * No PHYs are connected to Octeon, everything is | |
| * through switch. | |
| */ | |
| return -1; | |
| case CVMX_BOARD_TYPE_CUST_WSX16: | |
| if (ipd_port >= 0 && ipd_port <= 3) | |
| return ipd_port; | |
| else if (ipd_port >= 16 && ipd_port <= 19) | |
| return ipd_port - 16 + 4; | |
| else | |
| return -1; | |
| case CVMX_BOARD_TYPE_UBNT_E100: | |
| if (ipd_port >= 0 && ipd_port <= 2) | |
| return 7 - ipd_port; | |
| else | |
| return -1; | |
| case CVMX_BOARD_TYPE_KONTRON_S1901: | |
| if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) | |
| return 1; | |
| else | |
| return -1; | |
| } | |
| /* Some unknown board. Somebody forgot to update this function... */ | |
| cvmx_dprintf | |
| ("cvmx_helper_board_get_mii_address: Unknown board type %d\n", | |
| cvmx_sysinfo_get()->board_type); | |
| return -1; | |
| } | |
| /** | |
| * This function is the board specific method of determining an | |
| * ethernet ports link speed. Most Octeon boards have Marvell PHYs | |
| * and are handled by the fall through case. This function must be | |
| * updated for boards that don't have the normal Marvell PHYs. | |
| * | |
| * This function must be modified for every new Octeon board. | |
| * Internally it uses switch statements based on the cvmx_sysinfo | |
| * data to determine board types and revisions. It relies on the | |
| * fact that every Octeon board receives a unique board type | |
| * enumeration from the bootloader. | |
| * | |
| * @ipd_port: IPD input port associated with the port we want to get link | |
| * status for. | |
| * | |
| * Returns The ports link status. If the link isn't fully resolved, this must | |
| * return zero. | |
| */ | |
| cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) | |
| { | |
| cvmx_helper_link_info_t result; | |
| /* Unless we fix it later, all links are defaulted to down */ | |
| result.u64 = 0; | |
| /* | |
| * This switch statement should handle all ports that either don't use | |
| * Marvell PHYS, or don't support in-band status. | |
| */ | |
| switch (cvmx_sysinfo_get()->board_type) { | |
| case CVMX_BOARD_TYPE_SIM: | |
| /* The simulator gives you a simulated 1Gbps full duplex link */ | |
| result.s.link_up = 1; | |
| result.s.full_duplex = 1; | |
| result.s.speed = 1000; | |
| return result; | |
| case CVMX_BOARD_TYPE_EBH3100: | |
| case CVMX_BOARD_TYPE_CN3010_EVB_HS5: | |
| case CVMX_BOARD_TYPE_CN3005_EVB_HS5: | |
| case CVMX_BOARD_TYPE_CN3020_EVB_HS5: | |
| /* Port 1 on these boards is always Gigabit */ | |
| if (ipd_port == 1) { | |
| result.s.link_up = 1; | |
| result.s.full_duplex = 1; | |
| result.s.speed = 1000; | |
| return result; | |
| } | |
| /* Fall through to the generic code below */ | |
| break; | |
| case CVMX_BOARD_TYPE_CUST_NB5: | |
| /* Port 1 on these boards is always Gigabit */ | |
| if (ipd_port == 1) { | |
| result.s.link_up = 1; | |
| result.s.full_duplex = 1; | |
| result.s.speed = 1000; | |
| return result; | |
| } | |
| break; | |
| case CVMX_BOARD_TYPE_BBGW_REF: | |
| /* Port 1 on these boards is always Gigabit */ | |
| if (ipd_port == 2) { | |
| /* Port 2 is not hooked up */ | |
| result.u64 = 0; | |
| return result; | |
| } else { | |
| /* Ports 0 and 1 connect to the switch */ | |
| result.s.link_up = 1; | |
| result.s.full_duplex = 1; | |
| result.s.speed = 1000; | |
| return result; | |
| } | |
| break; | |
| } | |
| if (OCTEON_IS_MODEL(OCTEON_CN3XXX) | |
| || OCTEON_IS_MODEL(OCTEON_CN58XX) | |
| || OCTEON_IS_MODEL(OCTEON_CN50XX)) { | |
| /* | |
| * We don't have a PHY address, so attempt to use | |
| * in-band status. It is really important that boards | |
| * not supporting in-band status never get | |
| * here. Reading broken in-band status tends to do bad | |
| * things | |
| */ | |
| union cvmx_gmxx_rxx_rx_inbnd inband_status; | |
| int interface = cvmx_helper_get_interface_num(ipd_port); | |
| int index = cvmx_helper_get_interface_index_num(ipd_port); | |
| inband_status.u64 = | |
| cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface)); | |
| result.s.link_up = inband_status.s.status; | |
| result.s.full_duplex = inband_status.s.duplex; | |
| switch (inband_status.s.speed) { | |
| case 0: /* 10 Mbps */ | |
| result.s.speed = 10; | |
| break; | |
| case 1: /* 100 Mbps */ | |
| result.s.speed = 100; | |
| break; | |
| case 2: /* 1 Gbps */ | |
| result.s.speed = 1000; | |
| break; | |
| case 3: /* Illegal */ | |
| result.u64 = 0; | |
| break; | |
| } | |
| } else { | |
| /* | |
| * We don't have a PHY address and we don't have | |
| * in-band status. There is no way to determine the | |
| * link speed. Return down assuming this port isn't | |
| * wired | |
| */ | |
| result.u64 = 0; | |
| } | |
| /* If link is down, return all fields as zero. */ | |
| if (!result.s.link_up) | |
| result.u64 = 0; | |
| return result; | |
| } | |
| /** | |
| * This function is called by cvmx_helper_interface_probe() after it | |
| * determines the number of ports Octeon can support on a specific | |
| * interface. This function is the per board location to override | |
| * this value. It is called with the number of ports Octeon might | |
| * support and should return the number of actual ports on the | |
| * board. | |
| * | |
| * This function must be modifed for every new Octeon board. | |
| * Internally it uses switch statements based on the cvmx_sysinfo | |
| * data to determine board types and revisions. It relys on the | |
| * fact that every Octeon board receives a unique board type | |
| * enumeration from the bootloader. | |
| * | |
| * @interface: Interface to probe | |
| * @supported_ports: | |
| * Number of ports Octeon supports. | |
| * | |
| * Returns Number of ports the actual board supports. Many times this will | |
| * simple be "support_ports". | |
| */ | |
| int __cvmx_helper_board_interface_probe(int interface, int supported_ports) | |
| { | |
| switch (cvmx_sysinfo_get()->board_type) { | |
| case CVMX_BOARD_TYPE_CN3005_EVB_HS5: | |
| if (interface == 0) | |
| return 2; | |
| break; | |
| case CVMX_BOARD_TYPE_BBGW_REF: | |
| if (interface == 0) | |
| return 2; | |
| break; | |
| case CVMX_BOARD_TYPE_NIC_XLE_4G: | |
| if (interface == 0) | |
| return 0; | |
| break; | |
| /* The 2nd interface on the EBH5600 is connected to the Marvel switch, | |
| which we don't support. Disable ports connected to it */ | |
| case CVMX_BOARD_TYPE_EBH5600: | |
| if (interface == 1) | |
| return 0; | |
| break; | |
| } | |
| return supported_ports; | |
| } | |
| /** | |
| * Enable packet input/output from the hardware. This function is | |
| * called after by cvmx_helper_packet_hardware_enable() to | |
| * perform board specific initialization. For most boards | |
| * nothing is needed. | |
| * | |
| * @interface: Interface to enable | |
| * | |
| * Returns Zero on success, negative on failure | |
| */ | |
| int __cvmx_helper_board_hardware_enable(int interface) | |
| { | |
| if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5) { | |
| if (interface == 0) { | |
| /* Different config for switch port */ | |
| cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0); | |
| cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0); | |
| /* | |
| * Boards with gigabit WAN ports need a | |
| * different setting that is compatible with | |
| * 100 Mbit settings | |
| */ | |
| cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), | |
| 0xc); | |
| cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), | |
| 0xc); | |
| } | |
| } else if (cvmx_sysinfo_get()->board_type == | |
| CVMX_BOARD_TYPE_UBNT_E100) { | |
| cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0); | |
| cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0x10); | |
| cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0); | |
| cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0x10); | |
| cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(2, interface), 0); | |
| cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(2, interface), 0x10); | |
| } | |
| return 0; | |
| } | |
| /** | |
| * Get the clock type used for the USB block based on board type. | |
| * Used by the USB code for auto configuration of clock type. | |
| * | |
| * Return USB clock type enumeration | |
| */ | |
| enum cvmx_helper_board_usb_clock_types __cvmx_helper_board_usb_get_clock_type(void) | |
| { | |
| switch (cvmx_sysinfo_get()->board_type) { | |
| case CVMX_BOARD_TYPE_BBGW_REF: | |
| case CVMX_BOARD_TYPE_LANAI2_A: | |
| case CVMX_BOARD_TYPE_LANAI2_U: | |
| case CVMX_BOARD_TYPE_LANAI2_G: | |
| case CVMX_BOARD_TYPE_NIC10E_66: | |
| case CVMX_BOARD_TYPE_UBNT_E100: | |
| return USB_CLOCK_TYPE_CRYSTAL_12; | |
| case CVMX_BOARD_TYPE_NIC10E: | |
| return USB_CLOCK_TYPE_REF_12; | |
| default: | |
| break; | |
| } | |
| /* Most boards except NIC10e use a 12MHz crystal */ | |
| if (OCTEON_IS_OCTEON2()) | |
| return USB_CLOCK_TYPE_CRYSTAL_12; | |
| return USB_CLOCK_TYPE_REF_48; | |
| } |