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