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