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 SGMII initialization, configuration,
30af866496SDavid Daney  * and monitoring.
31af866496SDavid Daney  */
32af866496SDavid Daney 
33af866496SDavid Daney #include <asm/octeon/octeon.h>
34af866496SDavid Daney 
35af866496SDavid Daney #include <asm/octeon/cvmx-config.h>
36af866496SDavid Daney 
37af866496SDavid Daney #include <asm/octeon/cvmx-helper.h>
38af866496SDavid Daney #include <asm/octeon/cvmx-helper-board.h>
39af866496SDavid Daney 
40af866496SDavid Daney #include <asm/octeon/cvmx-gmxx-defs.h>
41af866496SDavid Daney #include <asm/octeon/cvmx-pcsx-defs.h>
42840267e4SSteven J. Hill #include <asm/octeon/cvmx-pcsxx-defs.h>
43af866496SDavid Daney 
44af866496SDavid Daney /**
45af866496SDavid Daney  * Perform initialization required only once for an SGMII port.
46af866496SDavid Daney  *
47af866496SDavid Daney  * @interface: Interface to init
48af866496SDavid Daney  * @index:     Index of prot on the interface
49af866496SDavid Daney  *
50af866496SDavid Daney  * Returns Zero on success, negative on failure
51af866496SDavid Daney  */
__cvmx_helper_sgmii_hardware_init_one_time(int interface,int index)52af866496SDavid Daney static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index)
53af866496SDavid Daney {
54af866496SDavid Daney 	const uint64_t clock_mhz = cvmx_sysinfo_get()->cpu_clock_hz / 1000000;
55af866496SDavid Daney 	union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
56af866496SDavid Daney 	union cvmx_pcsx_linkx_timer_count_reg pcsx_linkx_timer_count_reg;
57af866496SDavid Daney 	union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
58af866496SDavid Daney 
59af866496SDavid Daney 	/* Disable GMX */
60af866496SDavid Daney 	gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
61af866496SDavid Daney 	gmxx_prtx_cfg.s.en = 0;
62af866496SDavid Daney 	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
63af866496SDavid Daney 
64af866496SDavid Daney 	/*
65af866496SDavid Daney 	 * Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the
66af866496SDavid Daney 	 * appropriate value. 1000BASE-X specifies a 10ms
67af866496SDavid Daney 	 * interval. SGMII specifies a 1.6ms interval.
68af866496SDavid Daney 	 */
69af866496SDavid Daney 	pcs_misc_ctl_reg.u64 =
70af866496SDavid Daney 	    cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
71af866496SDavid Daney 	pcsx_linkx_timer_count_reg.u64 =
72af866496SDavid Daney 	    cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface));
73af866496SDavid Daney 	if (pcs_misc_ctl_reg.s.mode) {
74af866496SDavid Daney 		/* 1000BASE-X */
75af866496SDavid Daney 		pcsx_linkx_timer_count_reg.s.count =
76af866496SDavid Daney 		    (10000ull * clock_mhz) >> 10;
77af866496SDavid Daney 	} else {
78af866496SDavid Daney 		/* SGMII */
79af866496SDavid Daney 		pcsx_linkx_timer_count_reg.s.count =
80af866496SDavid Daney 		    (1600ull * clock_mhz) >> 10;
81af866496SDavid Daney 	}
82af866496SDavid Daney 	cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface),
83af866496SDavid Daney 		       pcsx_linkx_timer_count_reg.u64);
84af866496SDavid Daney 
85af866496SDavid Daney 	/*
86af866496SDavid Daney 	 * Write the advertisement register to be used as the
87af866496SDavid Daney 	 * tx_Config_Reg<D15:D0> of the autonegotiation.  In
88af866496SDavid Daney 	 * 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG.
89af866496SDavid Daney 	 * In SGMII PHY mode, tx_Config_Reg<D15:D0> is
90af866496SDavid Daney 	 * PCS*_SGM*_AN_ADV_REG.  In SGMII MAC mode,
91af866496SDavid Daney 	 * tx_Config_Reg<D15:D0> is the fixed value 0x4001, so this
92af866496SDavid Daney 	 * step can be skipped.
93af866496SDavid Daney 	 */
94af866496SDavid Daney 	if (pcs_misc_ctl_reg.s.mode) {
95af866496SDavid Daney 		/* 1000BASE-X */
96af866496SDavid Daney 		union cvmx_pcsx_anx_adv_reg pcsx_anx_adv_reg;
97af866496SDavid Daney 		pcsx_anx_adv_reg.u64 =
98af866496SDavid Daney 		    cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface));
99af866496SDavid Daney 		pcsx_anx_adv_reg.s.rem_flt = 0;
100af866496SDavid Daney 		pcsx_anx_adv_reg.s.pause = 3;
101af866496SDavid Daney 		pcsx_anx_adv_reg.s.hfd = 1;
102af866496SDavid Daney 		pcsx_anx_adv_reg.s.fd = 1;
103af866496SDavid Daney 		cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index, interface),
104af866496SDavid Daney 			       pcsx_anx_adv_reg.u64);
105af866496SDavid Daney 	} else {
106af866496SDavid Daney 		union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
107af866496SDavid Daney 		pcsx_miscx_ctl_reg.u64 =
108af866496SDavid Daney 		    cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
109af866496SDavid Daney 		if (pcsx_miscx_ctl_reg.s.mac_phy) {
110af866496SDavid Daney 			/* PHY Mode */
111af866496SDavid Daney 			union cvmx_pcsx_sgmx_an_adv_reg pcsx_sgmx_an_adv_reg;
112af866496SDavid Daney 			pcsx_sgmx_an_adv_reg.u64 =
113af866496SDavid Daney 			    cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG
114af866496SDavid Daney 					  (index, interface));
115af866496SDavid Daney 			pcsx_sgmx_an_adv_reg.s.link = 1;
116af866496SDavid Daney 			pcsx_sgmx_an_adv_reg.s.dup = 1;
117af866496SDavid Daney 			pcsx_sgmx_an_adv_reg.s.speed = 2;
118af866496SDavid Daney 			cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG
119af866496SDavid Daney 				       (index, interface),
120af866496SDavid Daney 				       pcsx_sgmx_an_adv_reg.u64);
121af866496SDavid Daney 		} else {
122af866496SDavid Daney 			/* MAC Mode - Nothing to do */
123af866496SDavid Daney 		}
124af866496SDavid Daney 	}
125af866496SDavid Daney 	return 0;
126af866496SDavid Daney }
127af866496SDavid Daney 
128af866496SDavid Daney /**
129af866496SDavid Daney  * Initialize the SERTES link for the first time or after a loss
130af866496SDavid Daney  * of link.
131af866496SDavid Daney  *
132af866496SDavid Daney  * @interface: Interface to init
133af866496SDavid Daney  * @index:     Index of prot on the interface
134af866496SDavid Daney  *
135af866496SDavid Daney  * Returns Zero on success, negative on failure
136af866496SDavid Daney  */
__cvmx_helper_sgmii_hardware_init_link(int interface,int index)137af866496SDavid Daney static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index)
138af866496SDavid Daney {
139af866496SDavid Daney 	union cvmx_pcsx_mrx_control_reg control_reg;
140af866496SDavid Daney 
141af866496SDavid Daney 	/*
142af866496SDavid Daney 	 * Take PCS through a reset sequence.
143af866496SDavid Daney 	 * PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero.
144af866496SDavid Daney 	 * Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the
145af866496SDavid Daney 	 * value of the other PCS*_MR*_CONTROL_REG bits).  Read
146af866496SDavid Daney 	 * PCS*_MR*_CONTROL_REG[RESET] until it changes value to
147af866496SDavid Daney 	 * zero.
148af866496SDavid Daney 	 */
149af866496SDavid Daney 	control_reg.u64 =
150af866496SDavid Daney 	    cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
151af866496SDavid Daney 	if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) {
152af866496SDavid Daney 		control_reg.s.reset = 1;
153af866496SDavid Daney 		cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
154af866496SDavid Daney 			       control_reg.u64);
155af866496SDavid Daney 		if (CVMX_WAIT_FOR_FIELD64
156af866496SDavid Daney 		    (CVMX_PCSX_MRX_CONTROL_REG(index, interface),
157af866496SDavid Daney 		     union cvmx_pcsx_mrx_control_reg, reset, ==, 0, 10000)) {
158af866496SDavid Daney 			cvmx_dprintf("SGMII%d: Timeout waiting for port %d "
159af866496SDavid Daney 				     "to finish reset\n",
160af866496SDavid Daney 			     interface, index);
161af866496SDavid Daney 			return -1;
162af866496SDavid Daney 		}
163af866496SDavid Daney 	}
164af866496SDavid Daney 
165af866496SDavid Daney 	/*
166af866496SDavid Daney 	 * Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh
167af866496SDavid Daney 	 * sgmii negotiation starts.
168af866496SDavid Daney 	 */
169af866496SDavid Daney 	control_reg.s.rst_an = 1;
170af866496SDavid Daney 	control_reg.s.an_en = 1;
171af866496SDavid Daney 	control_reg.s.pwr_dn = 0;
172af866496SDavid Daney 	cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
173af866496SDavid Daney 		       control_reg.u64);
174af866496SDavid Daney 
175af866496SDavid Daney 	/*
176af866496SDavid Daney 	 * Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating
177af866496SDavid Daney 	 * that sgmii autonegotiation is complete. In MAC mode this
178af866496SDavid Daney 	 * isn't an ethernet link, but a link between Octeon and the
179af866496SDavid Daney 	 * PHY.
180af866496SDavid Daney 	 */
181af866496SDavid Daney 	if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
182af866496SDavid Daney 	    CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface),
183af866496SDavid Daney 				  union cvmx_pcsx_mrx_status_reg, an_cpt, ==, 1,
184af866496SDavid Daney 				  10000)) {
185af866496SDavid Daney 		/* cvmx_dprintf("SGMII%d: Port %d link timeout\n", interface, index); */
186af866496SDavid Daney 		return -1;
187af866496SDavid Daney 	}
188af866496SDavid Daney 	return 0;
189af866496SDavid Daney }
190af866496SDavid Daney 
191af866496SDavid Daney /**
192af866496SDavid Daney  * Configure an SGMII link to the specified speed after the SERTES
193af866496SDavid Daney  * link is up.
194af866496SDavid Daney  *
195af866496SDavid Daney  * @interface: Interface to init
196af866496SDavid Daney  * @index:     Index of prot on the interface
197af866496SDavid Daney  * @link_info: Link state to configure
198af866496SDavid Daney  *
199af866496SDavid Daney  * Returns Zero on success, negative on failure
200af866496SDavid Daney  */
__cvmx_helper_sgmii_hardware_init_link_speed(int interface,int index,union cvmx_helper_link_info link_info)201af866496SDavid Daney static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface,
202af866496SDavid Daney 							int index,
203f7d2bdcbSChris Packham 							union cvmx_helper_link_info
204af866496SDavid Daney 							link_info)
205af866496SDavid Daney {
206af866496SDavid Daney 	int is_enabled;
207af866496SDavid Daney 	union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
208af866496SDavid Daney 	union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
209af866496SDavid Daney 
210af866496SDavid Daney 	/* Disable GMX before we make any changes. Remember the enable state */
211af866496SDavid Daney 	gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
212af866496SDavid Daney 	is_enabled = gmxx_prtx_cfg.s.en;
213af866496SDavid Daney 	gmxx_prtx_cfg.s.en = 0;
214af866496SDavid Daney 	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
215af866496SDavid Daney 
216af866496SDavid Daney 	/* Wait for GMX to be idle */
217af866496SDavid Daney 	if (CVMX_WAIT_FOR_FIELD64
218af866496SDavid Daney 	    (CVMX_GMXX_PRTX_CFG(index, interface), union cvmx_gmxx_prtx_cfg,
219af866496SDavid Daney 	     rx_idle, ==, 1, 10000)
220af866496SDavid Daney 	    || CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface),
221af866496SDavid Daney 				     union cvmx_gmxx_prtx_cfg, tx_idle, ==, 1,
222af866496SDavid Daney 				     10000)) {
223af866496SDavid Daney 		cvmx_dprintf
224af866496SDavid Daney 		    ("SGMII%d: Timeout waiting for port %d to be idle\n",
225af866496SDavid Daney 		     interface, index);
226af866496SDavid Daney 		return -1;
227af866496SDavid Daney 	}
228af866496SDavid Daney 
229af866496SDavid Daney 	/* Read GMX CFG again to make sure the disable completed */
230af866496SDavid Daney 	gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
231af866496SDavid Daney 
232af866496SDavid Daney 	/*
233af866496SDavid Daney 	 * Get the misc control for PCS. We will need to set the
234af866496SDavid Daney 	 * duplication amount.
235af866496SDavid Daney 	 */
236af866496SDavid Daney 	pcsx_miscx_ctl_reg.u64 =
237af866496SDavid Daney 	    cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
238af866496SDavid Daney 
239af866496SDavid Daney 	/*
240af866496SDavid Daney 	 * Use GMXENO to force the link down if the status we get says
241af866496SDavid Daney 	 * it should be down.
242af866496SDavid Daney 	 */
243af866496SDavid Daney 	pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up;
244af866496SDavid Daney 
245af866496SDavid Daney 	/* Only change the duplex setting if the link is up */
246af866496SDavid Daney 	if (link_info.s.link_up)
247af866496SDavid Daney 		gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex;
248af866496SDavid Daney 
249af866496SDavid Daney 	/* Do speed based setting for GMX */
250af866496SDavid Daney 	switch (link_info.s.speed) {
251af866496SDavid Daney 	case 10:
252af866496SDavid Daney 		gmxx_prtx_cfg.s.speed = 0;
253af866496SDavid Daney 		gmxx_prtx_cfg.s.speed_msb = 1;
254af866496SDavid Daney 		gmxx_prtx_cfg.s.slottime = 0;
255af866496SDavid Daney 		/* Setting from GMX-603 */
256af866496SDavid Daney 		pcsx_miscx_ctl_reg.s.samp_pt = 25;
257af866496SDavid Daney 		cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
258af866496SDavid Daney 		cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
259af866496SDavid Daney 		break;
260af866496SDavid Daney 	case 100:
261af866496SDavid Daney 		gmxx_prtx_cfg.s.speed = 0;
262af866496SDavid Daney 		gmxx_prtx_cfg.s.speed_msb = 0;
263af866496SDavid Daney 		gmxx_prtx_cfg.s.slottime = 0;
264af866496SDavid Daney 		pcsx_miscx_ctl_reg.s.samp_pt = 0x5;
265af866496SDavid Daney 		cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
266af866496SDavid Daney 		cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
267af866496SDavid Daney 		break;
268af866496SDavid Daney 	case 1000:
269af866496SDavid Daney 		gmxx_prtx_cfg.s.speed = 1;
270af866496SDavid Daney 		gmxx_prtx_cfg.s.speed_msb = 0;
271af866496SDavid Daney 		gmxx_prtx_cfg.s.slottime = 1;
272af866496SDavid Daney 		pcsx_miscx_ctl_reg.s.samp_pt = 1;
273af866496SDavid Daney 		cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 512);
274af866496SDavid Daney 		cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 8192);
275af866496SDavid Daney 		break;
276af866496SDavid Daney 	default:
277af866496SDavid Daney 		break;
278af866496SDavid Daney 	}
279af866496SDavid Daney 
280af866496SDavid Daney 	/* Write the new misc control for PCS */
281af866496SDavid Daney 	cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
282af866496SDavid Daney 		       pcsx_miscx_ctl_reg.u64);
283af866496SDavid Daney 
284af866496SDavid Daney 	/* Write the new GMX settings with the port still disabled */
285af866496SDavid Daney 	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
286af866496SDavid Daney 
287af866496SDavid Daney 	/* Read GMX CFG again to make sure the config completed */
288af866496SDavid Daney 	gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
289af866496SDavid Daney 
290af866496SDavid Daney 	/* Restore the enabled / disabled state */
291af866496SDavid Daney 	gmxx_prtx_cfg.s.en = is_enabled;
292af866496SDavid Daney 	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
293af866496SDavid Daney 
294af866496SDavid Daney 	return 0;
295af866496SDavid Daney }
296af866496SDavid Daney 
297af866496SDavid Daney /**
298af866496SDavid Daney  * Bring up the SGMII interface to be ready for packet I/O but
299af866496SDavid Daney  * leave I/O disabled using the GMX override. This function
300af866496SDavid Daney  * follows the bringup documented in 10.6.3 of the manual.
301af866496SDavid Daney  *
302af866496SDavid Daney  * @interface: Interface to bringup
303af866496SDavid Daney  * @num_ports: Number of ports on the interface
304af866496SDavid Daney  *
305af866496SDavid Daney  * Returns Zero on success, negative on failure
306af866496SDavid Daney  */
__cvmx_helper_sgmii_hardware_init(int interface,int num_ports)307af866496SDavid Daney static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
308af866496SDavid Daney {
309af866496SDavid Daney 	int index;
310af866496SDavid Daney 
311af866496SDavid Daney 	__cvmx_helper_setup_gmx(interface, num_ports);
312af866496SDavid Daney 
313af866496SDavid Daney 	for (index = 0; index < num_ports; index++) {
314af866496SDavid Daney 		int ipd_port = cvmx_helper_get_ipd_port(interface, index);
315af866496SDavid Daney 		__cvmx_helper_sgmii_hardware_init_one_time(interface, index);
316ec3a2207SDavid Daney 		/* Linux kernel driver will call ....link_set with the
317ec3a2207SDavid Daney 		 * proper link state. In the simulator there is no
318ec3a2207SDavid Daney 		 * link state polling and hence it is set from
319ec3a2207SDavid Daney 		 * here.
320ec3a2207SDavid Daney 		 */
321ec3a2207SDavid Daney 		if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
322af866496SDavid Daney 			__cvmx_helper_sgmii_link_set(ipd_port,
323ec3a2207SDavid Daney 				       __cvmx_helper_sgmii_link_get(ipd_port));
324af866496SDavid Daney 	}
325af866496SDavid Daney 
326af866496SDavid Daney 	return 0;
327af866496SDavid Daney }
328af866496SDavid Daney 
__cvmx_helper_sgmii_enumerate(int interface)32937d3bfd9SDavid Daney int __cvmx_helper_sgmii_enumerate(int interface)
33037d3bfd9SDavid Daney {
33137d3bfd9SDavid Daney 	return 4;
33237d3bfd9SDavid Daney }
333af866496SDavid Daney /**
334af866496SDavid Daney  * Probe a SGMII interface and determine the number of ports
335af866496SDavid Daney  * connected to it. The SGMII interface should still be down after
336af866496SDavid Daney  * this call.
337af866496SDavid Daney  *
338af866496SDavid Daney  * @interface: Interface to probe
339af866496SDavid Daney  *
340af866496SDavid Daney  * Returns Number of ports on the interface. Zero to disable.
341af866496SDavid Daney  */
__cvmx_helper_sgmii_probe(int interface)342af866496SDavid Daney int __cvmx_helper_sgmii_probe(int interface)
343af866496SDavid Daney {
344af866496SDavid Daney 	union cvmx_gmxx_inf_mode mode;
345af866496SDavid Daney 
346af866496SDavid Daney 	/*
347af866496SDavid Daney 	 * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
348af866496SDavid Daney 	 * interface needs to be enabled before IPD otherwise per port
349af866496SDavid Daney 	 * backpressure may not work properly
350af866496SDavid Daney 	 */
351af866496SDavid Daney 	mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
352af866496SDavid Daney 	mode.s.en = 1;
353af866496SDavid Daney 	cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
35437d3bfd9SDavid Daney 	return __cvmx_helper_sgmii_enumerate(interface);
355af866496SDavid Daney }
356af866496SDavid Daney 
357af866496SDavid Daney /**
358af866496SDavid Daney  * Bringup and enable a SGMII interface. After this call packet
359af866496SDavid Daney  * I/O should be fully functional. This is called with IPD
360af866496SDavid Daney  * enabled but PKO disabled.
361af866496SDavid Daney  *
362af866496SDavid Daney  * @interface: Interface to bring up
363af866496SDavid Daney  *
364af866496SDavid Daney  * Returns Zero on success, negative on failure
365af866496SDavid Daney  */
__cvmx_helper_sgmii_enable(int interface)366af866496SDavid Daney int __cvmx_helper_sgmii_enable(int interface)
367af866496SDavid Daney {
368af866496SDavid Daney 	int num_ports = cvmx_helper_ports_on_interface(interface);
369af866496SDavid Daney 	int index;
370af866496SDavid Daney 
371af866496SDavid Daney 	__cvmx_helper_sgmii_hardware_init(interface, num_ports);
372af866496SDavid Daney 
373af866496SDavid Daney 	for (index = 0; index < num_ports; index++) {
374af866496SDavid Daney 		union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
375af866496SDavid Daney 		gmxx_prtx_cfg.u64 =
376af866496SDavid Daney 		    cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
377af866496SDavid Daney 		gmxx_prtx_cfg.s.en = 1;
378af866496SDavid Daney 		cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
379af866496SDavid Daney 			       gmxx_prtx_cfg.u64);
380af866496SDavid Daney 		__cvmx_interrupt_pcsx_intx_en_reg_enable(index, interface);
381af866496SDavid Daney 	}
382af866496SDavid Daney 	__cvmx_interrupt_pcsxx_int_en_reg_enable(interface);
383af866496SDavid Daney 	__cvmx_interrupt_gmxx_enable(interface);
384af866496SDavid Daney 	return 0;
385af866496SDavid Daney }
386af866496SDavid Daney 
387af866496SDavid Daney /**
388af866496SDavid Daney  * Return the link state of an IPD/PKO port as returned by
389af866496SDavid Daney  * auto negotiation. The result of this function may not match
390af866496SDavid Daney  * Octeon's link config if auto negotiation has changed since
391af866496SDavid Daney  * the last call to cvmx_helper_link_set().
392af866496SDavid Daney  *
393af866496SDavid Daney  * @ipd_port: IPD/PKO port to query
394af866496SDavid Daney  *
395af866496SDavid Daney  * Returns Link state
396af866496SDavid Daney  */
__cvmx_helper_sgmii_link_get(int ipd_port)397f7d2bdcbSChris Packham union cvmx_helper_link_info __cvmx_helper_sgmii_link_get(int ipd_port)
398af866496SDavid Daney {
399f7d2bdcbSChris Packham 	union cvmx_helper_link_info result;
400af866496SDavid Daney 	union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
401af866496SDavid Daney 	int interface = cvmx_helper_get_interface_num(ipd_port);
402af866496SDavid Daney 	int index = cvmx_helper_get_interface_index_num(ipd_port);
403af866496SDavid Daney 	union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
404af866496SDavid Daney 
405af866496SDavid Daney 	result.u64 = 0;
406af866496SDavid Daney 
407af866496SDavid Daney 	if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) {
408af866496SDavid Daney 		/* The simulator gives you a simulated 1Gbps full duplex link */
409af866496SDavid Daney 		result.s.link_up = 1;
410af866496SDavid Daney 		result.s.full_duplex = 1;
411af866496SDavid Daney 		result.s.speed = 1000;
412af866496SDavid Daney 		return result;
413af866496SDavid Daney 	}
414af866496SDavid Daney 
415af866496SDavid Daney 	pcsx_mrx_control_reg.u64 =
416af866496SDavid Daney 	    cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
417af866496SDavid Daney 	if (pcsx_mrx_control_reg.s.loopbck1) {
418af866496SDavid Daney 		/* Force 1Gbps full duplex link for internal loopback */
419af866496SDavid Daney 		result.s.link_up = 1;
420af866496SDavid Daney 		result.s.full_duplex = 1;
421af866496SDavid Daney 		result.s.speed = 1000;
422af866496SDavid Daney 		return result;
423af866496SDavid Daney 	}
424af866496SDavid Daney 
425af866496SDavid Daney 	pcs_misc_ctl_reg.u64 =
426af866496SDavid Daney 	    cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
427af866496SDavid Daney 	if (pcs_misc_ctl_reg.s.mode) {
428af866496SDavid Daney 		/* 1000BASE-X */
429af866496SDavid Daney 		/* FIXME */
430af866496SDavid Daney 	} else {
431af866496SDavid Daney 		union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
432af866496SDavid Daney 		pcsx_miscx_ctl_reg.u64 =
433af866496SDavid Daney 		    cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
434af866496SDavid Daney 		if (pcsx_miscx_ctl_reg.s.mac_phy) {
435af866496SDavid Daney 			/* PHY Mode */
436af866496SDavid Daney 			union cvmx_pcsx_mrx_status_reg pcsx_mrx_status_reg;
437af866496SDavid Daney 			union cvmx_pcsx_anx_results_reg pcsx_anx_results_reg;
438af866496SDavid Daney 
439af866496SDavid Daney 			/*
440af866496SDavid Daney 			 * Don't bother continuing if the SERTES low
441af866496SDavid Daney 			 * level link is down
442af866496SDavid Daney 			 */
443af866496SDavid Daney 			pcsx_mrx_status_reg.u64 =
444af866496SDavid Daney 			    cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG
445af866496SDavid Daney 					  (index, interface));
446af866496SDavid Daney 			if (pcsx_mrx_status_reg.s.lnk_st == 0) {
447af866496SDavid Daney 				if (__cvmx_helper_sgmii_hardware_init_link
448af866496SDavid Daney 				    (interface, index) != 0)
449af866496SDavid Daney 					return result;
450af866496SDavid Daney 			}
451af866496SDavid Daney 
452af866496SDavid Daney 			/* Read the autoneg results */
453af866496SDavid Daney 			pcsx_anx_results_reg.u64 =
454af866496SDavid Daney 			    cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG
455af866496SDavid Daney 					  (index, interface));
456af866496SDavid Daney 			if (pcsx_anx_results_reg.s.an_cpt) {
457af866496SDavid Daney 				/*
458af866496SDavid Daney 				 * Auto negotiation is complete. Set
459af866496SDavid Daney 				 * status accordingly.
460af866496SDavid Daney 				 */
461af866496SDavid Daney 				result.s.full_duplex =
462af866496SDavid Daney 				    pcsx_anx_results_reg.s.dup;
463af866496SDavid Daney 				result.s.link_up =
464af866496SDavid Daney 				    pcsx_anx_results_reg.s.link_ok;
465af866496SDavid Daney 				switch (pcsx_anx_results_reg.s.spd) {
466af866496SDavid Daney 				case 0:
467af866496SDavid Daney 					result.s.speed = 10;
468af866496SDavid Daney 					break;
469af866496SDavid Daney 				case 1:
470af866496SDavid Daney 					result.s.speed = 100;
471af866496SDavid Daney 					break;
472af866496SDavid Daney 				case 2:
473af866496SDavid Daney 					result.s.speed = 1000;
474af866496SDavid Daney 					break;
475af866496SDavid Daney 				default:
476af866496SDavid Daney 					result.s.speed = 0;
477af866496SDavid Daney 					result.s.link_up = 0;
478af866496SDavid Daney 					break;
479af866496SDavid Daney 				}
480af866496SDavid Daney 			} else {
481af866496SDavid Daney 				/*
482af866496SDavid Daney 				 * Auto negotiation isn't
483af866496SDavid Daney 				 * complete. Return link down.
484af866496SDavid Daney 				 */
485af866496SDavid Daney 				result.s.speed = 0;
486af866496SDavid Daney 				result.s.link_up = 0;
487af866496SDavid Daney 			}
488af866496SDavid Daney 		} else {	/* MAC Mode */
489af866496SDavid Daney 
490af866496SDavid Daney 			result = __cvmx_helper_board_link_get(ipd_port);
491af866496SDavid Daney 		}
492af866496SDavid Daney 	}
493af866496SDavid Daney 	return result;
494af866496SDavid Daney }
495af866496SDavid Daney 
496af866496SDavid Daney /**
497af866496SDavid Daney  * Configure an IPD/PKO port for the specified link state. This
498af866496SDavid Daney  * function does not influence auto negotiation at the PHY level.
499af866496SDavid Daney  * The passed link state must always match the link state returned
5002b58a76eSAaro Koskinen  * by cvmx_helper_link_get().
501af866496SDavid Daney  *
502af866496SDavid Daney  * @ipd_port:  IPD/PKO port to configure
503af866496SDavid Daney  * @link_info: The new link state
504af866496SDavid Daney  *
505af866496SDavid Daney  * Returns Zero on success, negative on failure
506af866496SDavid Daney  */
__cvmx_helper_sgmii_link_set(int ipd_port,union cvmx_helper_link_info link_info)507af866496SDavid Daney int __cvmx_helper_sgmii_link_set(int ipd_port,
508f7d2bdcbSChris Packham 				 union cvmx_helper_link_info link_info)
509af866496SDavid Daney {
510af866496SDavid Daney 	int interface = cvmx_helper_get_interface_num(ipd_port);
511af866496SDavid Daney 	int index = cvmx_helper_get_interface_index_num(ipd_port);
512af866496SDavid Daney 	__cvmx_helper_sgmii_hardware_init_link(interface, index);
513af866496SDavid Daney 	return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index,
514af866496SDavid Daney 							    link_info);
515af866496SDavid Daney }
516