1210284Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2010 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/** 45210284Sjmallett * @file 46210284Sjmallett * 47210284Sjmallett * Functions for SPI initialization, configuration, 48210284Sjmallett * and monitoring. 49210284Sjmallett * 50232812Sjmallett * <hr>$Revision: 70030 $<hr> 51210284Sjmallett */ 52215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 53215990Sjmallett#include <asm/octeon/cvmx.h> 54215990Sjmallett#include <asm/octeon/cvmx-config.h> 55215990Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 56215990Sjmallett#include <asm/octeon/cvmx-spi.h> 57215990Sjmallett#include <asm/octeon/cvmx-helper.h> 58215990Sjmallett#endif 59215990Sjmallett#include <asm/octeon/cvmx-pko-defs.h> 60215990Sjmallett#include <asm/octeon/cvmx-pip-defs.h> 61215990Sjmallett#else 62215990Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL) 63215990Sjmallett#include "executive-config.h" 64215990Sjmallett#include "cvmx-config.h" 65215990Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 66215990Sjmallett 67210284Sjmallett#include "cvmx.h" 68210284Sjmallett#include "cvmx-spi.h" 69210284Sjmallett#include "cvmx-sysinfo.h" 70210284Sjmallett#include "cvmx-helper.h" 71215990Sjmallett#endif 72215990Sjmallett#else 73215990Sjmallett#include "cvmx.h" 74215990Sjmallett#include "cvmx-spi.h" 75215990Sjmallett#include "cvmx-sysinfo.h" 76215990Sjmallett#include "cvmx-helper.h" 77215990Sjmallett#endif 78215990Sjmallett#endif 79210284Sjmallett 80210311Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 81215990Sjmallett 82210284Sjmallett/* CVMX_HELPER_SPI_TIMEOUT is used to determine how long the SPI initialization 83210284Sjmallett routines wait for SPI training. You can override the value using 84210284Sjmallett executive-config.h if necessary */ 85210284Sjmallett#ifndef CVMX_HELPER_SPI_TIMEOUT 86210284Sjmallett#define CVMX_HELPER_SPI_TIMEOUT 10 87210284Sjmallett#endif 88210284Sjmallett 89232812Sjmallettint __cvmx_helper_spi_enumerate(int interface) 90232812Sjmallett{ 91232812Sjmallett#if defined(OCTEON_VENDOR_LANNER) 92232812Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_LANNER_MR955) 93232812Sjmallett { 94232812Sjmallett cvmx_pko_reg_crc_enable_t enable; 95210284Sjmallett 96232812Sjmallett enable.u64 = cvmx_read_csr(CVMX_PKO_REG_CRC_ENABLE); 97232812Sjmallett enable.s.enable &= 0xffff << (16 - (interface*16)); 98232812Sjmallett cvmx_write_csr(CVMX_PKO_REG_CRC_ENABLE, enable.u64); 99232812Sjmallett 100232812Sjmallett if (interface == 1) 101232812Sjmallett return 12; 102232812Sjmallett /* XXX This is not entirely true. */ 103232812Sjmallett return 0; 104232812Sjmallett } 105232812Sjmallett#endif 106232812Sjmallett 107243265Sjmallett#if defined(OCTEON_VENDOR_RADISYS) 108243265Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE) { 109243265Sjmallett if (interface == 0) 110243265Sjmallett return 13; 111243265Sjmallett if (interface == 1) 112243265Sjmallett return 8; 113243265Sjmallett return 0; 114243265Sjmallett } 115243265Sjmallett#endif 116243265Sjmallett 117232812Sjmallett if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) && 118232812Sjmallett cvmx_spi4000_is_present(interface)) 119232812Sjmallett return 10; 120232812Sjmallett else 121232812Sjmallett return 16; 122232812Sjmallett} 123232812Sjmallett 124210284Sjmallett/** 125210284Sjmallett * @INTERNAL 126210284Sjmallett * Probe a SPI interface and determine the number of ports 127210284Sjmallett * connected to it. The SPI interface should still be down after 128210284Sjmallett * this call. 129210284Sjmallett * 130210284Sjmallett * @param interface Interface to probe 131210284Sjmallett * 132210284Sjmallett * @return Number of ports on the interface. Zero to disable. 133210284Sjmallett */ 134210284Sjmallettint __cvmx_helper_spi_probe(int interface) 135210284Sjmallett{ 136232812Sjmallett int num_ports = __cvmx_helper_spi_enumerate(interface); 137210284Sjmallett 138232812Sjmallett if (num_ports == 16) { 139232812Sjmallett cvmx_pko_reg_crc_enable_t enable; 140232812Sjmallett /* 141232812Sjmallett * Unlike the SPI4000, most SPI devices don't 142232812Sjmallett * automatically put on the L2 CRC. For everything 143232812Sjmallett * except for the SPI4000 have PKO append the L2 CRC 144232812Sjmallett * to the packet 145232812Sjmallett */ 146232812Sjmallett enable.u64 = cvmx_read_csr(CVMX_PKO_REG_CRC_ENABLE); 147232812Sjmallett enable.s.enable |= 0xffff << (interface*16); 148232812Sjmallett cvmx_write_csr(CVMX_PKO_REG_CRC_ENABLE, enable.u64); 149212844Sjmallett } 150232812Sjmallett __cvmx_helper_setup_gmx(interface, num_ports); 151232812Sjmallett return num_ports; 152210284Sjmallett} 153210284Sjmallett 154210284Sjmallett 155210284Sjmallett/** 156210284Sjmallett * @INTERNAL 157210284Sjmallett * Bringup and enable a SPI interface. After this call packet I/O 158210284Sjmallett * should be fully functional. This is called with IPD enabled but 159210284Sjmallett * PKO disabled. 160210284Sjmallett * 161210284Sjmallett * @param interface Interface to bring up 162210284Sjmallett * 163210284Sjmallett * @return Zero on success, negative on failure 164210284Sjmallett */ 165210284Sjmallettint __cvmx_helper_spi_enable(int interface) 166210284Sjmallett{ 167210284Sjmallett /* Normally the ethernet L2 CRC is checked and stripped in the GMX block. 168210284Sjmallett When you are using SPI, this isn' the case and IPD needs to check 169210284Sjmallett the L2 CRC */ 170210284Sjmallett int num_ports = cvmx_helper_ports_on_interface(interface); 171210284Sjmallett int ipd_port; 172210284Sjmallett for (ipd_port=interface*16; ipd_port<interface*16+num_ports; ipd_port++) 173210284Sjmallett { 174215990Sjmallett cvmx_pip_prt_cfgx_t port_config; 175210284Sjmallett port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port)); 176210284Sjmallett port_config.s.crc_en = 1; 177243260Sjmallett#ifdef OCTEON_VENDOR_RADISYS 178243260Sjmallett /* 179243260Sjmallett * Incoming packets on the RSYS4GBE have the FCS stripped. 180243260Sjmallett */ 181243260Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE) 182243260Sjmallett port_config.s.crc_en = 0; 183243260Sjmallett#endif 184210284Sjmallett cvmx_write_csr(CVMX_PIP_PRT_CFGX(ipd_port), port_config.u64); 185210284Sjmallett } 186210284Sjmallett 187210284Sjmallett if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) 188210284Sjmallett { 189210284Sjmallett cvmx_spi_start_interface(interface, CVMX_SPI_MODE_DUPLEX, CVMX_HELPER_SPI_TIMEOUT, num_ports); 190210284Sjmallett if (cvmx_spi4000_is_present(interface)) 191210284Sjmallett cvmx_spi4000_initialize(interface); 192210284Sjmallett } 193210284Sjmallett return 0; 194210284Sjmallett} 195210284Sjmallett 196210284Sjmallett/** 197210284Sjmallett * @INTERNAL 198210284Sjmallett * Return the link state of an IPD/PKO port as returned by 199210284Sjmallett * auto negotiation. The result of this function may not match 200210284Sjmallett * Octeon's link config if auto negotiation has changed since 201210284Sjmallett * the last call to cvmx_helper_link_set(). 202210284Sjmallett * 203210284Sjmallett * @param ipd_port IPD/PKO port to query 204210284Sjmallett * 205210284Sjmallett * @return Link state 206210284Sjmallett */ 207210284Sjmallettcvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port) 208210284Sjmallett{ 209210284Sjmallett cvmx_helper_link_info_t result; 210210284Sjmallett int interface = cvmx_helper_get_interface_num(ipd_port); 211210284Sjmallett int index = cvmx_helper_get_interface_index_num(ipd_port); 212210284Sjmallett result.u64 = 0; 213210284Sjmallett 214210284Sjmallett if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 215210284Sjmallett { 216210284Sjmallett /* The simulator gives you a simulated full duplex link */ 217210284Sjmallett result.s.link_up = 1; 218210284Sjmallett result.s.full_duplex = 1; 219210284Sjmallett result.s.speed = 10000; 220210284Sjmallett } 221210284Sjmallett else if (cvmx_spi4000_is_present(interface)) 222210284Sjmallett { 223210284Sjmallett cvmx_gmxx_rxx_rx_inbnd_t inband = cvmx_spi4000_check_speed(interface, index); 224210284Sjmallett result.s.link_up = inband.s.status; 225210284Sjmallett result.s.full_duplex = inband.s.duplex; 226210284Sjmallett switch (inband.s.speed) 227210284Sjmallett { 228210284Sjmallett case 0: /* 10 Mbps */ 229210284Sjmallett result.s.speed = 10; 230210284Sjmallett break; 231210284Sjmallett case 1: /* 100 Mbps */ 232210284Sjmallett result.s.speed = 100; 233210284Sjmallett break; 234210284Sjmallett case 2: /* 1 Gbps */ 235210284Sjmallett result.s.speed = 1000; 236210284Sjmallett break; 237210284Sjmallett case 3: /* Illegal */ 238210284Sjmallett result.s.speed = 0; 239210284Sjmallett result.s.link_up = 0; 240210284Sjmallett break; 241210284Sjmallett } 242210284Sjmallett } 243210284Sjmallett else 244210284Sjmallett { 245210284Sjmallett /* For generic SPI we can't determine the link, just return some 246210284Sjmallett sane results */ 247210284Sjmallett result.s.link_up = 1; 248210284Sjmallett result.s.full_duplex = 1; 249210284Sjmallett result.s.speed = 10000; 250210284Sjmallett } 251210284Sjmallett return result; 252210284Sjmallett} 253210284Sjmallett 254210284Sjmallett 255210284Sjmallett/** 256210284Sjmallett * @INTERNAL 257210284Sjmallett * Configure an IPD/PKO port for the specified link state. This 258210284Sjmallett * function does not influence auto negotiation at the PHY level. 259210284Sjmallett * The passed link state must always match the link state returned 260210284Sjmallett * by cvmx_helper_link_get(). It is normally best to use 261210284Sjmallett * cvmx_helper_link_autoconf() instead. 262210284Sjmallett * 263210284Sjmallett * @param ipd_port IPD/PKO port to configure 264210284Sjmallett * @param link_info The new link state 265210284Sjmallett * 266210284Sjmallett * @return Zero on success, negative on failure 267210284Sjmallett */ 268210284Sjmallettint __cvmx_helper_spi_link_set(int ipd_port, cvmx_helper_link_info_t link_info) 269210284Sjmallett{ 270210284Sjmallett /* Nothing to do. If we have a SPI4000 then the setup was already performed 271210284Sjmallett by cvmx_spi4000_check_speed(). If not then there isn't any link 272210284Sjmallett info */ 273210284Sjmallett return 0; 274210284Sjmallett} 275210284Sjmallett 276210284Sjmallett#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ 277210284Sjmallett 278