^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /***********************license start***************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Author: Cavium Networks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Contact: support@caviumnetworks.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * This file is part of the OCTEON SDK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2003-2018 Cavium, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * This file is free software; you can redistribute it and/or modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * it under the terms of the GNU General Public License, Version 2, as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * published by the Free Software Foundation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * This file is distributed in the hope that it will be useful, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * NONINFRINGEMENT. See the GNU General Public License for more
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * You should have received a copy of the GNU General Public License
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * along with this file; if not, write to the Free Software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * or visit http://www.gnu.org/licenses/.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * This file may also be available under a different license from Cavium.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * Contact Cavium Networks for more information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) ***********************license end**************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * Functions for SPI initialization, configuration,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * and monitoring.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <asm/octeon/octeon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <asm/octeon/cvmx-config.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <asm/octeon/cvmx-spi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <asm/octeon/cvmx-helper.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <asm/octeon/cvmx-pip-defs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <asm/octeon/cvmx-pko-defs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <asm/octeon/cvmx-spxx-defs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <asm/octeon/cvmx-stxx-defs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * CVMX_HELPER_SPI_TIMEOUT is used to determine how long the SPI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * initialization routines wait for SPI training. You can override the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * value using executive-config.h if necessary.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #ifndef CVMX_HELPER_SPI_TIMEOUT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define CVMX_HELPER_SPI_TIMEOUT 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) int __cvmx_helper_spi_enumerate(int interface)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) cvmx_spi4000_is_present(interface)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * Probe a SPI interface and determine the number of ports
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * connected to it. The SPI interface should still be down after
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * this call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * @interface: Interface to probe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * Returns Number of ports on the interface. Zero to disable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) int __cvmx_helper_spi_probe(int interface)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) int num_ports = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) cvmx_spi4000_is_present(interface)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) num_ports = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) union cvmx_pko_reg_crc_enable enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) num_ports = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * Unlike the SPI4000, most SPI devices don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * automatically put on the L2 CRC. For everything
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * except for the SPI4000 have PKO append the L2 CRC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * to the packet.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) enable.u64 = cvmx_read_csr(CVMX_PKO_REG_CRC_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) enable.s.enable |= 0xffff << (interface * 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) cvmx_write_csr(CVMX_PKO_REG_CRC_ENABLE, enable.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) __cvmx_helper_setup_gmx(interface, num_ports);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return num_ports;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * Bringup and enable a SPI interface. After this call packet I/O
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * should be fully functional. This is called with IPD enabled but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * PKO disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * @interface: Interface to bring up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * Returns Zero on success, negative on failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) int __cvmx_helper_spi_enable(int interface)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * Normally the ethernet L2 CRC is checked and stripped in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * GMX block. When you are using SPI, this isn' the case and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * IPD needs to check the L2 CRC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) int num_ports = cvmx_helper_ports_on_interface(interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) int ipd_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) for (ipd_port = interface * 16; ipd_port < interface * 16 + num_ports;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) ipd_port++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) union cvmx_pip_prt_cfgx port_config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) port_config.s.crc_en = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) cvmx_write_csr(CVMX_PIP_PRT_CFGX(ipd_port), port_config.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) cvmx_spi_start_interface(interface, CVMX_SPI_MODE_DUPLEX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) CVMX_HELPER_SPI_TIMEOUT, num_ports);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (cvmx_spi4000_is_present(interface))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) cvmx_spi4000_initialize(interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) __cvmx_interrupt_spxx_int_msk_enable(interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) __cvmx_interrupt_stxx_int_msk_enable(interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) __cvmx_interrupt_gmxx_enable(interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * Return the link state of an IPD/PKO port as returned by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * auto negotiation. The result of this function may not match
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * Octeon's link config if auto negotiation has changed since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * the last call to cvmx_helper_link_set().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * @ipd_port: IPD/PKO port to query
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * Returns Link state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) union cvmx_helper_link_info __cvmx_helper_spi_link_get(int ipd_port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) union cvmx_helper_link_info result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) int interface = cvmx_helper_get_interface_num(ipd_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) int index = cvmx_helper_get_interface_index_num(ipd_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) result.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* The simulator gives you a simulated full duplex link */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) result.s.link_up = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) result.s.full_duplex = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) result.s.speed = 10000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) } else if (cvmx_spi4000_is_present(interface)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) union cvmx_gmxx_rxx_rx_inbnd inband =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) cvmx_spi4000_check_speed(interface, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) result.s.link_up = inband.s.status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) result.s.full_duplex = inband.s.duplex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) switch (inband.s.speed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) case 0: /* 10 Mbps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) result.s.speed = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) case 1: /* 100 Mbps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) result.s.speed = 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) case 2: /* 1 Gbps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) result.s.speed = 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) case 3: /* Illegal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) result.s.speed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) result.s.link_up = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) /* For generic SPI we can't determine the link, just return some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) sane results */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) result.s.link_up = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) result.s.full_duplex = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) result.s.speed = 10000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * Configure an IPD/PKO port for the specified link state. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * function does not influence auto negotiation at the PHY level.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * The passed link state must always match the link state returned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * by cvmx_helper_link_get().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * @ipd_port: IPD/PKO port to configure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * @link_info: The new link state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * Returns Zero on success, negative on failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) int __cvmx_helper_spi_link_set(int ipd_port, union cvmx_helper_link_info link_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /* Nothing to do. If we have a SPI4000 then the setup was already performed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) by cvmx_spi4000_check_speed(). If not then there isn't any link
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }