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