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